• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
svc_context(void * __u)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 
svcrtr_create(void)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 
svc_destroy(SVCXPRT * xprt)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! */
svc_find_nosync(SVCXPRT * xprt,rpcprog_t prog,rpcvers_t vers,registered_server ** prev)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 
svc_find(SVCXPRT * xprt,rpcprog_t prog,rpcvers_t vers)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 
svc_register(SVCXPRT * xprt,rpcprog_t prog,rpcvers_t vers,__dispatch_fn_t dispatch,rpcprot_t protocol)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 
svc_unregister(SVCXPRT * xprt,rpcprog_t prog,rpcvers_t vers)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 
svc_dispatch(registered_server * svc,SVCXPRT * xprt)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 
xprt_register(SVCXPRT * xprt)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 
xprt_unregister(SVCXPRT * xprt)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 
svc_getargs(SVCXPRT * xprt,xdrproc_t xdr_args,caddr_t args_ptr)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 
svc_freeargs(SVCXPRT * xprt,xdrproc_t xdr_args,caddr_t args_ptr)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
svc_sendreply(SVCXPRT * xprt,xdrproc_t xdr_results,caddr_t xdr_location)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 
svcerr_decode(SVCXPRT * xprt)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 
svcerr_systemerr(SVCXPRT * xprt)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 
svcerr_noproc(SVCXPRT * xprt)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