vcl: add sendmsg/recvmsg for vlsh in ldp

Type: improvement

Signed-off-by: Florin Coras <fcoras@cisco.com>
Change-Id: If61eec3f5723e6b36e6f4a21c05d8d0dd3547fc7
diff --git a/src/vcl/ldp.c b/src/vcl/ldp.c
index e3e6dfa..19f3827 100644
--- a/src/vcl/ldp.c
+++ b/src/vcl/ldp.c
@@ -1525,6 +1525,69 @@
   return size;
 }
 
+static int
+ldp_vls_sendo (vls_handle_t vlsh, const void *buf, size_t n, int flags,
+	       __CONST_SOCKADDR_ARG addr, socklen_t addr_len)
+{
+  vppcom_endpt_t *ep = 0;
+  vppcom_endpt_t _ep;
+
+  if (addr)
+    {
+      ep = &_ep;
+      switch (addr->sa_family)
+	{
+	case AF_INET:
+	  ep->is_ip4 = VPPCOM_IS_IP4;
+	  ep->ip =
+	    (uint8_t *) & ((const struct sockaddr_in *) addr)->sin_addr;
+	  ep->port = (uint16_t) ((const struct sockaddr_in *) addr)->sin_port;
+	  break;
+
+	case AF_INET6:
+	  ep->is_ip4 = VPPCOM_IS_IP6;
+	  ep->ip =
+	    (uint8_t *) & ((const struct sockaddr_in6 *) addr)->sin6_addr;
+	  ep->port =
+	    (uint16_t) ((const struct sockaddr_in6 *) addr)->sin6_port;
+	  break;
+
+	default:
+	  return EAFNOSUPPORT;
+	}
+    }
+
+  return vls_sendto (vlsh, (void *) buf, n, flags, ep);
+}
+
+static int
+ldp_vls_recvfrom (vls_handle_t vlsh, void *__restrict buf, size_t n,
+		  int flags, __SOCKADDR_ARG addr,
+		  socklen_t * __restrict addr_len)
+{
+  u8 src_addr[sizeof (struct sockaddr_in6)];
+  vppcom_endpt_t ep;
+  ssize_t size;
+  int rv;
+
+  if (addr)
+    {
+      ep.ip = src_addr;
+      size = vls_recvfrom (vlsh, buf, n, flags, &ep);
+
+      if (size > 0)
+	{
+	  rv = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep);
+	  if (rv < 0)
+	    size = rv;
+	}
+    }
+  else
+    size = vls_recvfrom (vlsh, buf, n, flags, NULL);
+
+  return size;
+}
+
 ssize_t
 sendto (int fd, const void *buf, size_t n, int flags,
 	__CONST_SOCKADDR_ARG addr, socklen_t addr_len)
@@ -1538,38 +1601,7 @@
   vlsh = ldp_fd_to_vlsh (fd);
   if (vlsh != INVALID_SESSION_ID)
     {
-      vppcom_endpt_t *ep = 0;
-      vppcom_endpt_t _ep;
-
-      if (addr)
-	{
-	  ep = &_ep;
-	  switch (addr->sa_family)
-	    {
-	    case AF_INET:
-	      ep->is_ip4 = VPPCOM_IS_IP4;
-	      ep->ip =
-		(uint8_t *) & ((const struct sockaddr_in *) addr)->sin_addr;
-	      ep->port =
-		(uint16_t) ((const struct sockaddr_in *) addr)->sin_port;
-	      break;
-
-	    case AF_INET6:
-	      ep->is_ip4 = VPPCOM_IS_IP6;
-	      ep->ip =
-		(uint8_t *) & ((const struct sockaddr_in6 *) addr)->sin6_addr;
-	      ep->port =
-		(uint16_t) ((const struct sockaddr_in6 *) addr)->sin6_port;
-	      break;
-
-	    default:
-	      errno = EAFNOSUPPORT;
-	      size = -1;
-	      goto done;
-	    }
-	}
-
-      size = vls_sendto (vlsh, (void *) buf, n, flags, ep);
+      size = ldp_vls_sendo (vlsh, buf, n, flags, addr, addr_len);
       if (size < 0)
 	{
 	  errno = -size;
@@ -1581,7 +1613,6 @@
       size = libc_sendto (fd, buf, n, flags, addr, addr_len);
     }
 
-done:
   return size;
 }
 
