home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 13 / MA_Cover_13.bin / source / c / nfsd / src / rpc_register.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-11-24  |  4.5 KB  |  173 lines

  1. /*  Register (and deregister) RPC services
  2.  
  3.     ©1999 Joseph Walton
  4.  
  5.     This software is distributed under the terms of the GNU General Public
  6.     License; either version 2 of the License, or (at your option) any
  7.     later version.
  8. */
  9.  
  10. #include "rpc.h"
  11. #include "rpc_register.h"
  12.  
  13. #include "nfs_utils.h"
  14.  
  15. #include <stdio.h>
  16. #include <sys/socket.h>
  17. #include <netinet/in.h>
  18. #include <sys/time.h>
  19.  
  20. #include <bsdsocket/socketbasetags.h>
  21.  
  22. #include <proto/exec.h>
  23. #include <proto/timer.h>
  24. #include <proto/socket.h>
  25.  
  26. static int32 make_xid(void)
  27. {
  28.     struct timeval now;
  29.  
  30.     GetSysTime(&now);
  31.     return (now.tv_secs ^ now.tv_micro ^ (ULONG)FindTask(NULL));
  32. }
  33.  
  34. static int32 mem[14];
  35. static char buffer[1024];
  36.  
  37. /* This is called very rarely - psychotic optimisations would be
  38.     self-defeating */
  39. static BOOL pmap_action(int socket, int action, int prog, int version, int port)
  40. {
  41.     int l, addr_len, id;
  42.  
  43.     struct timeval try_until, resend_at;
  44.  
  45.     int32 *ptr;
  46.  
  47.     struct sockaddr_in addr;
  48.  
  49.     id = make_xid();
  50.     ptr = mem;
  51.     *ptr++ = P_UINT(id);
  52.     *ptr++ = P_ENUM(CALL);
  53.     *ptr++ = P_UINT(RPC_VERSION);
  54.     *ptr++ = P_UINT(PMAP_PROGRAM);
  55.     *ptr++ = P_UINT(PMAP_VERSION);
  56.     *ptr++ = P_UINT(action);
  57.  
  58.     *ptr++ = P_ENUM(AUTH_NONE);
  59.     *ptr++ = P_UINT(0);
  60.     *ptr++ = P_ENUM(AUTH_NONE);
  61.     *ptr++ = P_UINT(0);
  62.  
  63.     *ptr++ = P_UINT(prog);
  64.     *ptr++ = P_UINT(version);
  65.     *ptr++ = P_UINT(IPPROTO_UDP);
  66.     *ptr++ = P_UINT(port);
  67.  
  68.     // 14 int32s
  69.  
  70.     GetSysTime(&try_until);
  71.     resend_at = try_until;
  72.     try_until.tv_secs += RPC_REGISTER_TIMEOUT_AFTER;
  73.  
  74.     while (TRUE) {
  75.         struct timeval now, timeout;
  76.         fd_set fdset;
  77.         int r;
  78.  
  79.         GetSysTime(&now);
  80.  
  81.         /* There is a wait so long? */
  82.         if (CmpTime(&now, &try_until) <= 0) {
  83.             puts("Portmap operation attempt timed out");
  84.             return FALSE;
  85.         }
  86.  
  87.         /* Should we resend? */
  88.         if (CmpTime(&now, &resend_at) <= 0) {
  89.             int length = 14 * sizeof(int32);
  90.             addr.sin_family = AF_INET;
  91.             addr.sin_port = htons(PMAP_PORT);
  92.             addr.sin_addr.s_addr = LOCAL_ADDR;
  93.  
  94.             l = sendto(socket, (char *)mem, length, 0, &addr, sizeof(addr));
  95.             if (l != length) {
  96.                 printSocketError("Could not send to localhost");
  97.                 return FALSE;
  98.             }
  99.             resend_at.tv_sec += RPC_REGISTER_SEND_EVERY;
  100.         }
  101.  
  102.         /* Want to wait for a valid response - what's the next scheduled
  103.             checkpoint? */
  104.         if (CmpTime(&resend_at, &try_until) < 0) {
  105.             timeout = try_until;
  106.         } else {
  107.             timeout = resend_at;
  108.         }
  109.         SubTime(&timeout, &now);
  110.  
  111.         FD_ZERO(&fdset);
  112.         FD_SET(socket, &fdset);
  113.  
  114.         r = WaitSelect(FD_SETSIZE, &fdset, NULL, NULL, &timeout, NULL);
  115.  
  116.         if (r > 0) {
  117.             addr_len = sizeof(addr);
  118.             l = recvfrom(socket, buffer, sizeof(buffer), 0, &addr, &addr_len);
  119.             if (l < 0) {
  120.                 printSocketError("recvfrom() failed");
  121.                 return FALSE;
  122.             }
  123.  
  124.             /* Make sure it's from 127.0.0.1 - that's where we sent to */
  125.             if ((addr_len < sizeof(addr)) || (addr.sin_addr.s_addr != LOCAL_ADDR))
  126.                 continue;
  127.  
  128.             l /= sizeof(int32);
  129.             if (l > 5) {
  130.                 int32 *ptr = (int32 *)buffer;
  131.                 int32 *limit = ptr + l;
  132.  
  133.                 if ((id != G_INT(*ptr++)) || (G_INT(*ptr++) != REPLY))
  134.                     continue;
  135.  
  136.                 if (G_INT(*ptr++) != MSG_ACCEPTED) {
  137.                     puts("Portmapper did not accept our registration message");
  138.                     return FALSE;
  139.                 }
  140.  
  141.                 if (G_INT(*ptr++) != SUCCESS) {
  142.                     puts("Portmapper registration failed remotely");
  143.                     return FALSE;
  144.                 }
  145.  
  146.                 /* We don't care about authorisation */
  147.                 ptr++;
  148.                 ptr += INT32S(G_UINT(*ptr)) + 1;
  149.  
  150.                 if (ptr < limit) {
  151.                     /* This is the actual return code from the remote call */
  152.                     return (1 == G_INT(*ptr));
  153.                 }
  154.             }
  155.         } else if (r < 0) {
  156.             printSocketError("select() failed");
  157.             return FALSE;
  158.         }
  159.     }
  160. }
  161.  
  162. /* Simple user-visible wrappers */
  163. BOOL pmap_set(int socket, int prog, int version, int port)
  164. {
  165.     return pmap_action(socket, PMAPPROC_SET, prog, version, port);
  166. }
  167.  
  168. BOOL pmap_unset(int socket, int prog, int version)
  169. {
  170.     return pmap_action(socket, PMAPPROC_UNSET, prog, version, 0);
  171. }
  172.  
  173.