home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume21 / amd / part06 / rpc_fwd.c < prev   
Encoding:
C/C++ Source or Header  |  1990-04-10  |  8.7 KB  |  413 lines

  1. /*
  2.  * $Id: rpc_fwd.c,v 5.1 89/11/17 18:22:04 jsp Exp Locker: jsp $
  3.  *
  4.  * Copyright (c) 1989 Jan-Simon Pendry
  5.  * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
  6.  * Copyright (c) 1989 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * This code is derived from software contributed to Berkeley by
  10.  * Jan-Simon Pendry at Imperial College, London.
  11.  *
  12.  * Redistribution and use in source and binary forms are permitted
  13.  * provided that the above copyright notice and this paragraph are
  14.  * duplicated in all such forms and that any documentation,
  15.  * advertising materials, and other materials related to such
  16.  * distribution and use acknowledge that the software was developed
  17.  * by Imperial College of Science, Technology and Medicine, London, UK.
  18.  * The names of the College and University may not be used to endorse
  19.  * or promote products derived from this software without specific
  20.  * prior written permission.
  21.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  22.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  23.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  24.  *
  25.  *    %W% (Berkeley) %G%
  26.  */
  27.  
  28. /*
  29.  * RPC packet forwarding
  30.  */
  31.  
  32. #include "am.h"
  33. #include <sys/ioctl.h>
  34. #ifndef F_SETFL
  35. #include <fcntl.h>
  36. #endif
  37. #ifndef FNDELAY
  38. #include <sys/file.h>
  39. #endif
  40.  
  41. /*
  42.  * Note that the ID field in the external packet is only
  43.  * ever treated as a 32 bit opaque data object, so there
  44.  * is no need to convert to and from network byte ordering.
  45.  */
  46.  
  47. /*
  48.  * Each pending reply has an rpc_forward structure
  49.  * associated with it.  These have a 15 second lifespan.
  50.  * If a new structure is required, then an expired
  51.  * one will be re-allocated if available, otherwise a fresh
  52.  * one is allocated.  Whenever a reply is received the
  53.  * structure is discarded.
  54.  */
  55. typedef struct rpc_forward rpc_forward;
  56. struct rpc_forward {
  57.     qelem    rf_q;        /* Linked list */
  58.     time_t    rf_ttl;        /* Time to live */
  59.     u_int    rf_xid;        /* Packet id */
  60.     u_int    rf_oldid;    /* Original packet id */
  61.     fwd_fun    rf_fwd;        /* Forwarding function */
  62.     voidp    rf_ptr;
  63.     struct sockaddr_in rf_sin;
  64. };
  65.  
  66. /*
  67.  * Head of list of pending replies
  68.  */
  69. extern qelem rpc_head;
  70. qelem rpc_head = { &rpc_head, &rpc_head };
  71.  
  72. static u_int xid;
  73. #define    XID_ALLOC()    (xid++)
  74.  
  75. #define    MAX_PACKET_SIZE    8192    /* Maximum UDP packet size */
  76.  
  77. int fwd_sock;
  78.  
  79. /*
  80.  * Allocate a rely structure
  81.  */
  82. static rpc_forward *fwd_alloc()
  83. {
  84.     time_t now = clocktime();
  85.     rpc_forward *p = 0, *p2;
  86.  
  87. #ifdef DEBUG
  88.     /*dlog("fwd_alloca: rpc_head = %#x", rpc_head.q_forw);*/
  89. #endif
  90.     /*
  91.      * First search for an existing expired one.
  92.      */
  93.     ITER(p2, rpc_forward, &rpc_head) {
  94.         if (p2->rf_ttl <= now) {
  95.             p = p2;
  96.             break;
  97.         }
  98.     }
  99.  
  100.     /*
  101.      * If one couldn't be found then allocate
  102.      * a new structure and link it at the
  103.      * head of the list.
  104.      */
  105.     if (p) {
  106.         /*
  107.          * Call forwarding function to say that
  108.          * this message was junked.
  109.          */
  110. #ifdef DEBUG
  111.         dlog("Re-using packet forwarding slot - id %#x", p->rf_xid);
  112. #endif
  113.         if (p->rf_fwd)
  114.             (*p->rf_fwd)(0, 0, 0, &p->rf_sin, p->rf_ptr, FALSE);
  115.         rem_que(&p->rf_q);
  116.     } else {
  117.         p = ALLOC(rpc_forward);
  118.     }
  119.     ins_que(&p->rf_q, &rpc_head);
  120.  
  121.     /*
  122.      * Set the time to live field
  123.      * Timeout in 43 seconds 
  124.      */
  125.     p->rf_ttl = now + 43;
  126.  
  127. #ifdef DEBUG
  128.     /*dlog("fwd_alloca: rpc_head = %#x", rpc_head.q_forw);*/
  129. #endif
  130.     return p;
  131. }
  132.  
  133. /*
  134.  * Free an allocated reply structure.
  135.  * First unlink it from the list, then
  136.  * discard it.
  137.  */
  138. static void fwd_free(p)
  139. rpc_forward *p;
  140. {
  141. #ifdef DEBUG
  142.     /*dlog("fwd_free: rpc_head = %#x", rpc_head.q_forw);*/
  143. #endif
  144.     rem_que(&p->rf_q);
  145. #ifdef DEBUG
  146.     /*dlog("fwd_free: rpc_head = %#x", rpc_head.q_forw);*/
  147. #endif
  148.     free(p);
  149. }
  150.  
  151. /*
  152.  * Initialise the RPC forwarder
  153.  */
  154. int fwd_init()
  155. {
  156.     int on = 1;
  157.  
  158.     /*
  159.      * Create ping socket
  160.      */
  161.     fwd_sock = socket(AF_INET, SOCK_DGRAM, 0);
  162.     if (fwd_sock < 0) {
  163.         plog(XLOG_ERROR, "Unable to create RPC forwarding socket: %m");
  164.         return errno;
  165.     }
  166.  
  167.     /*
  168.      * Some things we talk to require a priv port - so make one here
  169.      */
  170.     if (bind_resv_port(fwd_sock, (unsigned short *) 0) < 0)
  171.         plog(XLOG_ERROR, "can't bind privileged port");
  172.  
  173.     if (fcntl(fwd_sock, F_SETFL, FNDELAY) < 0 &&
  174.             ioctl(fwd_sock, FIONBIO, &on) < 0) {
  175.         plog(XLOG_ERROR, "Can't set non-block on forwarding socket: %m");
  176.         return errno;
  177.     }
  178.  
  179.     return 0;
  180. }
  181.  
  182. /*
  183.  * Locate a packet in the forwarding list
  184.  */
  185. static rpc_forward *fwd_locate(id)
  186. u_int id;
  187. {
  188.     rpc_forward *p;
  189.  
  190.     ITER(p, rpc_forward, &rpc_head) {
  191.         if (p->rf_xid == id)
  192.             return p;
  193.     }
  194.  
  195.     return 0;
  196. }
  197.  
  198. /*
  199.  * This is called to forward a packet to another
  200.  * RPC server.  The message id is changed and noted
  201.  * so that when a reply appears we can tie it up
  202.  * correctly.  Just matching the reply's source address
  203.  * would not work because it might come from a
  204.  * different address.
  205.  */
  206. int fwd_packet(type_id, pkt, len, fwdto, replyto, i, cb)
  207. int type_id;
  208. voidp pkt;
  209. int len;
  210. struct sockaddr_in *fwdto, *replyto;
  211. voidp i;
  212. fwd_fun cb;
  213. {
  214.     rpc_forward *p;
  215.     u_int *pkt_int;
  216.     int error;
  217.  
  218.     if ((int)amd_state >= (int)Finishing)
  219.         return ENOENT;
  220.  
  221.     /*
  222.      * See if the type_id is fully specified.
  223.      * If so, then discard any old entries
  224.      * for this id.
  225.      * Otherwise make sure the type_id is
  226.      * fully qualified by allocating an id here.
  227.      */
  228. #ifdef DEBUG
  229.     switch (type_id & RPC_XID_MASK) {
  230.     case RPC_XID_PORTMAP: dlog("Sending PORTMAP request"); break;
  231.     case RPC_XID_MOUNTD: dlog("Sending MOUNTD request %#x", type_id); break;
  232.     case RPC_XID_NFSPING: dlog("Sending NFS ping"); break;
  233.     default: dlog("UNKNOWN RPC XID"); break;
  234.     }
  235. #endif
  236.  
  237.     if (type_id & ~RPC_XID_MASK) {
  238. #ifdef DEBUG
  239.         /*dlog("Fully qualified rpc type provided");*/
  240. #endif
  241.         p = fwd_locate(type_id);
  242.         if (p) {
  243. #ifdef DEBUG
  244.             dlog("Discarding earlier rpc fwd handle");
  245. #endif
  246.             fwd_free(p);
  247.         }
  248.     } else {
  249. #ifdef DEBUG
  250.         dlog("Allocating a new xid...");
  251. #endif
  252.         type_id = MK_RPC_XID(type_id, XID_ALLOC());
  253.     }
  254.  
  255.     p = fwd_alloc();
  256.     if (!p)
  257.         return ENOBUFS;
  258.  
  259.     error = 0;
  260.  
  261.     pkt_int = (u_int *) pkt;
  262.  
  263.     /*
  264.      * Get the original packet id
  265.      */
  266.     p->rf_oldid = *pkt_int;
  267.  
  268.     /*
  269.      * Replace with newly allocated id
  270.      */
  271.     p->rf_xid = *pkt_int = type_id;
  272.  
  273.     /*
  274.      * The sendto may fail if, for example, the route
  275.      * to a remote host is lost because an intermediate
  276.      * gateway has gone down.  Important to fill in the
  277.      * rest of "p" otherwise nasty things happen later...
  278.      */
  279. #ifdef DEBUG
  280.     dlog("Sending packet id %#x to %#08x.%04x", p->rf_xid, ntohl(fwdto->sin_addr.s_addr), ntohs(fwdto->sin_port));
  281. #endif
  282.     if (sendto(fwd_sock, (char *) pkt, len, 0,
  283.             (struct sockaddr *) fwdto, sizeof(*fwdto)) < 0)
  284.         error = errno;
  285.  
  286.     /*
  287.      * Save callback function and return address
  288.      */
  289.     p->rf_fwd = cb;
  290.     if (replyto)
  291.         p->rf_sin = *replyto;
  292.     else
  293.         bzero((voidp) &p->rf_sin, sizeof(p->rf_sin));
  294.     p->rf_ptr = i;
  295.  
  296.     return error;
  297. }
  298.  
  299. /*
  300.  * Called when some data arrives on the forwarding socket
  301.  */
  302. void fwd_reply()
  303. {
  304.     int len;
  305. #ifdef DYNAMIC_BUFFERS
  306.     voidp pkt;
  307. #else
  308.     u_int pkt[MAX_PACKET_SIZE/sizeof(u_int)+1];
  309. #endif
  310.     u_int *pkt_int;
  311.     int rc;
  312.     rpc_forward *p;
  313.     struct sockaddr_in src_addr;
  314.     int src_addr_len;
  315.  
  316.     /*
  317.      * Determine the length of the packet
  318.      */
  319. #ifdef DYNAMIC_BUFFERS
  320.     if (ioctl(fwd_sock, FIONREAD, &len) < 0) {
  321.         plog(XLOG_ERROR, "Error reading packet size: %m");
  322.         return;
  323.     }
  324.  
  325.     /*
  326.      * Allocate a buffer
  327.      */
  328.     pkt = (voidp) malloc((unsigned) len);
  329.     if (!pkt) {
  330.         plog(XLOG_ERROR, "Out of buffers in fwd_reply");
  331.         return;
  332.     }
  333. #else
  334.     len = MAX_PACKET_SIZE;
  335. #endif
  336.  
  337.     /*
  338.      * Read the packet and check for validity
  339.      */
  340. again:
  341.     src_addr_len = sizeof(src_addr);
  342.     rc = recvfrom(fwd_sock, (char *) pkt, len, 0,
  343.             (struct sockaddr *) &src_addr, &src_addr_len);
  344.     if (rc < 0 || src_addr_len != sizeof(src_addr) ||
  345.             src_addr.sin_family != AF_INET) {
  346.         if (rc < 0 && errno == EINTR)
  347.             goto again;
  348.         plog(XLOG_ERROR, "Error reading RPC reply: %m");
  349.         goto out;
  350.     }
  351.  
  352. #ifdef DYNAMIC_BUFFERS
  353.     if (rc != len) {
  354.         plog(XLOG_ERROR, "Short read in fwd_reply");
  355.         goto out;
  356.     }
  357. #endif
  358.  
  359.     /*
  360.      * Do no more work if finishing soon
  361.      */
  362.     if ((int)amd_state >= (int)Finishing)
  363.         goto out;
  364.  
  365.     /*
  366.      * Find packet reference
  367.      */
  368.     pkt_int = (u_int *) pkt;
  369.  
  370. #ifdef DEBUG
  371.     switch (*pkt_int & RPC_XID_MASK) {
  372.     case RPC_XID_PORTMAP: dlog("Receiving PORTMAP reply"); break;
  373.     case RPC_XID_MOUNTD: dlog("Receiving MOUNTD reply %#x", *pkt_int); break;
  374.     case RPC_XID_NFSPING: dlog("Receiving NFS ping %#x", *pkt_int); break;
  375.     default: dlog("UNKNOWN RPC XID"); break;
  376.     }
  377. #endif
  378.  
  379.     p = fwd_locate(*pkt_int);
  380.     if (!p) {
  381. #ifdef DEBUG
  382.         dlog("Can't forward reply id %#x", *pkt_int);
  383. #endif
  384.         goto out;
  385.     }
  386.  
  387.     if (p->rf_fwd) {
  388.         /*
  389.          * Put the original message id back
  390.          * into the packet.
  391.          */
  392.         *pkt_int = p->rf_oldid;
  393.  
  394.         /*
  395.          * Call forwarding function
  396.          */
  397.         (*p->rf_fwd)(pkt, rc, &src_addr, &p->rf_sin, p->rf_ptr, TRUE);
  398.     }
  399.  
  400.     /*
  401.      * Free forwarding info
  402.      */
  403.     fwd_free(p);
  404.  
  405. out:;
  406. #ifdef DYNAMIC_BUFFERS
  407.     /*
  408.      * Free the packet
  409.      */
  410.     free(pkt);
  411. #endif
  412. }
  413.