@@ -1589,33 +1620,16 @@
 recvfrom (int fd, void *__restrict buf, size_t n, int flags,
 	  __SOCKADDR_ARG addr, socklen_t * __restrict addr_len)
 {
-  vls_handle_t sid;
-  ssize_t size, rv;
+  vls_handle_t vlsh;
+  ssize_t size;
 
   if ((errno = -ldp_init ()))
     return -1;
 
-  sid = ldp_fd_to_vlsh (fd);
-  if (sid != VLS_INVALID_HANDLE)
+  vlsh = ldp_fd_to_vlsh (fd);
+  if (vlsh != VLS_INVALID_HANDLE)
     {
-      vppcom_endpt_t ep;
-      u8 src_addr[sizeof (struct sockaddr_in6)];
-
-      if (addr)
-	{
-	  ep.ip = src_addr;
-	  size = vls_recvfrom (sid, buf, n, flags, &ep);
-
-	  if (size > 0)
-	    {
-	      rv = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep);
-	      if (rv < 0)
-		size = rv;
-	    }
-	}
-      else
-	size = vls_recvfrom (sid, buf, n, flags, NULL);
-
+      size = ldp_vls_recvfrom (vlsh, buf, n, flags, addr, addr_len);
       if (size < 0)
 	{
 	  errno = -size;
@@ -1631,7 +1645,7 @@
 }
 
 ssize_t
-sendmsg (int fd, const struct msghdr * message, int flags)
+sendmsg (int fd, const struct msghdr * msg, int flags)
 {
   vls_handle_t vlsh;
   ssize_t size;
@@ -1642,13 +1656,35 @@
   vlsh = ldp_fd_to_vlsh (fd);
   if (vlsh != VLS_INVALID_HANDLE)
     {
-      LDBG (0, "LDP-TBD");
-      errno = ENOSYS;
-      size = -1;
+      struct iovec *iov = msg->msg_iov;
+      ssize_t total = 0;
+      int i, rv;
+
+      for (i = 0; i < msg->msg_iovlen; ++i)
+	{
+	  rv = ldp_vls_sendo (vlsh, iov[i].iov_base, iov[i].iov_len, flags,
+			      msg->msg_name, msg->msg_namelen);
+	  if (rv < 0)
+	    break;
+	  else
+	    {
+	      total += rv;
+	      if (rv < iov[i].iov_len)
+		break;
+	    }
+	}
+
+      if (rv < 0 && total == 0)
+	{
+	  errno = -rv;
+	  size = -1;
+	}
+      else
+	size = total;
     }
   else
     {
-      size = libc_sendmsg (fd, message, flags);
+      size = libc_sendmsg (fd, msg, flags);
     }
 
   return size;
@@ -1703,7 +1739,7 @@
 #endif
 
 ssize_t
-recvmsg (int fd, struct msghdr * message, int flags)
+recvmsg (int fd, struct msghdr * msg, int flags)
 {
   vls_handle_t vlsh;
   ssize_t size;
@@ -1714,13 +1750,42 @@
   vlsh = ldp_fd_to_vlsh (fd);
   if (vlsh != VLS_INVALID_HANDLE)
     {
-      LDBG (0, "LDP-TBD");
-      errno = ENOSYS;
-      size = -1;
+      struct iovec *iov = msg->msg_iov;
+      ssize_t max_deq, total = 0;
+      int i, rv;
+
+      max_deq = vls_attr (vlsh, VPPCOM_ATTR_GET_NREAD, 0, 0);
+      if (!max_deq)
+	return 0;
+
+      for (i = 0; i < msg->msg_iovlen; i++)
+	{
+	  rv = ldp_vls_recvfrom (vlsh, iov[i].iov_base, iov[i].iov_len, flags,
+				 (i == 0 ? msg->msg_name : NULL),
+				 (i == 0 ? &msg->msg_namelen : NULL));
+	  if (rv <= 0)
+	    break;
+	  else
+	    {
+	      total += rv;
+	      if (rv < iov[i].iov_len)
+		break;
+	    }
+	  if (total >= max_deq)
+	    break;
+	}
+
+      if (rv < 0 && total == 0)
+	{
+	  errno = -rv;
+	  size = -1;
+	}
+      else
+	size = total;
     }
   else
     {
-      size = libc_recvmsg (fd, message, flags);
+      size = libc_recvmsg (fd, msg, flags);
     }
 
   return size;