home *** CD-ROM | disk | FTP | other *** search
- /* Receives, decodes the headers and delegates incoming RPC packets
-
- ©1999 Joseph Walton
-
- This software is distributed under the terms of the GNU General Public
- License; either version 2 of the License, or (at your option) any
- later version.
- */
-
- #include "rpc.h"
- #include "nfs.h"
- #include "mount.h"
- #include "pcnfsd.h"
-
- #include "nfsd.h"
- #include "memory.h"
- #include "handle_list.h"
- #include "nfs_utils.h"
-
- #include <stdio.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
-
- #include <proto/exec.h>
- #include <proto/dos.h>
- #include <proto/socket.h>
- #include <proto/timer.h>
-
- extern BYTE *send_buffer, *recv_buffer; /* memory.c */
-
- int handlePacket(int32 *ptr, int32 *limit, struct sockaddr_in *from);
- int pcnfsd_procedure(struct Call *call, int32 *ptr, int32 *limit,
- int32 *rptr, int32 *rlimit);
-
- void service(int s)
- {
- struct sockaddr_in remote_sa;
- int l, addr_len;
- struct timeval timeout;
- struct timeval last_flushed;
- BOOL check_handles_pending = TRUE;
-
- fd_set fdset;
-
- GetSysTime(&last_flushed);
-
- while (TRUE) {
- FD_ZERO(&fdset);
- FD_SET(s, &fdset);
-
- if (check_handles_pending) {
- DEBUG(puts("Waiting for a request with a timeout"));
- timeout.tv_secs = FLUSH_HANDLES_EVERY;
- timeout.tv_micro = 0;
- l = WaitSelect(FD_SETSIZE, &fdset, NULL, NULL, &timeout, NULL);
- } else {
- DEBUG(puts("Waiting for a request without timeout"));
- l = WaitSelect(FD_SETSIZE, &fdset, NULL, NULL, NULL, NULL);
- }
-
- if (l < 0) {
- printSocketError("WaitSelect() failed");
- break;
- }
-
- if (l > 0) {
- addr_len = sizeof(remote_sa);
- l = recvfrom(s, (char *)recv_buffer, RECV_BUFFER_BYTES, 0, &remote_sa, &addr_len);
-
- if (l < 0) {
- printSocketError("recvfrom() failed");
- break;
- }
-
- DEBUG(printf("Packet received: %d bytes\n", l));
-
- /* Round it down */
- l -= (l % SINT32);
-
- if (addr_len == sizeof(remote_sa)) {
- int response_len =
- handlePacket((int32 *)recv_buffer, (int32 *)(recv_buffer + l), &remote_sa);
- if (response_len >= 0) {
- int res = sendto(s, (char *)send_buffer, response_len * SINT32, 0, &remote_sa, sizeof(remote_sa));
- DEBUG(printf("Response sent: %d bytes\n", res));
- if (res < 0) {
- printSocketError("Could not send");
- }
- }
-
- /* That may have had some effect on the handle list */
- check_handles_pending = TRUE;
- } else {
- printf("Unexpected address length - %d\n", addr_len);
- }
- }
-
- /* Keep a periodic check on wasted memory */
- struct timeval time_now;
- GetSysTime(&time_now);
- SubTime(&time_now, &last_flushed);
- if (time_now.tv_secs > FLUSH_HANDLES_EVERY) {
- if (verbose) {
- puts("Flushing unused NFS handles...");
- }
- check_handles_pending = flush_handles();
- GetSysTime(&last_flushed);
- }
- }
- }
-
- static int handlePacket(int32 *ptr, int32 *limit, struct sockaddr_in *from)
- {
- int32 id;
- int l;
-
- struct Call call;
-
- int32 *rptr = send_buffer;
- int32 *rlimit = rptr + (SEND_BUFFER_BYTES / SINT32);
-
- if ((limit - ptr) < 6)
- return -1;
-
- call.c_hasBeenPrinted = FALSE;
-
- // Assignment of structures
- call.c_from = *from;
-
- id = G_UINT(*ptr++);
-
- /* One could, in theory, keep track of IDs and the corresponding
- responses for swift retransmissions of repeated requests.
- This is not done here, as it would require a fairly complex
- cache and a fair bit of memory management, and would only benefit
- us if packets were getting regularly lost on the way to the client.
- */
-
- if (G_ENUM(*ptr++) != CALL) { // This is a call?
- // We should simply ignore this silently
- return -1;
- }
-
- if (G_UINT(*ptr++) != RPC_VERSION) {
- /* Requires 6 int32s */
- *rptr++ = P_UINT(id);
- *rptr++ = P_ENUM(REPLY);
- *rptr++ = P_ENUM(MSG_DENIED);
- *rptr++ = P_ENUM(RPC_MISMATCH);
- *rptr++ = P_UINT(RPC_VERSION);
- *rptr++ = P_UINT(RPC_VERSION);
-
- return 6;
- }
-
- call.c_program = G_UINT(*ptr++);
- call.c_version = G_UINT(*ptr++);
- call.c_procedure = G_UINT(*ptr++);
-
- // printf("Program: %d, Version: %d, Procedure: %d\n", call.c_program,
- // call.c_version, call.c_procedure);
-
- /* Authorisation */
- ptr = readAuth(ptr, limit, &call.c_auth);
- if (!ptr)
- return -1;
-
- if ((limit - ptr) < 2)
- return -1;
-
- /* We're not bothered about the verifier */
- *ptr++;
- l = G_UINT(*ptr++);
- ptr += INT32S(l);
- if (ptr >= limit) /* Check we've not overcommitted */
- return -1;
-
- /* Check what authentication we got */
- /* if (call.c_auth.isUnix) {
- printf(" Name: %s, UID: %u GID: %u (%u secondary)\n",
- call.c_auth.machineName, call.c_auth.uid,
- call.c_auth.gid, call.c_auth.numGids);
- } else {
- puts("Non-UNIX authentication!");
- */
- /* Ironically, we'd fail DES as 'too weak' */
- /* *rptr++ = P_UINT(id);
- *rptr++ = P_ENUM(REPLY);
- *rptr++ = P_ENUM(MSG_DENIED);
- *rptr++ = P_ENUM(AUTH_ERROR);
- *rptr = P_ENUM(AUTH_TOOWEAK);
- return 5;
- }
- */
- /* We've accepted the request */
- rptr = PrepareAcceptedHeader(id, rptr);
- // 5 int32s
-
- switch (call.c_program) {
- case NFS_PROGRAM:
- return nfs_procedure(&call, ptr, limit, rptr, rlimit);
-
- case MOUNT_PROGRAM:
- return mount_procedure(&call, ptr, limit, rptr, rlimit);
-
- case PCNFSD_PROGRAM:
- return pcnfsd_procedure(&call, ptr, limit, rptr, rlimit);
-
- default:
- *rptr = P_ENUM(PROG_UNAVAIL);
- return 6;
- }
- }
-
-