diff options
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | sysdeps/mach/hurd/recvmsg.c | 144 | ||||
-rw-r--r-- | sysdeps/mach/hurd/sendmsg.c | 152 |
3 files changed, 301 insertions, 0 deletions
@@ -1,3 +1,8 @@ +2001-07-29 Mark Kettenis <kettenis@gnu.org> + + * sysdeps/mach/hurd/recvmsg.c: New file. + * sysdeps/mach/hurd/sendmsg.c: New file. + 2001-07-27 Ulrich Drepper <drepper@redhat.com> * version.h (VERSION): Bump to 2.2.4. diff --git a/sysdeps/mach/hurd/recvmsg.c b/sysdeps/mach/hurd/recvmsg.c new file mode 100644 index 0000000000..73cd03c6d4 --- /dev/null +++ b/sysdeps/mach/hurd/recvmsg.c @@ -0,0 +1,144 @@ +/* Copyright (C) 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <string.h> +#include <sys/socket.h> + +#include <hurd.h> +#include <hurd/fd.h> +#include <hurd/socket.h> + +/* Receive a message as described by MESSAGE from socket FD. + Returns the number of bytes read or -1 for errors. */ +ssize_t +__libc_recvmsg (int fd, struct msghdr *message, int flags) +{ + error_t err; + addr_port_t aport; + char *data = NULL; + mach_msg_type_number_t len = 0; + mach_port_t *ports; + mach_msg_type_number_t nports; + char *cdata = NULL; + mach_msg_type_number_t clen = 0; + size_t amount; + char *buf; + int i; + + /* Find the total number of bytes to be read. */ + amount = 0; + for (i = 0; i < message->msg_iovlen; i++) + { + amount += message->msg_iov[i].iov_len; + + /* As an optimization, we set the initial values of DATA and LEN + from the first non-empty iovec. This kicks-in in the case + where the whole packet fits into that iovec buffer. */ + if (data == NULL && message->msg_iov[i].iov_len > 0) + { + data = message->msg_iov[i].iov_base; + len = message->msg_iov[i].iov_len; + } + } + + buf = data; + if (err = HURD_DPORT_USE (fd, __socket_recv (port, &aport, + flags, &data, &len, + &ports, &nports, + &cdata, &clen, + &message->msg_flags, amount))) + return __hurd_dfail (fd, err); + + if (message->msg_name != NULL) + { + char *buf = message->msg_name; + mach_msg_type_number_t buflen = message->msg_namelen; + int type; + + err = __socket_whatis_address (aport, &type, &buf, &buflen); + if (err == EOPNOTSUPP) + /* If the protocol server can't tell us the address, just return a + zero-length one. */ + { + buf = message->msg_name; + buflen = 0; + err = 0; + } + + if (err) + { + __mach_port_deallocate (__mach_task_self (), aport); + return __hurd_dfail (fd, err); + } + + if (message->msg_namelen > buflen) + message->msg_namelen = buflen; + + if (buf != message->msg_name) + { + memcpy (message->msg_name, buf, message->msg_namelen); + __vm_deallocate (__mach_task_self (), (vm_address_t) buf, buflen); + } + + if (buflen > 0) + ((struct sockaddr *) message->msg_name)->sa_family = type; + } + + __mach_port_deallocate (__mach_task_self (), aport); + + if (buf == data) + buf += len; + else + { + /* Copy the data into MSG. */ + if (len > amount) + message->msg_flags |= MSG_TRUNC; + else + amount = len; + + buf = data; + for (i = 0; i < message->msg_iovlen; i++) + { +#define min(a, b) ((a) > (b) ? (b) : (a)) + size_t copy = min (message->msg_iov[i].iov_len, amount); + + memcpy (message->msg_iov[i].iov_base, buf, copy); + + buf += copy; + amount -= copy; + if (len == 0) + break; + } + + __vm_deallocate (__mach_task_self (), (vm_address_t) data, len); + } + + /* Copy the control message into MSG. */ + if (clen > message->msg_controllen) + message->msg_flags |= MSG_CTRUNC; + else + message->msg_controllen = clen; + memcpy (message->msg_control, cdata, message->msg_controllen); + + __vm_deallocate (__mach_task_self (), (vm_address_t) cdata, clen); + + return (buf - data); +} + +weak_alias (__libc_recvmsg, recvmsg) diff --git a/sysdeps/mach/hurd/sendmsg.c b/sysdeps/mach/hurd/sendmsg.c new file mode 100644 index 0000000000..c55b559e29 --- /dev/null +++ b/sysdeps/mach/hurd/sendmsg.c @@ -0,0 +1,152 @@ +/* Copyright (C) 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <hurd.h> +#include <hurd/fd.h> +#include <hurd/ifsock.h> +#include <hurd/socket.h> + +/* Send a message described MESSAGE on socket FD. + Returns the number of bytes sent, or -1 for errors. */ +ssize_t +__libc_sendmsg (int fd, const struct msghdr *message, int flags) +{ + error_t err = 0; + struct sockaddr_un *addr = message->msg_name; + socklen_t addr_len = message->msg_namelen; + addr_port_t aport = MACH_PORT_NULL; + char *data = NULL; + char data_buf[2048]; + mach_msg_type_number_t len; + mach_msg_type_number_t amount; + int dealloc = 0; + int i; + + /* Find the total number of bytes to be written. */ + len = 0; + for (i = 0; i < message->msg_iovlen; i++) + { + if (message->msg_iov[i].iov_len > 0) + { + /* As an optimization, if we only have a single non-empty + iovec, we set DATA and LEN from it. */ + if (len == 0) + data = message->msg_iov[i].iov_base; + else + data = NULL; + + len += message->msg_iov[i].iov_len; + } + } + + if (data == NULL) + { + size_t to_copy; + char *buf; + + /* Allocate a temporary buffer to hold the data. For small + amounts of data, we allocate a buffer on the stack. Larger + amounts of data are stored in a page-aligned buffer. The + limit of 2048 bytes is inspired by the MiG stubs. */ + if (len > 2048) + { + err = __vm_allocate (__mach_task_self (), + (vm_address_t *) &data, len, 1); + if (err) + { + __set_errno (err); + return -1; + } + dealloc = 1; + } + else + data = data_buf; + + /* Copy the data into DATA. */ + to_copy = len; + buf = data; + for (i = 0; i < len; i++) + { +#define min(a, b) ((a) > (b) ? (b) : (a)) + size_t copy = min (message->msg_iov[i].iov_len, to_copy); + + buf = __mempcpy (buf, message->msg_iov[i].iov_base, copy); + + to_copy -= copy; + if (to_copy == 0) + break; + } + } + + if (addr) + { + if (addr->sun_family == AF_LOCAL) + { + /* For the local domain, we must look up the name as a file + and talk to it with the ifsock protocol. */ + file_t file = __file_name_lookup (addr->sun_path, 0, 0); + if (file == MACH_PORT_NULL) + return -1; + err = __ifsock_getsockaddr (file, &aport); + __mach_port_deallocate (__mach_task_self (), file); + if (err == MIG_BAD_ID || err == EOPNOTSUPP) + /* The file did not grok the ifsock protocol. */ + err = ENOTSOCK; + if (err) + return __hurd_fail (err); + } + else + err = EIEIO; + } + + err = HURD_DPORT_USE (fd, + ({ + if (err) + err = __socket_create_address (port, + addr->sun_family, + (char *) addr, + addr_len, + &aport); + if (! err) + { + /* Send the data. */ + err = __socket_send (port, aport, + flags, data, len, + NULL, + MACH_MSG_TYPE_COPY_SEND, 0, + message->msg_control, + message->msg_controllen, + &amount); + __mach_port_deallocate (__mach_task_self (), + aport); + } + err; + })); + + if (dealloc) + __vm_deallocate (__mach_task_self (), (vm_address_t) data, len); + + return err ? __hurd_dfail (fd, err) : amount; +} + +weak_alias (__libc_sendmsg, sendmsg) |