struct sockaddr *src_addr,
socklen_t *addrlen);
typedef int (*__libc_recvmsg)(int sockfd, const struct msghdr *msg, int flags);
+#ifdef HAVE_RECVMMSG
+#if defined(HAVE_RECVMMSG_SSIZE_T_CONST_TIMEOUT)
+/* FreeBSD */
+typedef ssize_t (*__libc_recvmmsg)(int sockfd, struct mmsghdr *msgvec, size_t vlen, int flags, const struct timespec *timeout);
+#elif defined(HAVE_RECVMMSG_CONST_TIMEOUT)
+/* Linux legacy glibc < 2.21 */
+typedef int (*__libc_recvmmsg)(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, const struct timespec *timeout);
+#else
+/* Linux glibc >= 2.21 */
+typedef int (*__libc_recvmmsg)(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout);
+#endif
+#endif /* HAVE_RECVMMSG */
typedef int (*__libc_send)(int sockfd, const void *buf, size_t len, int flags);
typedef int (*__libc_sendmsg)(int sockfd, const struct msghdr *msg, int flags);
+#ifdef HAVE_SENDMMSG
+#if defined(HAVE_SENDMMSG_SSIZE_T)
+/* FreeBSD */
+typedef ssize_t (*__libc_sendmmsg)(int sockfd, struct mmsghdr *msgvec, size_t vlen, int flags);
+#else
+/* Linux */
+typedef int (*__libc_sendmmsg)(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags);
+#endif
+#endif /* HAVE_SENDMMSG */
typedef int (*__libc_sendto)(int sockfd,
const void *buf,
size_t len,
SWRAP_SYMBOL_ENTRY(recv);
SWRAP_SYMBOL_ENTRY(recvfrom);
SWRAP_SYMBOL_ENTRY(recvmsg);
+#ifdef HAVE_RECVMMSG
+ SWRAP_SYMBOL_ENTRY(recvmmsg);
+#endif
SWRAP_SYMBOL_ENTRY(send);
SWRAP_SYMBOL_ENTRY(sendmsg);
+#ifdef HAVE_SENDMMSG
+ SWRAP_SYMBOL_ENTRY(sendmmsg);
+#endif
SWRAP_SYMBOL_ENTRY(sendto);
SWRAP_SYMBOL_ENTRY(setsockopt);
#ifdef HAVE_SIGNALFD
return swrap.libc.symbols._libc_recvmsg.f(sockfd, msg, flags);
}
+#ifdef HAVE_RECVMMSG
+#if defined(HAVE_RECVMMSG_SSIZE_T_CONST_TIMEOUT)
+/* FreeBSD */
+static ssize_t libc_recvmmsg(int sockfd, struct mmsghdr *msgvec, size_t vlen, int flags, const struct timespec *timeout)
+#elif defined(HAVE_RECVMMSG_CONST_TIMEOUT)
+/* Linux legacy glibc < 2.21 */
+static int libc_recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, const struct timespec *timeout)
+#else
+/* Linux glibc >= 2.21 */
+static int libc_recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout)
+#endif
+{
+ swrap_bind_symbol_all();
+
+ return swrap.libc.symbols._libc_recvmmsg.f(sockfd, msgvec, vlen, flags, timeout);
+}
+#endif
+
static int libc_send(int sockfd, const void *buf, size_t len, int flags)
{
swrap_bind_symbol_all();
return swrap.libc.symbols._libc_sendmsg.f(sockfd, msg, flags);
}
+#ifdef HAVE_SENDMMSG
+#if defined(HAVE_SENDMMSG_SSIZE_T)
+/* FreeBSD */
+static ssize_t libc_sendmmsg(int sockfd, struct mmsghdr *msgvec, size_t vlen, int flags)
+#else
+/* Linux */
+static int libc_sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags)
+#endif
+{
+ swrap_bind_symbol_all();
+
+ return swrap.libc.symbols._libc_sendmmsg.f(sockfd, msgvec, vlen, flags);
+}
+#endif
+
static int libc_sendto(int sockfd,
const void *buf,
size_t len,
swrap_bind_symbol_libsocket(recv);
swrap_bind_symbol_libsocket(recvfrom);
swrap_bind_symbol_libsocket(recvmsg);
+#ifdef HAVE_RECVMMSG
+ swrap_bind_symbol_libsocket(recvmmsg);
+#endif
swrap_bind_symbol_libsocket(send);
swrap_bind_symbol_libsocket(sendmsg);
+#ifdef HAVE_SENDMMSG
+ swrap_bind_symbol_libsocket(sendmmsg);
+#endif
swrap_bind_symbol_libsocket(sendto);
swrap_bind_symbol_libsocket(setsockopt);
#ifdef HAVE_SIGNALFD
return swrap_recvmsg(sockfd, msg, flags);
}
+/****************************************************************************
+ * RECVMMSG
+ ***************************************************************************/
+
+#ifdef HAVE_RECVMMSG
+#if defined(HAVE_RECVMMSG_SSIZE_T_CONST_TIMEOUT)
+/* FreeBSD */
+static ssize_t swrap_recvmmsg(int s, struct mmsghdr *omsgvec, size_t _vlen, int flags, const struct timespec *timeout)
+#elif defined(HAVE_RECVMMSG_CONST_TIMEOUT)
+/* Linux legacy glibc < 2.21 */
+static int swrap_recvmmsg(int s, struct mmsghdr *omsgvec, unsigned int _vlen, int flags, const struct timespec *timeout)
+#else
+/* Linux glibc >= 2.21 */
+static int swrap_recvmmsg(int s, struct mmsghdr *omsgvec, unsigned int _vlen, int flags, struct timespec *timeout)
+#endif
+{
+ struct socket_info *si = find_socket_info(s);
+#define __SWRAP_RECVMMSG_MAX_VLEN 16
+ struct mmsghdr msgvec[__SWRAP_RECVMMSG_MAX_VLEN] = {};
+ struct {
+ struct iovec iov;
+ struct swrap_address from_addr;
+ struct swrap_address convert_addr;
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ size_t msg_ctrllen_filled;
+ size_t msg_ctrllen_left;
+#endif
+ } tmp[__SWRAP_RECVMMSG_MAX_VLEN] = {};
+ int vlen;
+ int i;
+ int ret;
+ int rc;
+ int saved_errno;
+
+ if (_vlen > __SWRAP_RECVMMSG_MAX_VLEN) {
+ vlen = __SWRAP_RECVMMSG_MAX_VLEN;
+ } else {
+ vlen = _vlen;
+ }
+
+ if (si == NULL) {
+ uint8_t *tmp_control[__SWRAP_RECVMMSG_MAX_VLEN] = { NULL, };
+
+ for (i = 0; i < vlen; i++) {
+ struct msghdr *omsg = &omsgvec[i].msg_hdr;
+ struct msghdr *msg = &msgvec[i].msg_hdr;
+
+ rc = swrap_recvmsg_before_unix(omsg, msg,
+ &tmp_control[i]);
+ if (rc < 0) {
+ ret = rc;
+ goto fail_libc;
+ }
+ }
+
+ ret = libc_recvmmsg(s, msgvec, vlen, flags, timeout);
+ if (ret < 0) {
+ goto fail_libc;
+ }
+
+ for (i = 0; i < ret; i++) {
+ omsgvec[i].msg_len = msgvec[i].msg_len;
+ }
+
+fail_libc:
+ saved_errno = errno;
+ for (i = 0; i < vlen; i++) {
+ struct msghdr *omsg = &omsgvec[i].msg_hdr;
+ struct msghdr *msg = &msgvec[i].msg_hdr;
+
+ if (i == 0 || i < ret) {
+ swrap_recvmsg_after_unix(msg, &tmp_control[i], omsg, ret);
+ }
+ SAFE_FREE(tmp_control[i]);
+ }
+ errno = saved_errno;
+
+ return ret;
+ }
+
+ for (i = 0; i < vlen; i++) {
+ struct msghdr *omsg = &omsgvec[i].msg_hdr;
+ struct msghdr *msg = &msgvec[i].msg_hdr;
+
+ tmp[i].from_addr.sa_socklen = sizeof(struct sockaddr_un);
+ tmp[i].convert_addr.sa_socklen = sizeof(struct sockaddr_storage);
+
+ msg->msg_name = &tmp[i].from_addr.sa; /* optional address */
+ msg->msg_namelen = tmp[i].from_addr.sa_socklen; /* size of address */
+ msg->msg_iov = omsg->msg_iov; /* scatter/gather array */
+ msg->msg_iovlen = omsg->msg_iovlen; /* # elements in msg_iov */
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ tmp[i].msg_ctrllen_filled = 0;
+ tmp[i].msg_ctrllen_left = omsg->msg_controllen;
+
+ msg->msg_control = omsg->msg_control; /* ancillary data, see below */
+ msg->msg_controllen = omsg->msg_controllen; /* ancillary data buffer len */
+ msg->msg_flags = omsg->msg_flags; /* flags on received message */
+#endif
+
+ rc = swrap_recvmsg_before(s, si, msg, &tmp[i].iov);
+ if (rc < 0) {
+ ret = rc;
+ goto fail_swrap;
+ }
+ }
+
+ ret = libc_recvmmsg(s, msgvec, vlen, flags, timeout);
+ if (ret < 0) {
+ goto fail_swrap;
+ }
+
+ for (i = 0; i < ret; i++) {
+ omsgvec[i].msg_len = msgvec[i].msg_len;
+ }
+
+fail_swrap:
+
+ saved_errno = errno;
+ for (i = 0; i < vlen; i++) {
+ struct msghdr *omsg = &omsgvec[i].msg_hdr;
+ struct msghdr *msg = &msgvec[i].msg_hdr;
+
+ if (!(i == 0 || i < ret)) {
+ break;
+ }
+
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ tmp[i].msg_ctrllen_filled += msg->msg_controllen;
+ tmp[i].msg_ctrllen_left -= msg->msg_controllen;
+
+ if (omsg->msg_control != NULL) {
+ uint8_t *p;
+
+ p = omsg->msg_control;
+ p += tmp[i].msg_ctrllen_filled;
+
+ msg->msg_control = p;
+ msg->msg_controllen = tmp[i].msg_ctrllen_left;
+ } else {
+ msg->msg_control = NULL;
+ msg->msg_controllen = 0;
+ }
+#endif
+
+ /*
+ * We convert the unix address to a IP address so we need a buffer
+ * which can store the address in case of SOCK_DGRAM, see below.
+ */
+ msg->msg_name = &tmp[i].convert_addr.sa;
+ msg->msg_namelen = tmp[i].convert_addr.sa_socklen;
+
+ swrap_recvmsg_after(s, si, msg,
+ &tmp[i].from_addr.sa.un,
+ tmp[i].from_addr.sa_socklen,
+ ret);
+
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ if (omsg->msg_control != NULL) {
+ /* msg->msg_controllen = space left */
+ tmp[i].msg_ctrllen_left = msg->msg_controllen;
+ tmp[i].msg_ctrllen_filled = omsg->msg_controllen - tmp[i].msg_ctrllen_left;
+ }
+
+ /* Update the original message length */
+ omsg->msg_controllen = tmp[i].msg_ctrllen_filled;
+ omsg->msg_flags = msg->msg_flags;
+#endif
+ omsg->msg_iovlen = msg->msg_iovlen;
+
+ SWRAP_LOCK_SI(si);
+
+ /*
+ * From the manpage:
+ *
+ * The msg_name field points to a caller-allocated buffer that is
+ * used to return the source address if the socket is unconnected. The
+ * caller should set msg_namelen to the size of this buffer before this
+ * call; upon return from a successful call, msg_name will contain the
+ * length of the returned address. If the application does not need
+ * to know the source address, msg_name can be specified as NULL.
+ */
+ if (si->type == SOCK_STREAM) {
+ omsg->msg_namelen = 0;
+ } else if (omsg->msg_name != NULL &&
+ omsg->msg_namelen != 0 &&
+ omsg->msg_namelen >= msg->msg_namelen) {
+ memcpy(omsg->msg_name, msg->msg_name, msg->msg_namelen);
+ omsg->msg_namelen = msg->msg_namelen;
+ }
+
+ SWRAP_UNLOCK_SI(si);
+ }
+ errno = saved_errno;
+
+ return ret;
+}
+
+#if defined(HAVE_RECVMMSG_SSIZE_T_CONST_TIMEOUT)
+/* FreeBSD */
+ssize_t recvmmsg(int sockfd, struct mmsghdr *msgvec, size_t vlen, int flags, const struct timespec *timeout)
+#elif defined(HAVE_RECVMMSG_CONST_TIMEOUT)
+/* Linux legacy glibc < 2.21 */
+int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, const struct timespec *timeout)
+#else
+/* Linux glibc >= 2.21 */
+int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout)
+#endif
+{
+ return swrap_recvmmsg(sockfd, msgvec, vlen, flags, timeout);
+}
+#endif /* HAVE_RECVMMSG */
+
/****************************************************************************
* SENDMSG
***************************************************************************/
return swrap_sendmsg(s, omsg, flags);
}
+/****************************************************************************
+ * SENDMMSG
+ ***************************************************************************/
+
+#ifdef HAVE_SENDMMSG
+#if defined(HAVE_SENDMMSG_SSIZE_T)
+/* FreeBSD */
+static ssize_t swrap_sendmmsg(int s, struct mmsghdr *omsgvec, size_t _vlen, int flags)
+#else
+/* Linux */
+static int swrap_sendmmsg(int s, struct mmsghdr *omsgvec, unsigned int _vlen, int flags)
+#endif
+{
+ struct socket_info *si = find_socket_info(s);
+#define __SWRAP_SENDMMSG_MAX_VLEN 16
+ struct mmsghdr msgvec[__SWRAP_SENDMMSG_MAX_VLEN] = {};
+ struct {
+ struct iovec iov;
+ struct sockaddr_un un_addr;
+ const struct sockaddr_un *to_un;
+ const struct sockaddr *to;
+ int bcast;
+ } tmp[__SWRAP_SENDMMSG_MAX_VLEN] = {};
+ int vlen;
+ int i;
+ char *swrap_dir = NULL;
+ int connected = 0;
+ int found_bcast = 0;
+ int ret;
+ int rc;
+ int saved_errno;
+
+ if (_vlen > __SWRAP_SENDMMSG_MAX_VLEN) {
+ vlen = __SWRAP_SENDMMSG_MAX_VLEN;
+ } else {
+ vlen = _vlen;
+ }
+
+ if (!si) {
+ int scm_rights_pipe_fd[__SWRAP_SENDMMSG_MAX_VLEN];
+
+ for (i = 0; i < __SWRAP_SENDMMSG_MAX_VLEN; i++) {
+ scm_rights_pipe_fd[i] = -1;
+ }
+
+ for (i = 0; i < vlen; i++) {
+ struct msghdr *omsg = &omsgvec[i].msg_hdr;
+ struct msghdr *msg = &msgvec[i].msg_hdr;
+
+ rc = swrap_sendmsg_before_unix(omsg, msg,
+ &scm_rights_pipe_fd[i]);
+ if (rc < 0) {
+ ret = rc;
+ goto fail_libc;
+ }
+ }
+
+ ret = libc_sendmmsg(s, msgvec, vlen, flags);
+ if (ret < 0) {
+ goto fail_libc;
+ }
+
+ for (i = 0; i < ret; i++) {
+ omsgvec[i].msg_len = msgvec[i].msg_len;
+ }
+
+fail_libc:
+ saved_errno = errno;
+ for (i = 0; i < vlen; i++) {
+ struct msghdr *msg = &msgvec[i].msg_hdr;
+
+ swrap_sendmsg_after_unix(msg, ret,
+ scm_rights_pipe_fd[i]);
+ }
+ errno = saved_errno;
+
+ return ret;
+ }
+
+ SWRAP_LOCK_SI(si);
+ connected = si->connected;
+ SWRAP_UNLOCK_SI(si);
+
+ for (i = 0; i < vlen; i++) {
+ struct msghdr *omsg = &omsgvec[i].msg_hdr;
+ struct msghdr *msg = &msgvec[i].msg_hdr;
+
+ if (connected == 0) {
+ msg->msg_name = omsg->msg_name; /* optional address */
+ msg->msg_namelen = omsg->msg_namelen; /* size of address */
+ }
+ msg->msg_iov = omsg->msg_iov; /* scatter/gather array */
+ msg->msg_iovlen = omsg->msg_iovlen; /* # elements in msg_iov */
+
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ if (omsg->msg_controllen > 0 && omsg->msg_control != NULL) {
+ uint8_t *cmbuf = NULL;
+ size_t cmlen = 0;
+
+ rc = swrap_sendmsg_filter_cmsghdr(omsg, &cmbuf, &cmlen);
+ if (rc < 0) {
+ ret = rc;
+ goto fail_swrap;
+ }
+
+ if (cmlen != 0) {
+ msg->msg_control = cmbuf;
+ msg->msg_controllen = cmlen;
+ }
+ }
+ msg->msg_flags = omsg->msg_flags; /* flags on received message */
+#endif
+
+ rc = swrap_sendmsg_before(s, si, msg,
+ &tmp[i].iov,
+ &tmp[i].un_addr,
+ &tmp[i].to_un,
+ &tmp[i].to,
+ &tmp[i].bcast);
+ if (rc < 0) {
+ ret = rc;
+ goto fail_swrap;
+ }
+
+ if (tmp[i].bcast) {
+ found_bcast = 1;
+ }
+ }
+
+ if (found_bcast) {
+
+ swrap_dir = socket_wrapper_dir();
+ if (swrap_dir == NULL) {
+ ret = -1;
+ goto fail_swrap;
+ }
+
+ for (i = 0; i < vlen; i++) {
+ struct msghdr *msg = &msgvec[i].msg_hdr;
+ struct sockaddr_un *un_addr = &tmp[i].un_addr;
+ const struct sockaddr *to = tmp[i].to;
+ struct stat st;
+ unsigned int iface;
+ unsigned int prt = ntohs(((const struct sockaddr_in *)(const void *)to)->sin_port);
+ char type;
+ size_t l, len = 0;
+ uint8_t *buf;
+ off_t ofs = 0;
+ size_t avail = 0;
+ size_t remain;
+
+ for (l = 0; l < (size_t)msg->msg_iovlen; l++) {
+ avail += msg->msg_iov[l].iov_len;
+ }
+
+ len = avail;
+ remain = avail;
+
+ /* we capture it as one single packet */
+ buf = (uint8_t *)malloc(remain);
+ if (!buf) {
+ ret = -1;
+ goto fail_swrap;
+ }
+
+ for (l = 0; l < (size_t)msg->msg_iovlen; l++) {
+ size_t this_time = MIN(remain, (size_t)msg->msg_iov[l].iov_len);
+ memcpy(buf + ofs,
+ msg->msg_iov[l].iov_base,
+ this_time);
+ ofs += this_time;
+ remain -= this_time;
+ }
+
+ type = SOCKET_TYPE_CHAR_UDP;
+
+ for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
+ swrap_un_path(un_addr, swrap_dir, type, iface, prt);
+ if (stat(un_addr->sun_path, &st) != 0) continue;
+
+ msg->msg_name = un_addr; /* optional address */
+ msg->msg_namelen = sizeof(*un_addr); /* size of address */
+
+ /*
+ * ignore the any errors in broadcast sends and
+ * do a single sendmsg instead of sendmmsg
+ */
+ libc_sendmsg(s, msg, flags);
+ }
+
+ SWRAP_LOCK_SI(si);
+ swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
+ SWRAP_UNLOCK_SI(si);
+
+ SAFE_FREE(buf);
+
+ msgvec[i].msg_len = len;
+ }
+
+ ret = vlen;
+ goto bcast_done;
+ }
+
+ ret = libc_sendmmsg(s, msgvec, vlen, flags);
+ if (ret < 0) {
+ goto fail_swrap;
+ }
+
+bcast_done:
+ for (i = 0; i < ret; i++) {
+ omsgvec[i].msg_len = msgvec[i].msg_len;
+ }
+
+fail_swrap:
+ saved_errno = errno;
+ for (i = 0; i < vlen; i++) {
+ struct msghdr *msg = &msgvec[i].msg_hdr;
+
+ if (i == 0 || i < ret) {
+ swrap_sendmsg_after(s, si, msg, tmp[i].to, ret);
+ }
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ SAFE_FREE(msg->msg_control);
+#endif
+ }
+ SAFE_FREE(swrap_dir);
+ errno = saved_errno;
+
+ return ret;
+}
+
+#if defined(HAVE_SENDMMSG_SSIZE_T)
+/* FreeBSD */
+ssize_t sendmmsg(int s, struct mmsghdr *msgvec, size_t vlen, int flags)
+#else
+/* Linux */
+int sendmmsg(int s, struct mmsghdr *msgvec, unsigned int vlen, int flags)
+#endif
+{
+ return swrap_sendmmsg(s, msgvec, vlen, flags);
+}
+#endif /* HAVE_SENDMMSG */
+
/****************************************************************************
* READV
***************************************************************************/