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