/* 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;
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)
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)
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
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);
* 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
* 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