X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvcl%2Fvcom_socket.c;h=13e008cc6c0ed532ff8972a5c82ecf69c66ecc81;hb=9c5161aedff8e271cc036faeab58b665a3c8105e;hp=6fcc4e5820eeb6a76018c10deb3970b35b231dac;hpb=5917939256af392914d8a648de0c3287042ddbf6;p=vpp.git diff --git a/src/vcl/vcom_socket.c b/src/vcl/vcom_socket.c index 6fcc4e5820e..13e008cc6c0 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; @@ -1297,12 +1298,43 @@ vcom_socket_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len) } static inline int -vcom_session_getsockname (int sid, vppcom_endpt_t * ep) +vcom_socket_copy_ep_to_sockaddr (__SOCKADDR_ARG __addr, + socklen_t * __restrict __len, + vppcom_endpt_t * ep) { - int rv; - uint32_t size = sizeof (*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; + } - rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_LCL_ADDR, ep, &size); return rv; } @@ -1314,7 +1346,12 @@ vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr, vcom_socket_main_t *vsm = &vcom_socket_main; uword *p; vcom_socket_t *vsock; + vppcom_endpt_t ep; + u8 addr_buf[sizeof (struct in6_addr)]; + uint32_t size = sizeof (ep); + if (!__addr || !__len) + return -EFAULT; p = hash_get (vsm->sockidx_by_fd, __fd); if (!p) @@ -1327,34 +1364,10 @@ vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr, if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND) return -EINVAL; - if (!__addr || !__len) - return -EFAULT; - - vppcom_endpt_t ep; - ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr; - rv = vcom_session_getsockname (vsock->sid, &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; - *__len = sizeof (struct sockaddr_in); - break; - - case AF_INET6: - ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port; - *__len = sizeof (struct sockaddr_in6); - break; - - default: - break; - } - } - } + ep.ip = addr_buf; + rv = vppcom_session_attr (vsock->sid, VPPCOM_ATTR_GET_LCL_ADDR, &ep, &size); + if (rv == VPPCOM_OK) + rv = vcom_socket_copy_ep_to_sockaddr (__addr, __len, &ep); return rv; } @@ -1421,7 +1434,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) @@ -1437,39 +1451,179 @@ 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) + { + 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) { - if (ep.vrf == VPPCOM_VRF_DEFAULT) + 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 + { + rv = vppcom_session_attr (out_sid, VPPCOM_ATTR_GET_NWRITE, 0, 0); + if (rv < 0) + { + clib_warning ("[%d] ERROR: vppcom_session_attr (out_sid (%u), " + "VPPCOM_ATTR_GET_NWRITE, 0, 0) returned %d (%s)!", + getpid (), out_sid, rv, vppcom_retval_str (rv)); + vec_reset_length (vsm->io_buffer); + return rv; + } + + bytes_to_read = (size_t) rv; + 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 (%s)", + getpid (), out_sid, vsm->io_buffer, nbytes, + rv, vppcom_retval_str (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 @@ -1633,37 +1787,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); @@ -2336,7 +2460,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 @@ -2346,7 +2470,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 @@ -2858,12 +2982,10 @@ vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events, { vcom_socket_main_t *vsm = &vcom_socket_main; 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; /* validate __event */ if (!__events || (__timeout < -1)) @@ -2875,8 +2997,7 @@ vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events, 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) @@ -2899,7 +3020,8 @@ vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events, { if (VCOM_DEBUG > 2) fprintf (stderr, "[%d] vcom_socket_epoll_pwait: libc_cnt = 0, " - "calling vppcom_epoll_wait()\n", getpid ()); + "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) @@ -2913,49 +3035,52 @@ vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events, { if (VCOM_DEBUG > 2) fprintf (stderr, "[%d] vcom_socket_epoll_pwait: vcl_cnt = %d, " - "libc_cnt = %d -> mixed polling\n", getpid (), - vepoll->vcl_cnt, vepoll->libc_cnt); - vec_validate (libc_ev, __maxevents); + "libc_cnt = %d -> mixed polling (time_to_wait = %f, " + "__timeout = %d)\n", + getpid (), vepoll->vcl_cnt, vepoll->libc_cnt, + time_to_wait, __timeout); 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 ((rv > 0) || (rv2 > 0)) + if (rv > 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; + "vppcom_epoll_wait() returned %d\n", getpid (), rv); + goto out; + } + else if (rv < 0) + { + if (VCOM_DEBUG > 2) + fprintf (stderr, "[%d] ERROR: vcom_socket_epoll_pwait: " + "vppcom_epoll_wait() returned %d\n", getpid (), rv); - clib_memcpy (&__events[rv], libc_ev, n * sizeof (*libc_ev)); - rv += rv2; goto out; } - else if ((rv < 0) || (rv2 < 0)) + rv = libc_epoll_pwait (__epfd, __events, __maxevents, 1, __ss); + if (rv > 0) { - if (rv < 0) - fprintf (stderr, - "[%d] ERROR: vppcom_epoll_wait() returned %d\n", - getpid (), rv); - if (rv2 < 0) - { - fprintf (stderr, - "[%d] ERROR: libc_epoll_wait() failed, errno %d\n", - getpid (), errno); - rv = (rv < 0) ? rv : -errno; - } + if (VCOM_DEBUG > 2) + fprintf (stderr, "[%d] vcom_socket_epoll_pwait: " + "libc_epoll_pwait() returned %d\n", getpid (), rv); goto out; } + else if (rv < 0) + { + int errno_val = errno; + perror ("libc_epoll_wait"); + fprintf (stderr, "[%d] vcom_socket_epoll_pwait: " + "libc_epoll_wait() failed, errno %d\n", + getpid (), errno_val); + 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: - vec_reset_length (libc_ev); return rv; }