Add sendmsg and recvmsg (#148)

This commit is contained in:
fabriziobertocci 2021-04-08 01:53:23 -04:00 committed by GitHub
parent da8a08fd58
commit 24d79599cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 184 additions and 2 deletions

View file

@ -95,6 +95,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;

54
libc/sock/recvmsg.c Normal file
View file

@ -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();
}
}

64
libc/sock/sendmsg.c Normal file
View file

@ -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 (msg->msg_namelen > sizeof(addr2)) 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();
}
}

View file

@ -67,7 +67,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 */
@ -94,7 +94,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);

View file

@ -0,0 +1,62 @@
/*-*- 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 2021 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/dce.h"
#include "libc/sock/sock.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sock.h"
#include "libc/testlib/testlib.h"
#include "libc/runtime/gc.internal.h"
#include "libc/x/x.h"
TEST(sendrecvmsg, testPingPong) {
int fd[2];
const char hello[] = "HELLO";
const char world[] = "WORLD";
struct msghdr msg;
struct iovec data[2];
const uint32_t hwLen = strlen(hello)+strlen(world);
memset(&msg, 0, sizeof(msg));
memset(&data[0], 0, sizeof(data));
data[0].iov_base = hello;
data[0].iov_len = strlen(hello);
data[1].iov_base = world;
data[1].iov_len = strlen(world); /* Don't send the '\0' */
msg.msg_iov = &data[0];
msg.msg_iovlen = 2;
ASSERT_NE(-1, socketpair(AF_UNIX, SOCK_STREAM, 0, fd));
ASSERT_EQ(hwLen, sendmsg(fd[0], &msg, 0));
data[0].iov_base = gc(xcalloc(20, 1));
data[0].iov_len = 20;
msg.msg_iovlen = 1;
ASSERT_EQ(hwLen, recvmsg(fd[1], &msg, 0));
EXPECT_STREQ("HELLOWORLD", msg.msg_iov[0].iov_base);
ASSERT_NE(-1, close(fd[0]));
ASSERT_NE(-1, close(fd[1]));
}