aboutsummaryrefslogtreecommitdiff
path: root/lwip/io-ops.c
diff options
context:
space:
mode:
Diffstat (limited to 'lwip/io-ops.c')
-rw-r--r--lwip/io-ops.c554
1 files changed, 554 insertions, 0 deletions
diff --git a/lwip/io-ops.c b/lwip/io-ops.c
new file mode 100644
index 00000000..636c26f7
--- /dev/null
+++ b/lwip/io-ops.c
@@ -0,0 +1,554 @@
+/*
+ Copyright (C) 1995,96,97,98,99,2000,02,17 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* General input/output operations */
+
+#include <lwip_io_S.h>
+
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <lwip/sockets.h>
+
+error_t
+lwip_S_io_write (struct sock_user *user,
+ char *data,
+ size_t datalen,
+ off_t offset, mach_msg_type_number_t * amount)
+{
+ int sent;
+ int sockflags;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ sockflags = lwip_fcntl (user->sock->sockno, F_GETFL, 0);
+ sent = lwip_send (user->sock->sockno, data, datalen,
+ (sockflags & O_NONBLOCK) ? MSG_DONTWAIT : 0);
+
+ if (sent >= 0)
+ {
+ *amount = sent;
+ }
+
+ return errno;
+}
+
+error_t
+lwip_S_io_read (struct sock_user * user,
+ char **data,
+ size_t * datalen, off_t offset, mach_msg_type_number_t amount)
+{
+ error_t err;
+ int alloced = 0;
+ int flags;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ /* Instead of this, we should peek and the socket and only
+ allocate as much as necessary. */
+ if (amount > *datalen)
+ {
+ *data = mmap (0, amount, PROT_READ | PROT_WRITE, MAP_ANON, 0, 0);
+ if (*data == MAP_FAILED)
+ /* Should check whether errno is indeed ENOMEM --
+ but this can't be done in a straightforward way,
+ because the glue headers #undef errno. */
+ return ENOMEM;
+ alloced = 1;
+ }
+
+ /* Get flags */
+ flags = lwip_fcntl (user->sock->sockno, F_GETFL, 0);
+
+ err = lwip_recv (user->sock->sockno, *data, amount,
+ (flags & O_NONBLOCK) ? MSG_DONTWAIT : 0);
+
+ if (err < 0)
+ {
+ if (alloced)
+ munmap (*data, amount);
+ }
+ else
+ {
+ *datalen = err;
+ if (alloced && round_page (*datalen) < round_page (amount))
+ munmap (*data + round_page (*datalen),
+ round_page (amount) - round_page (*datalen));
+ errno = 0;
+ }
+
+ return errno;
+}
+
+error_t
+lwip_S_io_seek (struct sock_user * user,
+ off_t offset, int whence, off_t * newp)
+{
+ return user ? ESPIPE : EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_readable (struct sock_user * user, mach_msg_type_number_t * amount)
+{
+ error_t err;
+ if (!user)
+ return EOPNOTSUPP;
+
+ err = lwip_ioctl (user->sock->sockno, FIONREAD, amount);
+
+ if (err < 0)
+ *amount = 0;
+
+ return errno;
+}
+
+error_t
+lwip_S_io_set_all_openmodes (struct sock_user * user, int bits)
+{
+ int opt;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ if (bits & O_NONBLOCK)
+ opt = 1;
+ else
+ opt = 0;
+
+ lwip_ioctl (user->sock->sockno, FIONBIO, &opt);
+
+ return errno;
+}
+
+error_t
+lwip_S_io_get_openmodes (struct sock_user * user, int *bits)
+{
+ if (!user)
+ return EOPNOTSUPP;
+
+ *bits = lwip_fcntl (user->sock->sockno, F_GETFL, 0);
+
+ return errno;
+}
+
+error_t
+lwip_S_io_set_some_openmodes (struct sock_user * user, int bits)
+{
+ if (!user)
+ return EOPNOTSUPP;
+
+ if (bits & O_NONBLOCK)
+ {
+ int opt = 1;
+ lwip_ioctl (user->sock->sockno, FIONBIO, &opt);
+ }
+
+ return errno;
+}
+
+
+error_t
+lwip_S_io_clear_some_openmodes (struct sock_user * user, int bits)
+{
+ if (!user)
+ return EOPNOTSUPP;
+
+ if (bits & O_NONBLOCK)
+ {
+ int opt = 0;
+ lwip_ioctl (user->sock->sockno, FIONBIO, &opt);
+ }
+
+ return errno;
+}
+
+/*
+ * Arrange things to call lwip_poll()
+ */
+static error_t
+lwip_io_select_common (struct sock_user *user,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ struct timespec *tv, int *select_type)
+{
+ int ret;
+ int timeout;
+ struct pollfd fdp;
+ nfds_t nfds;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ /* Make this thread cancellable */
+ ports_interrupt_self_on_notification (user, reply, MACH_NOTIFY_DEAD_NAME);
+
+ memset (&fdp, 0, sizeof (struct pollfd));
+ fdp.fd = user->sock->sockno;
+
+ if (*select_type & SELECT_READ)
+ {
+ fdp.events |= POLLIN;
+ }
+ if (*select_type & SELECT_WRITE)
+ {
+ fdp.events |= POLLOUT;
+ }
+ if (*select_type & SELECT_URG)
+ {
+ fdp.events |= POLLPRI;
+ }
+
+ *select_type = 0;
+
+ nfds = 1;
+ timeout = tv ? tv->tv_sec * 1000 + tv->tv_nsec / 1000000 : -1;
+ ret = lwip_poll (&fdp, nfds, timeout);
+
+ if (ret > 0)
+ {
+ if (fdp.revents & POLLIN)
+ *select_type |= SELECT_READ;
+
+ if (fdp.revents & POLLOUT)
+ *select_type |= SELECT_WRITE;
+
+ if (fdp.revents & POLLPRI)
+ *select_type |= SELECT_URG;
+ }
+
+ return errno;
+}
+
+error_t
+lwip_S_io_select (struct sock_user * user,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type, int *select_type)
+{
+ return lwip_io_select_common (user, reply, reply_type, 0, select_type);
+}
+
+error_t
+lwip_S_io_select_timeout (struct sock_user * user,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ struct timespec ts, int *select_type)
+{
+ struct timespec current_ts;
+ clock_gettime (CLOCK_REALTIME, &current_ts);
+
+ ts.tv_sec -= current_ts.tv_sec;
+ ts.tv_nsec -= current_ts.tv_nsec;
+
+ return lwip_io_select_common (user, reply, reply_type, &ts, select_type);
+}
+
+
+error_t
+lwip_S_io_stat (struct sock_user * user, struct stat * st)
+{
+ if (!user)
+ return EOPNOTSUPP;
+
+ memset (st, 0, sizeof (struct stat));
+
+ st->st_fstype = FSTYPE_SOCKET;
+ st->st_fsid = getpid ();
+ st->st_ino = user->sock->sockno;
+
+ st->st_mode = S_IFSOCK | ACCESSPERMS;
+ st->st_blksize = 512; /* ???? */
+
+ return 0;
+}
+
+error_t
+lwip_S_io_reauthenticate (struct sock_user * user, mach_port_t rend)
+{
+ struct sock_user *newuser;
+ uid_t gubuf[20], ggbuf[20], aubuf[20], agbuf[20];
+ uid_t *gen_uids, *gen_gids, *aux_uids, *aux_gids;
+ size_t genuidlen, gengidlen, auxuidlen, auxgidlen;
+ error_t err;
+ size_t i, j;
+ auth_t auth;
+ mach_port_t newright;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ genuidlen = gengidlen = auxuidlen = auxgidlen = 20;
+ gen_uids = gubuf;
+ gen_gids = ggbuf;
+ aux_uids = aubuf;
+ aux_gids = agbuf;
+
+ newuser = make_sock_user (user->sock, 0, 1, 0);
+
+ auth = getauth ();
+ newright = ports_get_send_right (newuser);
+ assert_backtrace (newright != MACH_PORT_NULL);
+
+ do
+ err = auth_server_authenticate (auth,
+ rend,
+ MACH_MSG_TYPE_COPY_SEND,
+ newright,
+ MACH_MSG_TYPE_COPY_SEND,
+ &gen_uids, &genuidlen,
+ &aux_uids, &auxuidlen,
+ &gen_gids, &gengidlen,
+ &aux_gids, &auxgidlen);
+ while (err == EINTR);
+
+ mach_port_deallocate (mach_task_self (), rend);
+ mach_port_deallocate (mach_task_self (), newright);
+ mach_port_deallocate (mach_task_self (), auth);
+
+ if (err)
+ newuser->isroot = 0;
+ else
+ /* Check permission as fshelp_isowner would do. */
+ for (i = 0; i < genuidlen; i++)
+ {
+ if (gen_uids[i] == 0 || gen_uids[i] == lwip_owner)
+ newuser->isroot = 1;
+ if (gen_uids[i] == lwip_group)
+ for (j = 0; j < gengidlen; j++)
+ if (gen_gids[j] == lwip_group)
+ newuser->isroot = 1;
+ }
+
+ mach_port_move_member (mach_task_self (), newuser->pi.port_right,
+ lwip_bucket->portset);
+
+ ports_port_deref (newuser);
+
+ if (gubuf != gen_uids)
+ munmap (gen_uids, genuidlen * sizeof (uid_t));
+ if (ggbuf != gen_gids)
+ munmap (gen_gids, gengidlen * sizeof (uid_t));
+ if (aubuf != aux_uids)
+ munmap (aux_uids, auxuidlen * sizeof (uid_t));
+ if (agbuf != aux_gids)
+ munmap (aux_gids, auxgidlen * sizeof (uid_t));
+
+ return 0;
+}
+
+error_t
+lwip_S_io_restrict_auth (struct sock_user * user,
+ mach_port_t * newobject,
+ mach_msg_type_name_t * newobject_type,
+ uid_t * uids, size_t uidslen,
+ uid_t * gids, size_t gidslen)
+{
+ struct sock_user *newuser;
+ int i, j;
+ int isroot;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ isroot = 0;
+ if (user->isroot)
+ /* Check permission as fshelp_isowner would do. */
+ for (i = 0; i < uidslen; i++)
+ {
+ if (uids[i] == 0 || uids[i] == lwip_owner)
+ isroot = 1;
+ if (uids[i] == lwip_group)
+ for (j = 0; j < gidslen; j++)
+ if (gids[j] == lwip_group)
+ isroot = 1;
+ }
+
+ newuser = make_sock_user (user->sock, isroot, 0, 0);
+ *newobject = ports_get_right (newuser);
+ *newobject_type = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (newuser);
+
+ return 0;
+}
+
+error_t
+lwip_S_io_duplicate (struct sock_user * user,
+ mach_port_t * newobject,
+ mach_msg_type_name_t * newobject_type)
+{
+ struct sock_user *newuser;
+ if (!user)
+ return EOPNOTSUPP;
+
+ newuser = make_sock_user (user->sock, user->isroot, 0, 0);
+ *newobject = ports_get_right (newuser);
+ *newobject_type = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (newuser);
+
+ return 0;
+}
+
+error_t
+lwip_S_io_identity (struct sock_user * user,
+ mach_port_t * id,
+ mach_msg_type_name_t * idtype,
+ mach_port_t * fsys,
+ mach_msg_type_name_t * fsystype, ino_t * fileno)
+{
+ error_t err;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ if (user->sock->identity == MACH_PORT_NULL)
+ {
+ err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+ &user->sock->identity);
+ if (err)
+ {
+ return err;
+ }
+ }
+
+ *id = user->sock->identity;
+ *idtype = MACH_MSG_TYPE_MAKE_SEND;
+ *fsys = fsys_identity;
+ *fsystype = MACH_MSG_TYPE_MAKE_SEND;
+ *fileno = user->sock->sockno;
+
+ return 0;
+}
+
+error_t
+lwip_S_io_revoke (struct sock_user * user)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_async (struct sock_user * user,
+ mach_port_t notify,
+ mach_port_t * id, mach_msg_type_name_t * idtype)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_mod_owner (struct sock_user * user, pid_t owner)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_get_owner (struct sock_user * user, pid_t * owner)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_get_icky_async_id (struct sock_user * user,
+ mach_port_t * id, mach_msg_type_name_t * idtype)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_server_version (struct sock_user * user,
+ char *name, int *major, int *minor, int *edit)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_pathconf (struct sock_user * user, int name, int *value)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_map (struct sock_user * user,
+ mach_port_t * rdobj,
+ mach_msg_type_name_t * rdobj_type,
+ mach_port_t * wrobj, mach_msg_type_name_t * wrobj_type)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_map_cntl (struct sock_user * user,
+ mach_port_t * obj, mach_msg_type_name_t * obj_type)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_get_conch (struct sock_user * user)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_release_conch (struct sock_user * user)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_eofnotify (struct sock_user * user)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_prenotify (struct sock_user * user,
+ vm_offset_t start, vm_offset_t end)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_postnotify (struct sock_user * user,
+ vm_offset_t start, vm_offset_t end)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_readnotify (struct sock_user * user)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_readsleep (struct sock_user * user)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_sigio (struct sock_user * user)
+{
+ return EOPNOTSUPP;
+}