X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvcl%2Fvcom_socket.c;h=6450eddc8958a326187ffcf2ede2df0294ec7af3;hb=227867f5d3fb1b1dacbaf2f426812417b72ef03a;hp=ece9b69a44b57e69ae386eea295ccdbd124f7a16;hpb=e695cb4dbdb6f9424ac5a567799e67f791fad328;p=vpp.git diff --git a/src/vcl/vcom_socket.c b/src/vcl/vcom_socket.c index ece9b69a44b..6450eddc895 100644 --- a/src/vcl/vcom_socket.c +++ b/src/vcl/vcom_socket.c @@ -70,6 +70,7 @@ typedef struct vcom_socket_main_t_ /* Hash table - key:fd, value:vec of epitemidx */ uword *epitemidxs_by_fd; + u8 *io_buffer; } vcom_socket_main_t; vcom_socket_main_t vcom_socket_main; @@ -781,10 +782,24 @@ vcom_session_ioctl_va (int __sid, int __cmd, va_list __ap) { int rv; - if (__cmd == FIONREAD) - rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_NREAD, 0, 0); - else - rv = -EOPNOTSUPP; + switch (__cmd) + { + case FIONREAD: + rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_NREAD, 0, 0); + break; + + case FIONBIO: + { + u32 flags = va_arg (__ap, int) ? O_NONBLOCK : 0; + u32 len = sizeof (flags); + rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_FLAGS, &flags, &len); + } + break; + + default: + rv = -EOPNOTSUPP; + break; + } return rv; } @@ -1015,7 +1030,6 @@ vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds, struct timeval *__restrict timeout) { static unsigned long vcom_nsid_fds = 0; - vcom_socket_main_t *vsm = &vcom_socket_main; int vcom_nsid = 0; int rv = -EBADF; @@ -1086,14 +1100,14 @@ vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds, if (VCOM_DEBUG > 0) fprintf (stderr, "[%d] vcom_socket_select called to " - "emulate delay_ns()!\n", vsm->my_pid); + "emulate delay_ns()!\n", getpid ()); rv = vppcom_select (0, NULL, NULL, NULL, time_to_wait); } else { fprintf (stderr, "[%d] vcom_socket_select called vcom_nfds = 0 " "and invalid time_to_wait (%f)!\n", - vsm->my_pid, time_to_wait); + getpid (), time_to_wait); } return 0; } @@ -1128,7 +1142,7 @@ vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds, NULL, time_to_wait); if (VCOM_DEBUG > 2) fprintf (stderr, "[%d] called vppcom_select(): " - "'%04d'='%04d'\n", vsm->my_pid, rv, (int) vcom_nsid_fds); + "'%04d'='%04d'\n", getpid (), rv, (int) vcom_nsid_fds); /* check if any file descriptors changed status */ if (rv > 0) @@ -1400,6 +1414,47 @@ vcom_session_getpeername (int sid, vppcom_endpt_t * ep) return rv; } +static inline int +vcom_socket_copy_ep_to_sockaddr (__SOCKADDR_ARG __addr, + socklen_t * __restrict __len, + vppcom_endpt_t * ep) +{ + int rv = 0; + int sa_len, copy_len; + + __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; + if (*__len > sizeof (struct sockaddr_in)) + *__len = sizeof (struct sockaddr_in); + sa_len = sizeof (struct sockaddr_in) - sizeof (struct in_addr); + copy_len = *__len - sa_len; + if (copy_len > 0) + memcpy (&((struct sockaddr_in *) __addr)->sin_addr, ep->ip, copy_len); + break; + + case AF_INET6: + ((struct sockaddr_in6 *) __addr)->sin6_port = ep->port; + if (*__len > sizeof (struct sockaddr_in6)) + *__len = sizeof (struct sockaddr_in6); + sa_len = sizeof (struct sockaddr_in6) - sizeof (struct in6_addr); + copy_len = *__len - sa_len; + if (copy_len > 0) + memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr. + __in6_u.__u6_addr8, ep->ip, copy_len); + break; + + default: + /* Not possible */ + rv = -EAFNOSUPPORT; + break; + } + + return rv; +} + int vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __len) @@ -1408,7 +1463,8 @@ vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr, vcom_socket_main_t *vsm = &vcom_socket_main; uword *p; vcom_socket_t *vsock; - + u8 src_addr[sizeof (struct sockaddr_in6)]; + vppcom_endpt_t ep; p = hash_get (vsm->sockidx_by_fd, __fd); if (!p) @@ -1424,39 +1480,168 @@ vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr, if (!__addr || !__len) return -EFAULT; - vppcom_endpt_t ep; - ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr; + ep.ip = src_addr; rv = vcom_session_getpeername (vsock->sid, &ep); if (rv == 0) + rv = vcom_socket_copy_ep_to_sockaddr (__addr, __len, &ep); + + return rv; +} + +ssize_t +vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags) +{ + return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0); +} + +/* NOTE: this function is not thread safe or 32-bit friendly */ +ssize_t +vcom_socket_sendfile (int __out_fd, int __in_fd, off_t * __offset, + size_t __len) +{ + vcom_socket_main_t *vsm = &vcom_socket_main; + uword *p; + vcom_socket_t *vsock; + size_t n_bytes_left = __len; + u32 out_sockidx, out_sid = ~0; + size_t bytes_to_read; + int nbytes; + int rv, errno_val; + ssize_t results = 0; + u8 eagain = 0; + + if (VCOM_DEBUG > 2) + clib_warning ("[%d] __out_fd %d, __in_fd %d, __offset %p, __len %lu", + getpid (), __out_fd, __in_fd, __offset, __len); + + p = hash_get (vsm->sockidx_by_fd, __out_fd); + if (!p) { - if (ep.vrf == VPPCOM_VRF_DEFAULT) + clib_warning ("[%d] ERROR: invalid __out_fd (%d), fd lookup failed!", + getpid (), __len); + return -EBADF; + } + out_sockidx = p[0]; + vsock = pool_elt_at_index (vsm->vsockets, out_sockidx); + if (!vsock) + { + clib_warning ("[%d] ERROR: invalid __out_fd (%d) / out_sockidx %u, " + "missing vsock pool element!", + getpid (), __len, out_sockidx); + return -ENOTSOCK; + } + out_sid = vsock->sid; + if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND) + { + clib_warning ("[%d] ERROR: __out_fd (%d), socket (sid %u) " + "is not VCL bound!", getpid (), __out_fd, out_sid); + return -EINVAL; + } + + if (__offset) + { + off_t offset = lseek (__in_fd, *__offset, SEEK_SET); + if (offset == -1) { - __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; - *__len = sizeof (struct sockaddr_in); - break; + errno_val = errno; + perror ("lseek()"); + clib_warning ("[%d] ERROR: lseek SEEK_SET failed: " + "in_fd %d, offset %p (%ld), rv %ld, errno %d", + getpid (), __in_fd, __offset, *__offset, offset, + errno_val); + return -errno_val; + } - case AF_INET6: - ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port; - *__len = sizeof (struct sockaddr_in6); - break; + ASSERT (offset == *__offset); + } - default: - break; + do + { + bytes_to_read = vppcom_session_attr (out_sid, + VPPCOM_ATTR_GET_NWRITE, 0, 0); + if (VCOM_DEBUG > 2) + clib_warning ("[%d] results %ld, n_bytes_left %lu, " + "bytes_to_read %lu", getpid (), results, + n_bytes_left, bytes_to_read); + if (bytes_to_read == 0) + { + u32 flags, flags_len = sizeof (flags); + rv = vppcom_session_attr (out_sid, VPPCOM_ATTR_GET_FLAGS, &flags, + &flags_len); + ASSERT (rv == VPPCOM_OK); + + if (flags & O_NONBLOCK) + { + if (!results) + { + if (VCOM_DEBUG > 2) + clib_warning ("[%d] EAGAIN", getpid ()); + eagain = 1; + } + goto update_offset; } + else + continue; + } + bytes_to_read = clib_min (n_bytes_left, bytes_to_read); + vec_validate (vsm->io_buffer, bytes_to_read); + nbytes = libc_read (__in_fd, vsm->io_buffer, bytes_to_read); + if (nbytes < 0) + { + errno_val = errno; + perror ("read()"); + clib_warning ("[%d] ERROR: libc_read (__in_fd (%d), " + "io_buffer %p, bytes_to_read %lu) returned " + "errno %d", + getpid (), __in_fd, vsm->io_buffer, + bytes_to_read, errno_val); + if (results == 0) + { + vec_reset_length (vsm->io_buffer); + return -errno_val; + } + goto update_offset; } + rv = vppcom_session_write (out_sid, vsm->io_buffer, nbytes); + if (rv < 0) + { + clib_warning ("[%d] ERROR: vppcom_session_write (" + "out_sid %u, io_buffer %p, nbytes %d) returned %d", + getpid (), out_sid, vsm->io_buffer, nbytes, rv); + if (results == 0) + { + vec_reset_length (vsm->io_buffer); + return rv; + } + goto update_offset; + } + + results += nbytes; + ASSERT (n_bytes_left >= nbytes); + n_bytes_left = n_bytes_left - nbytes; } + while (n_bytes_left > 0); - return rv; -} +update_offset: + if (__offset) + { + off_t offset = lseek (__in_fd, *__offset, SEEK_SET); + if (offset == -1) + { + errno_val = errno; + perror ("lseek()"); + clib_warning ("[%d] ERROR: lseek (__in_fd %d, __offset %p " + "(%ld), SEEK_SET) returned errno %d", + getpid (), __in_fd, __offset, *__offset, errno_val); + vec_reset_length (vsm->io_buffer); + return -errno_val; + } -ssize_t -vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags) -{ - return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0); + *__offset += results + 1; + } + + vec_reset_length (vsm->io_buffer); + return eagain ? -EAGAIN : results; } ssize_t @@ -1620,37 +1805,7 @@ vcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n, 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; - memcpy (&((struct sockaddr_in *) __addr)->sin_addr, - src_addr, sizeof (struct in_addr)); - - *__addr_len = sizeof (struct sockaddr_in); - break; - - case AF_INET6: - ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port; - memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr. - __in6_u.__u6_addr8, src_addr, - sizeof (struct in6_addr)); - *__addr_len = sizeof (struct sockaddr_in6); - break; - - default: - rv = -EAFNOSUPPORT; - break; - } - } - else - rv = -1; - } + rv = vcom_socket_copy_ep_to_sockaddr (__addr, __addr_len, &ep); } else rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, NULL); @@ -2278,9 +2433,17 @@ vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr, /* flags can be 0 or can be bitwise OR * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */ + if (VCOM_DEBUG > 2) + fprintf (stderr, "[%d] vcom_socket_accept_flags: " + "fd = %d, __addr = %p, __addr_len = %p flags = %d (0x%x)\n", + getpid (), __fd, __addr, __addr_len, flags, flags); + if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC)))) { /* TBD: return proper error code */ + fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: " + "invalid flags = %d (0x%x)\n", getpid (), flags, flags); + return -1; } @@ -2288,6 +2451,8 @@ vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr, if (!vcom_socket_is_connection_mode_socket (__fd)) { + fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: " + "connection mode socket support TBD!\n", getpid ()); return -EOPNOTSUPP; } @@ -2300,6 +2465,8 @@ vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr, rv = vcom_fcntl (vsock->fd, F_GETFL, 0); if (rv < 0) { + fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: " + "vcom_fcnt() returned %d!\n", getpid (), rv); return rv; } @@ -2311,7 +2478,7 @@ vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr, * on the queue, accept () blocks the caller * until a connection is present. */ - rv = vppcom_session_accept (vsock->sid, &ep, + rv = vppcom_session_accept (vsock->sid, &ep, flags, -1.0 /* wait forever */ ); } else @@ -2321,7 +2488,7 @@ vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr, * block. * */ /* is non blocking */ - rv = vppcom_session_accept (vsock->sid, &ep, 0); + rv = vppcom_session_accept (vsock->sid, &ep, flags, 0); /* If the socket is marked nonblocking and * no pending connections are present on the * queue, accept fails with the error @@ -2334,6 +2501,9 @@ vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr, } if (rv < 0) { + if (rv != VPPCOM_EAGAIN) + fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: " + "vppcom_session_accept() returned %d!", getpid (), rv); return rv; } @@ -2347,6 +2517,9 @@ vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr, &domain, &type, &protocol, flags); if (fd < 0) { + fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: " + "vcom_socket_connected_socket() returned %d!", + getpid (), rv); return fd; } @@ -2426,18 +2599,6 @@ vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr, } } } - else - { - /* when __addr is NULL, nothing is filled in, - * in this case, __addr_len is not used, - * and should also be null - * */ - if (__addr_len) - { - /* TBD: return proper error code */ - return -1; - } - } } return rv; @@ -2451,7 +2612,6 @@ vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr, return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0); } -#ifdef __USE_GNU int vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len, int __flags) @@ -2459,7 +2619,6 @@ vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr, /* SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */ return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags); } -#endif /* TBD: move it to vppcom */ static inline int @@ -2757,7 +2916,6 @@ vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd, struct epoll_event *__event, int free_vepitem_on_del) { - vcom_socket_main_t *vsm = &vcom_socket_main; int rv = -1; i32 cnt; vcom_epoll_t *vepoll; @@ -2790,7 +2948,7 @@ vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd, "[%d] vcom_socket_epoll_ctl_i: vppcom_epoll_ctl() " "returned %d\n\tepfd %d, vep_idx %d, fd %d sid %d op %d" "\n\tcount %d, vcl_cnt %d, libc_cnt %d\n", - vsm->my_pid, rv, __epfd, vep_idx, __fd, sid, __op, + getpid (), rv, __epfd, vep_idx, __fd, sid, __op, vepoll->count, vepoll->vcl_cnt, vepoll->libc_cnt); } else @@ -2808,7 +2966,7 @@ vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd, "[%d] vcom_socket_epoll_ctl_i: libc_epoll_ctl() " "returned %d\n\tepfd %d, vep_idx %d, fd %d sid %d op %d" "\n\tcount %d, vcl_cnt %d, libc_cnt %d\n", - vsm->my_pid, rv, __epfd, vep_idx, __fd, sid, __op, + getpid (), rv, __epfd, vep_idx, __fd, sid, __op, vepoll->count, vepoll->vcl_cnt, vepoll->libc_cnt); } @@ -2844,7 +3002,7 @@ vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events, int rv = -EBADF; int rv2; double time_to_wait = (double) 0; - double timeout; + double timeout, now = 0; vcom_epoll_t *vepoll; i32 vep_idx; static struct epoll_event *libc_ev = 0; @@ -2853,20 +3011,19 @@ vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events, if (!__events || (__timeout < -1)) { fprintf (stderr, "[%d] ERROR: vcom_socket_epoll_pwait: " - "Bad args __events %p, __timeout %d\n", vsm->my_pid, + "Bad args __events %p, __timeout %d\n", getpid (), __events, __timeout); rv = -EFAULT; goto out; } - time_to_wait = ((__timeout > 0) ? - (double) __timeout / (double) 1000 : (double) __timeout); + time_to_wait = ((__timeout >= 0) ? (double) __timeout / (double) 1000 : 0); vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll); if (vep_idx == INVALID_VEP_IDX) { fprintf (stderr, "[%d] ERROR: vcom_socket_epoll_pwait: " - "Bad epoll fd %d\n", vsm->my_pid, __epfd); + "Bad epoll fd %d\n", getpid (), __epfd); return -EBADF; } @@ -2874,29 +3031,49 @@ vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events, { fprintf (stderr, "[%d] ERROR: vcom_socket_epoll_pwait: No events" " in epfd!\n\tcount %d, vcl_cnt %d, libc_cnt %d\n", - vsm->my_pid, vepoll->count, vepoll->vcl_cnt, vepoll->libc_cnt); + getpid (), vepoll->count, vepoll->vcl_cnt, vepoll->libc_cnt); rv = -EINVAL; goto out; } if (vepoll->libc_cnt == 0) { + if (VCOM_DEBUG > 2) + fprintf (stderr, "[%d] vcom_socket_epoll_pwait: libc_cnt = 0, " + "calling vppcom_epoll_wait() time_to_wait = %f\n", + getpid (), time_to_wait); rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, time_to_wait); } else if (vepoll->vcl_cnt == 0) { + if (VCOM_DEBUG > 2) + fprintf (stderr, "[%d] vcom_socket_epoll_pwait: vcl_cnt = 0, " + "calling libc_epoll_pwait()\n", getpid ()); rv = libc_epoll_pwait (__epfd, __events, __maxevents, __timeout, __ss); } else { + if (VCOM_DEBUG > 2) + fprintf (stderr, "[%d] vcom_socket_epoll_pwait: vcl_cnt = %d, " + "libc_cnt = %d -> mixed polling (time_to_wait = %f, " + "__timeout = %d)\n", + getpid (), vepoll->vcl_cnt, vepoll->libc_cnt, + time_to_wait, __timeout); vec_validate (libc_ev, __maxevents); timeout = clib_time_now (&vsm->clib_time) + time_to_wait; do { rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, 0); rv2 = libc_epoll_pwait (__epfd, libc_ev, __maxevents, 1, __ss); + if (VCOM_DEBUG == 666) + fprintf (stderr, "[%d] vcom_socket_epoll_pwait: " + "rv = %d, rv2 = %d, timeout = %f, now = %f\n", + getpid (), rv, rv2, timeout, now); if ((rv > 0) || (rv2 > 0)) { + if (VCOM_DEBUG > 2) + fprintf (stderr, "[%d] vcom_socket_epoll_pwait: " + "rv = %d, rv2 = %d\n", getpid (), rv, rv2); int n = __maxevents - rv; n = rv2 <= n ? rv2 : n; rv = (rv > 0) ? rv : 0; @@ -2910,19 +3087,20 @@ vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events, if (rv < 0) fprintf (stderr, "[%d] ERROR: vppcom_epoll_wait() returned %d\n", - vsm->my_pid, rv); + getpid (), rv); if (rv2 < 0) { fprintf (stderr, "[%d] ERROR: libc_epoll_wait() failed, errno %d\n", - vsm->my_pid, errno); + getpid (), errno); rv = (rv < 0) ? rv : -errno; } goto out; } + if (__timeout != -1) + now = clib_time_now (&vsm->clib_time); } - while ((__timeout == -1) - || (clib_time_now (&vsm->clib_time) < timeout)); + while (now < timeout); } out: @@ -3116,7 +3294,6 @@ vcom_socket_poll_select_impl (struct pollfd *__fds, nfds_t __nfds, int __timeout) { int rv; - vcom_socket_main_t *vsm = &vcom_socket_main; nfds_t fds_idx = 0; int nfd = 0; @@ -3205,7 +3382,7 @@ vcom_socket_poll_select_impl (struct pollfd *__fds, nfds_t __nfds, if (VCOM_DEBUG > 2) fprintf (stderr, "[%d] vcom_socket_select: " - "'%04d'='%04d'\n", vsm->my_pid, vcom_nfd, vcom_nfds); + "'%04d'='%04d'\n", getpid (), vcom_nfd, vcom_nfds); if (vcom_nfd < 0) { @@ -3339,7 +3516,6 @@ vcom_socket_main_init (void) vsm->epitemidxs_by_fd = hash_create (0, sizeof (i32 *)); clib_time_init (&vsm->clib_time); - vsm->my_pid = getpid (); vsm->init = 1; }