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