VCL/LDPRELOAD: Add support for getsockopt, sendto, and recvfrom 04/9004/3
authorSteven <sluong@cisco.com>
Tue, 24 Oct 2017 23:03:58 +0000 (16:03 -0700)
committerDave Wallace <dwallacelf@gmail.com>
Wed, 25 Oct 2017 14:08:39 +0000 (14:08 +0000)
Add support for getsockopt, sendto, and recvfrom. Not all options
for the system calls are supported yet. Only the options used by
curl and wget are supported for now.

Change-Id: I2e0ed7349a0273616b3831c201e7c117725ca287
Signed-off-by: Steven <sluong@cisco.com>
src/vcl/vcom_socket.c
src/vcl/vppcom.c
src/vcl/vppcom.h

index 1ccb054..304cebb 100644 (file)
@@ -1513,9 +1513,29 @@ vcom_session_sendto (int __sid, void *__buf, size_t __n,
                     socklen_t __addr_len)
 {
   int rv = -1;
-  /* TBD add new vpp api  */
-  /* TBD add flags parameter */
-  rv = vppcom_session_write (__sid, (void *) __buf, (int) __n);
+  vppcom_endpt_t ep;
+
+  ep.vrf = VPPCOM_VRF_DEFAULT;
+  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 -1;
+    }
+
+  rv = vppcom_session_sendto (__sid, __buf, __n, __flags, &ep);
+
   return rv;
 }
 
@@ -1580,10 +1600,44 @@ vcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
                       int __flags, __SOCKADDR_ARG __addr,
                       socklen_t * __restrict __addr_len)
 {
-  int rv = -1;
+  int rv;
+  vppcom_endpt_t ep;
+
+  if (__addr)
+    {
+      ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
+      rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, &ep);
+
+      if (rv > 0)
+       {
+         if (ep.vrf == VPPCOM_VRF_DEFAULT)
+           {
+             __addr->sa_family =
+               ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
+             switch (__addr->sa_family)
+               {
+               case AF_INET:
+                 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
+                 *__addr_len = sizeof (struct sockaddr_in);
+                 break;
+
+               case AF_INET6:
+                 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
+                 *__addr_len = sizeof (struct sockaddr_in6);
+                 break;
+
+               default:
+                 rv = -1;
+                 break;
+               }
+           }
+         else
+           rv = -1;
+       }
+    }
+  else
+    rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, NULL);
 
-  /* TBD add flags parameter */
-  rv = vppcom_session_read (__sid, __buf, __n);
   return rv;
 }
 
@@ -1597,10 +1651,8 @@ vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
   uword *p;
   vcom_socket_t *vsock;
 
-  if (!__buf || !__addr || !__addr_len)
-    {
-      return -EINVAL;
-    }
+  if (__addr && !__addr_len)
+    return -EINVAL;
 
   p = hash_get (vsm->sockidx_by_fd, __fd);
   if (!p)
@@ -1737,9 +1789,26 @@ vcom_session_get_sockopt (int __sid, int __level, int __optname,
                          void *__restrict __optval,
                          socklen_t * __restrict __optlen)
 {
+  int rv = 0;
+
   /* 1. for socket level options that are NOT socket attributes
    *    and that has corresponding vpp options get from vppcom */
-  return 0;
+  switch (__level)
+    {
+    case SOL_SOCKET:
+      switch (__optname)
+       {
+       case SO_ERROR:
+         *(int *) __optval = 0;
+         break;
+       default:
+         break;
+       }
+    default:
+      break;
+    }
+  /* 2. unhandled options */
+  return rv;
 }
 
 int
