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