diff options
author | Michael I. Bushnell <mib@gnu.org> | 1996-07-18 04:35:29 +0000 |
---|---|---|
committer | Michael I. Bushnell <mib@gnu.org> | 1996-07-18 04:35:29 +0000 |
commit | 94cef36797600d11a50d09828fa80df8a73dfd1c (patch) | |
tree | b7cba9afef95489eedef534d3e6946eb13f595ba /nfsd/loop.c | |
parent | 88dbbbf9e48e24f1ac007c1e4eeffd9caf8e2fad (diff) |
*** empty log message ***
Diffstat (limited to 'nfsd/loop.c')
-rw-r--r-- | nfsd/loop.c | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/nfsd/loop.c b/nfsd/loop.c new file mode 100644 index 00000000..3520e1da --- /dev/null +++ b/nfsd/loop.c @@ -0,0 +1,233 @@ +/* + Copyright (C) 1996 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +#include <string.h> +#include <fcntl.h> + +#include "nfsd.h" + +#include <rpc/pmap_prot.h> +#include "../nfs/rpcsvc/mount.h" + +#undef TRUE +#undef FALSE +#define malloc spoogie_woogie /* barf */ +#include <rpc/xdr.h> +#include <rpc/types.h> +#include <rpc/auth.h> +#include <rpc/rpc_msg.h> +#undef malloc + +void +server_loop () +{ + char buf[MAXIOSIZE]; + int xid; + int *p, *r; + char *rbuf; + struct cached_reply *cr; + int program; + struct sockaddr_in sender; + int version; + int procedure; + struct proctable *table = 0; + struct procedure *proc; + struct idspec *cred; + struct cache_handle *c, fakec; + error_t err; + size_t addrlen; + fd_set readfds; + int maxfd; + int i; + int *errloc; + + bzero (&fakec, sizeof (struct cache_handle)); + + if (main_udp_socket > pmap_udp_socket) + maxfd = main_udp_socket; + else + maxfd = pmap_udp_socket; + + for (;;) + { + FD_ZERO (&readfds); + FD_SET (main_udp_socket, &readfds); + FD_SET (pmap_udp_socket, &readfds); + select (maxfd, &readfds, 0, 0, 0); + + for (i = main_udp_socket; + i != -1; + i = (i == main_udp_socket ? pmap_udp_socket : -1)) + { + if (!FD_ISSET (i, &readfds)) + continue; + + p = (int *) buf; + proc = 0; + addrlen = sizeof (struct sockaddr_in); + recvfrom (i, buf, MAXIOSIZE, 0, &sender, &addrlen); + xid = *p++; + + /* Ignore things that aren't proper RPCs. */ + if (ntohl (*p++) != CALL) + continue; + + cr = check_cached_replies (xid, &sender); + if (cr->data) + /* This transacation has already completed */ + goto repost_reply; + + r = (int *) rbuf = malloc (MAXIOSIZE); + + if (ntohl (*p++) != RPC_MSG_VERSION) + { + /* Reject RPC */ + *r++ = xid; + *r++ = htonl (REPLY); + *r++ = htonl (MSG_DENIED); + *r++ = htonl (RPC_MISMATCH); + *r++ = htonl (RPC_MSG_VERSION); + *r++ = htonl (RPC_MSG_VERSION); + goto send_reply; + } + + program = ntohl (*p++); + switch (program) + { + case MOUNTPROG: + version = MOUNTVERS; + table = &mounttable; + break; + + case NFS_PROGRAM: + version = NFS_VERSION; + table = &nfstable; + break; + + case PMAPPROG: + version = PMAPVERS; + table = &pmaptable; + break; + + default: + /* Program unavailable */ + *r++ = xid; + *r++ = htonl (REPLY); + *r++ = htonl (MSG_ACCEPTED); + *r++ = htonl (AUTH_NULL); + *r++ = htonl (0); + *r++ = htonl (PROG_UNAVAIL); + goto send_reply; + } + + if (ntohl (*p++) != version) + { + /* Program mismatch */ + *r++ = xid; + *r++ = htonl (REPLY); + *r++ = htonl (MSG_ACCEPTED); + *r++ = htonl (AUTH_NULL); + *r++ = htonl (0); + *r++ = htonl (PROG_MISMATCH); + *r++ = htonl (version); + *r++ = htonl (version); + goto send_reply; + } + + procedure = htonl (*p++); + if (procedure < table->min + || procedure > table->max + || table->procs[procedure - table->min].func == 0) + { + /* Procedure unavailable */ + *r++ = xid; + *r++ = htonl (REPLY); + *r++ = htonl (MSG_ACCEPTED); + *r++ = htonl (AUTH_NULL); + *r++ = htonl (0); + *r++ = htonl (PROC_UNAVAIL); + *r++ = htonl (table->min); + *r++ = htonl (table->max); + goto send_reply; + } + proc = &table->procs[procedure - table->min]; + + p = process_cred (p, &cred); /* auth */ + p = skip_cred (p); /* verf */ + + if (proc->need_handle) + p = lookup_cache_handle (p, &c, cred); + else + { + fakec.ids = cred; + c = &fakec; + } + + if (proc->alloc_reply) + { + size_t amt; + amt = (*proc->alloc_reply) (p) + 256; + if (amt > MAXIOSIZE) + { + free (rbuf); + r = (int *) rbuf = malloc (amt); + } + } + + /* Fill in beginning of reply */ + *r++ = xid; + *r++ = htonl (REPLY); + *r++ = htonl (MSG_ACCEPTED); + *r++ = htonl (AUTH_NULL); + *r++ = htonl (0); + *r++ = htonl (SUCCESS); + if (proc->process_error) + { + /* Assume success for now and patch it later if necessary */ + errloc = r; + *r++ = htonl (0); + } + + if (c) + err = (*proc->func) (c, p, &r); + else + err = ESTALE; + + if (proc->process_error && err) + { + r = errloc; + *r++ = htonl (nfs_error_trans (err)); + } + + cred_rele (cred); + if (c != &fakec) + cache_handle_rele (c); + + send_reply: + cr->data = rbuf; + cr->len = (char *)r - rbuf; + + repost_reply: + sendto (i, cr->data, cr->len, 0, + (struct sockaddr *)&sender, addrlen); + release_cached_reply (cr); + } + } +} |