Home | History | Annotate | Download | only in librpc
      1 /* Parts of this file are derived from the original Sun (ONC) RPC
      2  * code, under the following copyright:
      3  */
      4 /*
      5  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
      6  * unrestricted use provided that this legend is included on all tape
      7  * media and as a part of the software program in whole or part.  Users
      8  * may copy or modify Sun RPC without charge, but are not authorized
      9  * to license or distribute it to anyone else except as part of a product or
     10  * program developed by the user.
     11  *
     12  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
     13  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
     14  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
     15  *
     16  * Sun RPC is provided with no support and without any obligation on the
     17  * part of Sun Microsystems, Inc. to assist in its use, correction,
     18  * modification or enhancement.
     19  *
     20  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
     21  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
     22  * OR ANY PART THEREOF.
     23  *
     24  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
     25  * or profits or other special, indirect and consequential damages, even if
     26  * Sun has been advised of the possibility of such damages.
     27  *
     28  * Sun Microsystems, Inc.
     29  * 2550 Garcia Avenue
     30  * Mountain View, California  94043
     31  */
     32 /*
     33  * svc.c, Server-side remote procedure call interface.
     34  *
     35  * There are two sets of procedures here.  The xprt routines are
     36  * for handling transport handles.  The svc routines handle the
     37  * list of service routines.
     38  *
     39  * Copyright (C) 1984, Sun Microsystems, Inc.
     40  */
     41 
     42 #include <rpc/rpc.h>
     43 #include <sys/select.h>
     44 #include <sys/types.h>
     45 #include <unistd.h>
     46 #include <arpa/inet.h>
     47 #include <rpc/rpc_router_ioctl.h>
     48 #include <debug.h>
     49 #include <pthread.h>
     50 
     51 extern XDR *xdr_init_common(const char *name, int is_client);
     52 extern void xdr_destroy_common(XDR *xdr);
     53 extern int r_control(int handle, const uint32 cmd, void *arg);
     54 extern void grabPartialWakeLock();
     55 extern void releaseWakeLock();
     56 
     57 #include <stdio.h>
     58 #include <errno.h>
     59 #include <string.h>
     60 
     61 typedef struct registered_server_struct {
     62     /* MUST BE AT OFFSET ZERO!  The client code assumes this when it overwrites
     63        the XDR for server entries which represent a callback client.  Those
     64        server entries do not have their own XDRs.
     65     */
     66     XDR *xdr;
     67     /* Because the xdr is NULL for callback clients (as opposed to true
     68        servers), we keep track of the program number and version number in this
     69        structure as well.
     70     */
     71     rpcprog_t x_prog; /* program number */
     72     rpcvers_t x_vers; /* program version */
     73 
     74     int active;
     75     struct registered_server_struct *next;
     76     SVCXPRT *xprt;
     77     __dispatch_fn_t dispatch;
     78 } registered_server;
     79 
     80 struct SVCXPRT {
     81     fd_set fdset;
     82     int max_fd;
     83     pthread_attr_t thread_attr;
     84     pthread_t  svc_thread;
     85     pthread_mutexattr_t lock_attr;
     86     pthread_mutex_t lock;
     87     registered_server *servers;
     88     volatile int num_servers;
     89 };
     90 
     91 static pthread_mutex_t xprt_lock = PTHREAD_MUTEX_INITIALIZER;
     92 int xprt_refcount;
     93 SVCXPRT *the_xprt; /* FIXME: have a list or something */
     94 
     95 /*
     96   This routine is only of interest if a service implementor does not
     97   call svc_run(), but instead implements custom asynchronous event
     98   processing.  It is called when the select() system call has
     99   determined that an RPC request has arrived on some RPC socket(s);
    100   rdfds is the resultant read file descriptor bit mask.  The routine
    101   returns when all sockets associated with the value of rdfds have
    102   been serviced.
    103  */
    104 
    105 void svc_dispatch(registered_server *svc, SVCXPRT *xprt);
    106 
    107 static void* svc_context(void *__u)
    108 {
    109     SVCXPRT *xprt = (SVCXPRT *)__u;
    110     int n;
    111     struct timeval tv;
    112     volatile fd_set rfds;
    113     while(xprt->num_servers) {
    114         rfds = xprt->fdset;
    115         tv.tv_sec = 1; tv.tv_usec = 0;
    116         n = select(xprt->max_fd + 1, (fd_set *)&rfds, NULL, NULL, &tv);
    117         if (n < 0) {
    118             E("select() error %s (%d)\n", strerror(errno), errno);
    119             continue;
    120         }
    121         if (n) {
    122             grabPartialWakeLock();
    123             for (n = 0; n <= xprt->max_fd; n++) {
    124                 if (FD_ISSET(n, &rfds)) {
    125                     /* the file descriptor points to the service instance; we
    126                        simply look that service by its file descriptor, and
    127                        call its service function. */
    128                     registered_server *trav = xprt->servers;
    129                     for (; trav; trav = trav->next)
    130                         if (trav->xdr->fd == n) {
    131                             /* read the entire RPC */
    132                             trav->xdr->xops->read(trav->xdr);
    133                             svc_dispatch(trav, xprt);
    134                             break;
    135                         }
    136                 } /* if fd is set */
    137             } /* for each fd */
    138             releaseWakeLock();
    139         }
    140     }
    141     D("RPC-server thread exiting!\n");
    142     return NULL;
    143 }
    144 
    145 SVCXPRT *svcrtr_create (void)
    146 {
    147     SVCXPRT *xprt;
    148     pthread_mutex_lock(&xprt_lock);
    149     if (the_xprt) {
    150         D("The RPC transport has already been created.\n");
    151         xprt = the_xprt;
    152     } else {
    153         xprt = calloc(1, sizeof(SVCXPRT));
    154         if (xprt) {
    155             FD_ZERO(&xprt->fdset);
    156             xprt->max_fd = 0;
    157             pthread_attr_init(&xprt->thread_attr);
    158             pthread_attr_setdetachstate(&xprt->thread_attr,
    159                                         PTHREAD_CREATE_DETACHED);
    160             pthread_mutexattr_init(&xprt->lock_attr);
    161 //          pthread_mutexattr_settype(&xprt->lock_attr,
    162 //                                    PTHREAD_MUTEX_RECURSIVE);
    163             pthread_mutex_init(&xprt->lock, &xprt->lock_attr);
    164         }
    165     }
    166     pthread_mutex_unlock(&xprt_lock);
    167     return xprt;
    168 }
    169 
    170 void svc_destroy(SVCXPRT *xprt)
    171 {
    172     /* the last call to xprt_unregister() does the job */
    173 }
    174 
    175 /* NOTE: this function must always be called with the xprt->lock held! */
    176 static registered_server* svc_find_nosync(SVCXPRT *xprt,
    177                                           rpcprog_t prog, rpcvers_t vers,
    178                                           registered_server **prev)
    179 {
    180     registered_server *trav;
    181     trav = xprt->servers;
    182     if (prev) *prev = NULL;
    183     for (; trav; trav = trav->next) {
    184         if (trav->x_prog == prog && trav->x_vers == vers)
    185             break;
    186         if (prev) *prev = trav;
    187     }
    188     return trav;
    189 }
    190 
    191 registered_server* svc_find(SVCXPRT *xprt,
    192                             rpcprog_t prog, rpcvers_t vers)
    193 {
    194     pthread_mutex_lock(&xprt->lock);
    195     registered_server *svc = svc_find_nosync(xprt, prog, vers, NULL);
    196     pthread_mutex_unlock(&xprt->lock);
    197     return svc;
    198 }
    199 
    200 bool_t svc_register (SVCXPRT *xprt, rpcprog_t prog, rpcvers_t vers,
    201                      __dispatch_fn_t dispatch,
    202                      rpcprot_t protocol)
    203 {
    204     struct rpcrouter_ioctl_server_args args;
    205     registered_server* svc;
    206 
    207     pthread_mutex_lock(&xprt->lock);
    208 
    209     D("registering for service %08x:%d\n", (uint32_t)prog, (int)vers);
    210 
    211     svc = svc_find_nosync(xprt, prog, vers, NULL);
    212 
    213     if (svc) {
    214         E("service is already registered!\n");
    215         pthread_mutex_unlock(&xprt->lock);
    216         return svc->dispatch == dispatch;
    217     }
    218 
    219     svc = malloc(sizeof(registered_server));
    220 
    221     /* If the program number of the RPC server ANDs with 0x01000000, then it is
    222        not a true RPC server, but a callback client for an existing RPC client.
    223        For example, if you have an RPC client with the program number
    224        0x30000000, then its callback client will have a program number
    225        0x31000000.  RPC calls on program number 0x31000000 will arrive on the
    226        RPC client 0x30000000.
    227     */
    228 
    229     if (prog & 0x01000000) {
    230         D("RPC server %08x:%d is a callback client, "
    231           "creating dummy service entry!\n", (uint32_t)prog, (int)vers);
    232         svc->xdr = NULL;
    233         svc->x_prog = prog;
    234         svc->x_vers = vers;
    235     } else {
    236         V("RPC server %08x:%d is a real server.\n", (uint32_t)prog, (int)vers);
    237         svc->xdr = xdr_init_common("/dev/oncrpc/00000000:0",
    238                                    0 /* not a client XDR */);
    239         if (svc->xdr == NULL) {
    240             E("failed to initialize service (permissions?)!\n");
    241             free(svc);
    242             pthread_mutex_unlock(&xprt->lock);
    243             return FALSE;
    244         }
    245 
    246         args.prog = prog;
    247         args.vers = vers;
    248         V("RPC server %08x:%d: registering with kernel.\n",
    249           (uint32_t)prog, (int)vers);
    250         if (r_control(svc->xdr->fd,
    251                       RPC_ROUTER_IOCTL_REGISTER_SERVER,
    252                       &args) < 0) {
    253             E("ioctl(RPC_ROUTER_IOCTL_REGISTER_SERVER) failed: %s!\n",
    254               strerror(errno));
    255             xdr_destroy_common(svc->xdr);
    256             free(svc);
    257             pthread_mutex_unlock(&xprt->lock);
    258             return FALSE;
    259         }
    260 
    261         FD_SET(svc->xdr->fd, &xprt->fdset);
    262         if (svc->xdr->fd > xprt->max_fd) xprt->max_fd = svc->xdr->fd;
    263         svc->x_prog = svc->xdr->x_prog = prog;
    264         svc->x_vers = svc->xdr->x_vers = vers;
    265     }
    266 
    267     svc->dispatch = dispatch;
    268     svc->next = xprt->servers;
    269     xprt->servers = svc;
    270     xprt->num_servers++;
    271     V("RPC server %08x:%d: after registering, there are %d servers.\n",
    272       (uint32_t)prog, (int)vers, xprt->num_servers);
    273     svc->xprt = xprt;
    274     if (xprt->num_servers == 1) {
    275         D("creating RPC-server thread (detached)!\n");
    276         pthread_create(&xprt->svc_thread,
    277                        &xprt->thread_attr,
    278                        svc_context, xprt);
    279     }
    280     pthread_mutex_unlock(&xprt->lock);
    281     return TRUE;
    282 }
    283 
    284 void svc_unregister (SVCXPRT *xprt, rpcprog_t prog, rpcvers_t vers) {
    285     registered_server *prev, *found;
    286     pthread_mutex_lock(&xprt->lock);
    287     found = svc_find_nosync(xprt, prog, vers, &prev);
    288     D("unregistering RPC server %08x:%d\n", (unsigned)prog, (unsigned)vers);
    289     if (found) {
    290         struct rpcrouter_ioctl_server_args args;
    291         if (prev) {
    292             V("RPC server %08x:%d is not the first in the list\n",
    293               (unsigned)prog, (unsigned)vers);
    294             prev->next = found->next;
    295         } else {
    296             V("RPC server %08x:%d the first in the list\n",
    297               (unsigned)prog, (unsigned)vers);
    298             xprt->servers = found->next;
    299         }
    300 
    301         /* Is is an RPC server or a callback client? */
    302         if (found->xdr) {
    303             if (!(prog & 0x01000000)) {
    304                 V("RPC server %08x:%d is not a callback server.\n",
    305                   (unsigned)prog, (unsigned)vers);
    306                 /* don't bother decreasing the xprt->max_fd to the previous
    307                  * minimum.
    308                  */
    309                 args.prog = prog;
    310                 args.vers = vers;
    311                 if (r_control(found->xdr->fd,
    312                               RPC_ROUTER_IOCTL_UNREGISTER_SERVER,
    313                               &args) < 0) {
    314                     E("ioctl(RPC_ROUTER_IOCTL_UNREGISTER_SERVER) "
    315                       "failed: %s!\n",
    316                       strerror(errno));
    317                 }
    318                 FD_CLR(found->xdr->fd, &xprt->fdset);
    319             }
    320             V("RPC server %08x:%d: destroying XDR\n",
    321                    (unsigned)prog, (unsigned)vers);
    322             xdr_destroy_common(found->xdr);
    323         }
    324         else V("RPC server %08x:%d does not have an associated XDR\n",
    325                (unsigned)prog, (unsigned)vers);
    326 
    327         free(found);
    328         /* When this goes to zero, the RPC-server thread will exit.  We do not
    329          * need to wait for the thread to exit, because it is detached.
    330          */
    331         xprt->num_servers--;
    332         V("RPC server %08x:%d: after unregistering, %d servers left.\n",
    333           (unsigned)prog, (unsigned)vers, xprt->num_servers);
    334     }
    335     pthread_mutex_unlock(&xprt->lock);
    336 }
    337 
    338 /*
    339 RPC_OFFSET +
    340 0  00000000 RPC xid                 network-byte order
    341 1  00000000 RPC call
    342 2  00000002 rpc version
    343 3  3000005d prog num
    344 4  00000000 prog vers
    345 5  00000001 proc num
    346 
    347 6  00000000 cred
    348 7  00000000 cred
    349 8  00000000 verf
    350 9  00000000 verf
    351 
    352 a  0001fcc1 parms...
    353 b  00354230
    354 c  00000000
    355  */
    356 
    357 void svc_dispatch(registered_server *svc, SVCXPRT *xprt)
    358 {
    359     struct svc_req req;
    360 
    361     /* Read enough of the packet to be able to find the program number, the
    362        program-version number, and the procedure call.  Notice that anything
    363        arriving on this channel must be an RPC call.  Also, the program and
    364        program-version numbers must match what's in the XDR of the service. */
    365 
    366     D("reading on fd %d for %08x:%d\n",
    367       svc->xdr->fd, svc->x_prog, svc->x_vers);
    368 
    369     uint32 prog = ntohl(((uint32 *)(svc->xdr->in_msg))[RPC_OFFSET+3]);
    370     uint32 vers = ntohl(((uint32 *)(svc->xdr->in_msg))[RPC_OFFSET+4]);
    371     uint32 proc = ntohl(((uint32 *)(svc->xdr->in_msg))[RPC_OFFSET+5]);
    372 
    373     if (ntohl(((uint32 *)svc->xdr->in_msg)[RPC_OFFSET+1]) != RPC_MSG_CALL) {
    374         E("ERROR: expecting an RPC call on server channel!\n");
    375         return;
    376     }
    377 
    378     if (prog != svc->x_prog) {
    379         E("ERROR: prog num %08x does not match expected %08x!\n",
    380           (unsigned)prog, (unsigned)svc->x_prog);
    381         return;
    382     }
    383 
    384     if (vers != svc->xdr->x_vers) {
    385         E("ERROR: prog vers %08x does not match expected %08x!\n",
    386                 vers, svc->xdr->x_vers);
    387         return;
    388     }
    389 
    390     req.rq_prog = prog;
    391     req.rq_vers = vers;
    392     req.rq_proc = proc;
    393     req.rq_xprt = xprt;
    394 
    395     D("START: SVC DISPATCH %08x:%08x --> %08x\n",
    396       (uint32_t)prog, (int)vers, proc);
    397     /* The RPC header (XID, call type, RPC version, program number, program
    398        version, proc number) is 6 long words; the default credentials are 4
    399        long words.  This the offset (RPC_OFFSET + 10)<<2 is where the first
    400        arguments start.
    401     */
    402     svc->xdr->in_next = (RPC_OFFSET + 6 + 4)*sizeof(uint32);
    403 
    404     svc->active = getpid();
    405     svc->xdr->x_op = XDR_DECODE;
    406     svc->dispatch(&req, (SVCXPRT *)svc);
    407     svc->active = 0;
    408     D("DONE: SVC DISPATCH %08x:%08x --> %08x\n",
    409       (uint32_t)prog, (int)vers, proc);
    410 }
    411 
    412 void xprt_register(SVCXPRT *xprt)
    413 {
    414     pthread_mutex_lock(&xprt_lock);
    415     if (!the_xprt || (xprt && (xprt == the_xprt))) {
    416         xprt_refcount++;
    417         the_xprt = xprt;
    418         D("registering RPC transport (refcount %d)\n", xprt_refcount);
    419     }
    420     else E("a different RPC transport has already been registered!\n");
    421     pthread_mutex_unlock(&xprt_lock);
    422 }
    423 
    424 void xprt_unregister (SVCXPRT *xprt)
    425 {
    426     pthread_mutex_lock(&xprt_lock);
    427     if (xprt && xprt == the_xprt) {
    428         if (xprt_refcount == 1) {
    429             xprt_refcount = 0;
    430             D("Destroying RPC transport (servers %d)\n",
    431               the_xprt->num_servers);
    432 
    433             pthread_attr_destroy(&xprt->thread_attr);
    434             pthread_mutexattr_destroy(&xprt->lock_attr);
    435             pthread_mutex_destroy(&xprt->lock);
    436             /* Make sure the thread has existed before we free the xprt
    437                structure.  The thread is created as detached, so we do not wait
    438                for it after we set the terminate flag in svc_unregister, but we
    439                do have to wait for it to exit when we call svc_destroy.
    440             */
    441             pthread_join(xprt->svc_thread, NULL);
    442             free(xprt);
    443             the_xprt = NULL;
    444         }
    445         else xprt_refcount--;
    446         D("unregistering RPC transport (refcount %d)\n", xprt_refcount);
    447     }
    448     else E("no RPC transport has been registered!\n");
    449     pthread_mutex_unlock(&xprt_lock);
    450 }
    451 
    452 /* The functions that follow all take a pointer to the SVCXPRT instead of the
    453    XDR of the server that they refer to.  The xprt pointer is actually a
    454    pointer to a registered_server, which identified the RPC server in
    455    question.
    456 */
    457 
    458 bool_t svc_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
    459 {
    460     registered_server *serv = (registered_server *)xprt;
    461     if (serv->active) {
    462         bool_t result = (bool_t) (*xdr_args)(serv->xdr, args_ptr);
    463         XDR_MSG_DONE (serv->xdr);
    464         return result;
    465     }
    466     return FALSE;
    467 } /* svc_getargs */
    468 
    469 bool_t svc_freeargs (SVCXPRT * xprt, xdrproc_t xdr_args, caddr_t args_ptr)
    470 {
    471     registered_server *serv = (registered_server *)xprt;
    472     if (serv->active) {
    473         serv->xdr->x_op = XDR_FREE;
    474         return (*xdr_args)((XDR *)serv->xdr, args_ptr);
    475     }
    476     return FALSE;
    477 }
    478 
    479 /* Send a reply to an rpc request */
    480 bool_t
    481 svc_sendreply (SVCXPRT *xprt, xdrproc_t xdr_results,
    482                caddr_t xdr_location)
    483 {
    484     registered_server *serv = (registered_server *)xprt;
    485     if (serv->active) {
    486         opaque_auth verf;
    487         verf.oa_flavor = AUTH_NONE;
    488         verf.oa_length = 0;
    489 
    490         serv->xdr->x_op = XDR_ENCODE;
    491 
    492         if (!xdr_reply_msg_start(serv->xdr, &verf) ||
    493             !xdr_results(serv->xdr, xdr_location))
    494             return FALSE;
    495 
    496         ((uint32 *)(serv->xdr->out_msg))[RPC_OFFSET] =
    497             ((uint32 *)(serv->xdr->in_msg))[RPC_OFFSET]; //RPC xid
    498         D("%08x:%d sending RPC reply (XID %d)\n",
    499           serv->xdr->x_prog,
    500           serv->xdr->x_vers,
    501           ntohl(((uint32 *)(serv->xdr->out_msg))[RPC_OFFSET]));
    502         XDR_MSG_SEND(serv->xdr);
    503         return TRUE;
    504     }
    505     return FALSE;
    506 }
    507 
    508 /* Service error functions. */
    509 
    510 #define SVCERR_XDR_SEND(xdr, reply) \
    511   ( XDR_MSG_START(xdr, RPC_MSG_REPLY) && \
    512     xdr_send_reply_header(xdr, &reply) && \
    513     XDR_MSG_SEND(xdr) )
    514 
    515 void svcerr_decode (SVCXPRT *xprt)
    516 {
    517     registered_server *serv = (registered_server *)xprt;
    518     if (serv->active) {
    519         rpc_reply_header reply;
    520         reply.stat = RPC_MSG_ACCEPTED;
    521         reply.u.ar.verf = serv->xdr->verf;
    522         reply.u.ar.stat = RPC_GARBAGE_ARGS;
    523 
    524         if (!SVCERR_XDR_SEND(serv->xdr, reply))
    525             /* Couldn't send the reply - just give up */
    526             XDR_MSG_ABORT(serv->xdr);
    527     }
    528 } /* svcerr_decode */
    529 
    530 void svcerr_systemerr (SVCXPRT *xprt)
    531 {
    532     registered_server *serv = (registered_server *)xprt;
    533     if (serv->active) {
    534         rpc_reply_header reply;
    535         reply.stat = RPC_MSG_ACCEPTED;
    536         reply.u.ar.verf = serv->xdr->verf;
    537         reply.u.ar.stat = RPC_SYSTEM_ERR;
    538 
    539         if (!SVCERR_XDR_SEND(serv->xdr, reply))
    540             /* Couldn't send the reply - just give up */
    541             XDR_MSG_ABORT(serv->xdr);
    542     }
    543 } /* svcerr_systemerr */
    544 
    545 void svcerr_noproc(SVCXPRT *xprt)
    546 {
    547     registered_server *serv = (registered_server *)xprt;
    548     if (serv->active) {
    549         rpc_reply_header reply;
    550         reply.stat = RPC_MSG_ACCEPTED;
    551         reply.u.ar.verf = serv->xdr->verf;
    552         reply.u.ar.stat = RPC_PROC_UNAVAIL;
    553 
    554         if (!SVCERR_XDR_SEND(serv->xdr, reply))
    555             /* Couldn't send the reply - just give up */
    556             XDR_MSG_ABORT(serv->xdr);
    557     }
    558 } /* svcerr_noproc */
    559