@@ -1768,7 +1837,6 @@ vcom_socket_getsockopt (int __fd, int __level, int __optname,
 
   switch (__level)
     {
-      /* handle options at socket level */
     case SOL_SOCKET:
       switch (__optname)
        {
@@ -1791,7 +1859,6 @@ vcom_socket_getsockopt (int __fd, int __level, int __optname,
        case SO_TYPE:
        case SO_PROTOCOL:
        case SO_DOMAIN:
-       case SO_ERROR:
        case SO_OOBINLINE:
        case SO_NO_CHECK:
        case SO_PRIORITY:
@@ -1835,6 +1902,11 @@ vcom_socket_getsockopt (int __fd, int __level, int __optname,
            }
          break;
 
+       case SO_ERROR:
+         rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
+                                        __optval, __optlen);
+         break;
+
        default:
          /* We implement the SO_SNDLOWAT etc to not be settable
           * (1003.1g 7).
index 0f30c60..1b1a08e 100644 (file)
@@ -109,7 +109,8 @@ typedef struct
   u32 vrf;
   vppcom_ip46_t lcl_addr;
   vppcom_ip46_t peer_addr;
-  u16 port;
+  u16 lcl_port;                        // network order
+  u16 peer_port;               // network order
   u8 proto;
   u64 client_queue_address;
   u64 options[16];
@@ -806,7 +807,7 @@ vppcom_send_connect_sock (session_t * session, u32 session_index)
   cmp->vrf = session->vrf;
   cmp->is_ip4 = session->peer_addr.is_ip4;
   clib_memcpy (cmp->ip, &session->peer_addr.ip46, sizeof (cmp->ip));
-  cmp->port = session->port;
+  cmp->port = session->peer_port;
   cmp->proto = session->proto;
   clib_memcpy (cmp->options, session->options, sizeof (cmp->options));
   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & cmp);
@@ -1014,7 +1015,7 @@ vl_api_accept_session_t_handler (vl_api_accept_session_t * mp)
   session->state = STATE_ACCEPT;
   session->is_cut_thru = 0;
   session->is_server = 1;
-  session->port = mp->port;
+  session->peer_port = mp->port;
   session->peer_addr.is_ip4 = mp->is_ip4;
   clib_memcpy (&session->peer_addr.ip46, mp->ip,
               sizeof (session->peer_addr.ip46));
@@ -1132,7 +1133,7 @@ vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp)
   session->client_queue_address = mp->client_queue_address;
   session->is_cut_thru = 1;
   session->is_server = 1;
-  session->port = mp->port;
+  session->peer_port = mp->port;
   session->peer_addr.is_ip4 = mp->is_ip4;
   clib_memcpy (&session->peer_addr.ip46, mp->ip,
               sizeof (session->peer_addr.ip46));
@@ -1198,7 +1199,7 @@ vppcom_send_bind_sock (session_t * session)
   bmp->vrf = session->vrf;
   bmp->is_ip4 = session->lcl_addr.is_ip4;
   clib_memcpy (bmp->ip, &session->lcl_addr.ip46, sizeof (bmp->ip));
-  bmp->port = session->port;
+  bmp->port = session->lcl_port;
   bmp->proto = session->proto;
   clib_memcpy (bmp->options, session->options, sizeof (bmp->options));
   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
@@ -1986,13 +1987,16 @@ vppcom_session_bind (uint32_t session_index, vppcom_endpt_t * ep)
       return VPPCOM_EBADFD;
     }
 
-  if (VPPCOM_DEBUG > 0)
-    clib_warning ("[%d] sid %d", vcm->my_pid, session_index);
-
   session->vrf = ep->vrf;
   session->lcl_addr.is_ip4 = ep->is_ip4;
   session->lcl_addr.ip46 = to_ip46 (!ep->is_ip4, ep->ip);
-  session->port = ep->port;
+  session->lcl_port = ep->port;
+
+  if (VPPCOM_DEBUG > 0)
+    clib_warning ("[%d] sid %d, bound to lcl address %U lcl port %u",
+                 vcm->my_pid, session_index, format_ip46_address,
+                 &session->lcl_addr.ip46, session->lcl_addr.is_ip4,
+                 clib_net_to_host_u16 (session->lcl_port));
 
   clib_spinlock_unlock (&vcm->sessions_lockp);
   return VPPCOM_OK;
@@ -2138,16 +2142,26 @@ vppcom_session_accept (uint32_t listen_session_index, vppcom_endpt_t * ep,
     clib_warning ("[%d] Got a request: client sid %d", vcm->my_pid,
                  client_session_index);
 
+  // Copy the lcl information from the listening session to the client session
+  //  client_session->lcl_port = listen_session->lcl_port;
+  //  client_session->lcl_addr = listen_session->lcl_addr;
+
   ep->vrf = client_session->vrf;
   ep->is_cut_thru = client_session->is_cut_thru;
   ep->is_ip4 = client_session->peer_addr.is_ip4;
-  ep->port = client_session->port;
+  ep->port = client_session->peer_port;
   if (client_session->peer_addr.is_ip4)
     clib_memcpy (ep->ip, &client_session->peer_addr.ip46.ip4,
                 sizeof (ip4_address_t));
   else
     clib_memcpy (ep->ip, &client_session->peer_addr.ip46.ip6,
                 sizeof (ip6_address_t));
+  if (VPPCOM_DEBUG > 0)
+    clib_warning ("[%d] sid %d, accepted peer address %U peer port %u",
+                 vcm->my_pid, client_session_index, format_ip46_address,
+                 &client_session->peer_addr.ip46,
+                 client_session->peer_addr.is_ip4,
+                 clib_net_to_host_u16 (client_session->peer_port));
   clib_spinlock_unlock (&vcm->sessions_lockp);
   return (int) client_session_index;
 }
@@ -2191,7 +2205,7 @@ vppcom_session_connect (uint32_t session_index, vppcom_endpt_t * server_ep)
   session->vrf = server_ep->vrf;
   session->peer_addr.is_ip4 = server_ep->is_ip4;
   session->peer_addr.ip46 = to_ip46 (!server_ep->is_ip4, server_ep->ip);
-  session->port = server_ep->port;
+  session->peer_port = server_ep->port;
 
   if (VPPCOM_DEBUG > 0)
     {
@@ -2200,7 +2214,7 @@ vppcom_session_connect (uint32_t session_index, vppcom_endpt_t * server_ep)
                           session->peer_addr.is_ip4);
       clib_warning ("[%d] connect sid %d to %s server port %d proto %s",
                    vcm->my_pid, session_index, ip_str,
-                   clib_net_to_host_u16 (session->port),
+                   clib_net_to_host_u16 (session->peer_port),
                    session->proto ? "UDP" : "TCP");
       vec_free (ip_str);
     }
@@ -3181,7 +3195,7 @@ vppcom_session_attr (uint32_t session_index, uint32_t op,
        {
          ep->vrf = session->vrf;
          ep->is_ip4 = session->peer_addr.is_ip4;
-         ep->port = session->port;
+         ep->port = session->peer_port;
          if (session->peer_addr.is_ip4)
            clib_memcpy (ep->ip, &session->peer_addr.ip46.ip4,
                         sizeof (ip4_address_t));
@@ -3190,9 +3204,11 @@ vppcom_session_attr (uint32_t session_index, uint32_t op,
                         sizeof (ip6_address_t));
          *buflen = sizeof (*ep);
          if (VPPCOM_DEBUG > 0)
-           clib_warning ("VPPCOM_ATTR_GET_PEER_ADDR: is_ip4 = %u, "
-                         "addr = %U", ep->is_ip4, format_ip46_address,
-                         &session->peer_addr.ip46, ep->is_ip4);
+           clib_warning ("VPPCOM_ATTR_GET_PEER_ADDR: sid %u is_ip4 = %u, "
+                         "addr = %U, port %u", session_index,
+                         ep->is_ip4, format_ip46_address,
+                         &session->peer_addr.ip46, ep->is_ip4,
+                         clib_net_to_host_u16 (ep->port));
        }
       else
        rv = VPPCOM_EINVAL;
@@ -3203,7 +3219,7 @@ vppcom_session_attr (uint32_t session_index, uint32_t op,
        {
          ep->vrf = session->vrf;
          ep->is_ip4 = session->lcl_addr.is_ip4;
-         ep->port = session->port;
+         ep->port = session->lcl_port;
          if (session->lcl_addr.is_ip4)
            clib_memcpy (ep->ip, &session->lcl_addr.ip46.ip4,
                         sizeof (ip4_address_t));
@@ -3212,10 +3228,11 @@ vppcom_session_attr (uint32_t session_index, uint32_t op,
                         sizeof (ip6_address_t));
          *buflen = sizeof (*ep);
          if (VPPCOM_DEBUG > 0)
-           if (VPPCOM_DEBUG > 0)
-             clib_warning ("VPPCOM_ATTR_GET_LCL_ADDR: is_ip4 = %u, "
-                           "addr = %U", ep->is_ip4, format_ip46_address,
-                           &session->lcl_addr.ip46, ep->is_ip4);
+           clib_warning ("VPPCOM_ATTR_GET_LCL_ADDR: sid %u is_ip4 = %u, "
+                         "addr = %U port %d", session_index,
+                         ep->is_ip4, format_ip46_address,
+                         &session->lcl_addr.ip46, ep->is_ip4,
+                         clib_net_to_host_u16 (ep->port));
        }
       else
        rv = VPPCOM_EINVAL;
@@ -3249,6 +3266,71 @@ done:
   return rv;
 }
 
+int
+vppcom_session_recvfrom (uint32_t session_index, void *buffer,
+                        uint32_t buflen, int flags, vppcom_endpt_t * ep)
+{
+  vppcom_main_t *vcm = &vppcom_main;
+  int rv = VPPCOM_OK;
+  session_t *session = 0;
+
+  if (ep)
+    {
+      clib_spinlock_lock (&vcm->sessions_lockp);
+      rv = vppcom_session_at_index (session_index, &session);
+      if (PREDICT_FALSE (rv))
+       {
+         clib_spinlock_unlock (&vcm->sessions_lockp);
+         if (VPPCOM_DEBUG > 0)
+           clib_warning ("[%d] invalid session, sid (%u) has been closed!",
+                         vcm->my_pid, session_index);
+         rv = VPPCOM_EINVAL;
+       }
+      ep->vrf = session->vrf;
+      ep->is_ip4 = session->peer_addr.is_ip4;
+      ep->port = session->peer_port;
+      if (session->peer_addr.is_ip4)
+       clib_memcpy (ep->ip, &session->peer_addr.ip46.ip4,
+                    sizeof (ip4_address_t));
+      else
+       clib_memcpy (ep->ip, &session->peer_addr.ip46.ip6,
+                    sizeof (ip6_address_t));
+      clib_spinlock_unlock (&vcm->sessions_lockp);
+      rv = vppcom_session_read (session_index, buffer, buflen);
+    }
+  else if (flags == 0)
+    rv = vppcom_session_read (session_index, buffer, buflen);
+  else if (flags & MSG_PEEK)
+    {
+      rv = vppcom_session_attr (session_index, VPPCOM_ATTR_GET_NREAD, 0, 0);
+      if (rv > buflen)
+       rv = buflen;
+    }
+  else
+    {
+      clib_warning ("Unsupport flags for recvfro %d", flags);
+      rv = VPPCOM_EAFNOSUPPORT;
+    }
+
+  return rv;
+}
+
+int
+vppcom_session_sendto (uint32_t session_index, void *buffer,
+                      uint32_t buflen, int flags, vppcom_endpt_t * ep)
+{
+  if (ep)
+    // TBD
+    return -1;
+  else if (flags == 0)
+    return (vppcom_session_write (session_index, buffer, buflen));
+  else if (flags)
+    // TBD check the flags and do the right thing
+    return (vppcom_session_write (session_index, buffer, buflen));
+
+  return -1;
+}
+
 /*
  * fd.io coding-style-patch-verification: ON
  *
index dd72986..d9ed22f 100644 (file)
@@ -159,6 +159,12 @@ extern int vppcom_epoll_wait (uint32_t vep_idx, struct epoll_event *events,
                              int maxevents, double wait_for_time);
 extern int vppcom_session_attr (uint32_t session_index, uint32_t op,
                                void *buffer, uint32_t * buflen);
+extern int vppcom_session_recvfrom (uint32_t session_index, void *buffer,
+                                   uint32_t buflen, int flags,
+                                   vppcom_endpt_t * ep);
+extern int vppcom_session_sendto (uint32_t session_index, void *buffer,
+                                 uint32_t buflen, int flags,
+                                 vppcom_endpt_t * ep);
 
 #endif /* included_vppcom_h */