From ac1f96d7cdfb845c08400d27ec566b991e32e24b Mon Sep 17 00:00:00 2001 From: Steven Date: Tue, 24 Oct 2017 16:03:58 -0700 Subject: [PATCH] VCL/LDPRELOAD: Add support for getsockopt, sendto, and recvfrom 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 --- src/vcl/vcom_socket.c | 98 +++++++++++++++++++++++++++++++++------ src/vcl/vppcom.c | 124 +++++++++++++++++++++++++++++++++++++++++--------- src/vcl/vppcom.h | 6 +++ 3 files changed, 194 insertions(+), 34 deletions(-) diff --git a/src/vcl/vcom_socket.c b/src/vcl/vcom_socket.c index 1ccb05451ad..304cebb8f9b 100644 --- a/src/vcl/vcom_socket.c +++ b/src/vcl/vcom_socket.c @@ -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). diff --git a/src/vcl/vppcom.c b/src/vcl/vppcom.c index 0f30c60c803..1b1a08e4c06 100644 --- a/src/vcl/vppcom.c +++ b/src/vcl/vppcom.c @@ -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 * diff --git a/src/vcl/vppcom.h b/src/vcl/vppcom.h index dd72986ec53..d9ed22fe755 100644 --- a/src/vcl/vppcom.h +++ b/src/vcl/vppcom.h @@ -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 */ -- 2.16.6