From 5eaf863528c7f4304a528c6d85a7124b538bbcfc Mon Sep 17 00:00:00 2001 From: Fabrizio Bertocci Date: Wed, 7 Apr 2021 08:53:47 -0400 Subject: [PATCH] Changed the type of msghdr->msg_namelen to be uint32_t instead of int32_t (the original type is socklen_t and is not signed). Added implementation of recvmsg --- libc/sock/internal.h | 2 ++ libc/sock/recvmsg.c | 54 +++++++++++++++++++++++++++++++++++++ libc/sock/sendmsg.c | 64 ++++++++++++++++++++++++++++++++++++++++++++ libc/sock/sock.h | 4 +-- 4 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 libc/sock/recvmsg.c create mode 100644 libc/sock/sendmsg.c diff --git a/libc/sock/internal.h b/libc/sock/internal.h index 1a9c38838..9c468fc25 100644 --- a/libc/sock/internal.h +++ b/libc/sock/internal.h @@ -89,6 +89,8 @@ int64_t sys_writev(int32_t, const struct iovec *, int32_t) hidden; ssize_t sys_recvfrom(int, void *, size_t, int, void *, uint32_t *) hidden; ssize_t sys_sendto(int, const void *, size_t, int, const void *, uint32_t) hidden; +ssize_t sys_sendmsg(int, const struct msghdr *, int) hidden; +ssize_t sys_recvmsg(int, struct msghdr *, int) hidden; int32_t sys_select(int32_t, fd_set *, fd_set *, fd_set *, struct timeval *) hidden; int sys_setsockopt(int, int, int, const void *, uint32_t) hidden; diff --git a/libc/sock/recvmsg.c b/libc/sock/recvmsg.c new file mode 100644 index 000000000..704c6eba5 --- /dev/null +++ b/libc/sock/recvmsg.c @@ -0,0 +1,54 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" +#include "libc/calls/internal.h" +#include "libc/calls/struct/iovec.h" +#include "libc/dce.h" +#include "libc/sock/internal.h" +#include "libc/sock/sock.h" +#include "libc/str/str.h" +#include "libc/sysv/errfuns.h" + +/** + * Sends a message from a socket. + * + * @param fd is the file descriptor returned by socket() + * @param msg is a pointer to a struct msghdr containing all the allocated + * buffers where to store incoming data. + * @param flags MSG_OOB, MSG_DONTROUTE, MSG_PARTIAL, MSG_NOSIGNAL, etc. + * @return number of bytes received, or -1 w/ errno + * @error EINTR, EHOSTUNREACH, ECONNRESET (UDP ICMP Port Unreachable), + * EPIPE (if MSG_NOSIGNAL), EMSGSIZE, ENOTSOCK, EFAULT, etc. + * @asyncsignalsafe + */ +ssize_t recvmsg(int fd, struct msghdr *msg, int flags) { + if (!IsWindows()) { + ssize_t got = sys_recvmsg(fd, msg, flags); + /* An address was provided, convert from BSD form */ + if (msg->msg_name && IsBsd() && got != -1) { + sockaddr2linux(msg->msg_name); + } + return got; + } else if (__isfdkind(fd, kFdSocket)) { + return sys_recvfrom_nt(&g_fds.p[fd], msg->msg_iov, msg->msg_iovlen, flags, + msg->msg_name, &msg->msg_namelen); + } else { + return ebadf(); + } +} diff --git a/libc/sock/sendmsg.c b/libc/sock/sendmsg.c new file mode 100644 index 000000000..5e9cca4c2 --- /dev/null +++ b/libc/sock/sendmsg.c @@ -0,0 +1,64 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" +#include "libc/calls/internal.h" +#include "libc/calls/struct/iovec.h" +#include "libc/dce.h" +#include "libc/sock/internal.h" +#include "libc/sock/sock.h" +#include "libc/str/str.h" +#include "libc/sysv/errfuns.h" + +/** + * Sends a message on a socket. + * + * @param fd is the file descriptor returned by socket() + * @param msg is a pointer to a struct msghdr containing all the required + * parameters (the destination address, buffers, ...) + * @param flags MSG_OOB, MSG_DONTROUTE, MSG_PARTIAL, MSG_NOSIGNAL, etc. + * @return number of bytes transmitted, or -1 w/ errno + * @error EINTR, EHOSTUNREACH, ECONNRESET (UDP ICMP Port Unreachable), + * EPIPE (if MSG_NOSIGNAL), EMSGSIZE, ENOTSOCK, EFAULT, etc. + * @asyncsignalsafe + */ +ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) { + if (!IsWindows()) { + if (IsBsd() && msg->msg_name) { + /* An optional address is provided, convert it to the BSD form */ + char addr2[128]; + struct msghdr msg2; + if (sizeof(addr2) > msg->msg_namelen) return einval(); + memcpy(&addr2[0], msg->msg_name, msg->msg_namelen); + sockaddr2bsd(&addr2[0]); + + /* Copy all of msg (except for msg_name) into the new ephemeral local */ + memcpy(&msg2, msg, sizeof(msg2)); + msg2.msg_name = &addr2[0]; + return sys_sendmsg(fd, &msg2, flags); + } + /* else do the syscall */ + return sys_sendmsg(fd, msg, flags); + } else if (__isfdkind(fd, kFdSocket)) { + if (msg->msg_control != NULL) return einval(); /* Control msg not supported */ + return sys_sendto_nt(&g_fds.p[fd], msg->msg_iov, msg->msg_iovlen, flags, + msg->msg_name, msg->msg_namelen); + } else { + return ebadf(); + } +} diff --git a/libc/sock/sock.h b/libc/sock/sock.h index 2983b640e..9590ca6ba 100644 --- a/libc/sock/sock.h +++ b/libc/sock/sock.h @@ -62,7 +62,7 @@ struct pollfd { struct msghdr { /* Linux+NT ABI */ void *msg_name; /* optional address */ - int32_t msg_namelen; /* size of msg_name */ + uint32_t msg_namelen; /* size of msg_name */ struct iovec *msg_iov; /* scatter/gather array */ uint64_t msg_iovlen; /* iovec count */ void *msg_control; /* credentials and stuff */ @@ -89,7 +89,7 @@ int getsockname(int, void *, uint32_t *) paramsnonnull(); int getpeername(int, void *, uint32_t *) paramsnonnull(); ssize_t send(int, const void *, size_t, int) paramsnonnull(); ssize_t recv(int, void *, size_t, int); -ssize_t recvmsg(int, struct msghdr *, uint32_t) paramsnonnull(); +ssize_t recvmsg(int, struct msghdr *, int) paramsnonnull(); ssize_t recvfrom(int, void *, size_t, uint32_t, void *, uint32_t *); ssize_t sendmsg(int, const struct msghdr *, int) paramsnonnull(); ssize_t readv(int, const struct iovec *, int);