1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 /* 30 * Portions of this source code were derived from Berkeley 31 * 4.3 BSD under license from the Regents of the University of 32 * California. 33 */ 34 35 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 /* 38 * svc_dg.c, Server side for connectionless RPC. 39 * 40 * Does some caching in the hopes of achieving execute-at-most-once semantics. 41 */ 42 43 #include "mt.h" 44 #include "rpc_mt.h" 45 #include <stdio.h> 46 #include <sys/types.h> 47 #include <rpc/rpc.h> 48 #include <errno.h> 49 #include <syslog.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <unistd.h> 53 #ifdef RPC_CACHE_DEBUG 54 #include <netconfig.h> 55 #include <netdir.h> 56 #endif 57 58 #ifndef MAX 59 #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 60 #endif 61 62 static struct xp_ops *svc_dg_ops(); 63 static void cache_set(); 64 static int cache_get(); 65 66 #define MAX_OPT_WORDS 128 /* needs to fit a ucred */ 67 68 /* 69 * kept in xprt->xp_p2 70 */ 71 struct svc_dg_data { 72 /* XXX: optbuf should be the first field, used by ti_opts.c code */ 73 struct netbuf optbuf; /* netbuf for options */ 74 int opts[MAX_OPT_WORDS]; /* options */ 75 uint_t su_iosz; /* size of send.recv buffer */ 76 uint32_t su_xid; /* transaction id */ 77 XDR su_xdrs; /* XDR handle */ 78 char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */ 79 char *su_cache; /* cached data, NULL if none */ 80 struct t_unitdata su_tudata; /* tu_data for recv */ 81 }; 82 #define su_data(xprt) ((struct svc_dg_data *)(xprt->xp_p2)) 83 #define rpc_buffer(xprt) ((xprt)->xp_p1) 84 85 /* 86 * Usage: 87 * xprt = svc_dg_create(sock, sendsize, recvsize); 88 * Does other connectionless specific initializations. 89 * Once *xprt is initialized, it is registered. 90 * see (svc.h, xprt_register). If recvsize or sendsize are 0 suitable 91 * system defaults are chosen. 92 * The routines returns NULL if a problem occurred. 93 */ 94 static const char svc_dg_str[] = "svc_dg_create: %s"; 95 static const char svc_dg_err1[] = "could not get transport information"; 96 static const char svc_dg_err2[] = " transport does not support data transfer"; 97 static const char svc_dg_err3[] = 98 "fd > FD_SETSIZE; Use rpc_control(RPC_SVC_USE_POLLFD,...);"; 99 static const char __no_mem_str[] = "out of memory"; 100 101 /* Structure used to initialize SVC_XP_AUTH(xprt).svc_ah_ops. */ 102 extern struct svc_auth_ops svc_auth_any_ops; 103 extern int __rpc_get_ltaddr(struct netbuf *, struct netbuf *); 104 105 void 106 svc_dg_xprtfree(SVCXPRT *xprt) 107 { 108 /* LINTED pointer alignment */ 109 SVCXPRT_EXT *xt = xprt ? SVCEXT(xprt) : NULL; 110 /* LINTED pointer alignment */ 111 struct svc_dg_data *su = xprt ? su_data(xprt) : NULL; 112 113 if (xprt == NULL) 114 return; 115 if (xprt->xp_netid) 116 free(xprt->xp_netid); 117 if (xprt->xp_tp) 118 free(xprt->xp_tp); 119 if (xt->parent == NULL) 120 if (xprt->xp_ltaddr.buf) 121 free(xprt->xp_ltaddr.buf); 122 if (xprt->xp_rtaddr.buf) 123 free(xprt->xp_rtaddr.buf); 124 if (su != NULL) { 125 XDR_DESTROY(&(su->su_xdrs)); 126 free(su); 127 } 128 if (rpc_buffer(xprt)) 129 free(rpc_buffer(xprt)); 130 svc_xprt_free(xprt); 131 } 132 133 SVCXPRT * 134 svc_dg_create_private(int fd, uint_t sendsize, uint_t recvsize) 135 { 136 SVCXPRT *xprt; 137 struct svc_dg_data *su = NULL; 138 struct t_info tinfo; 139 140 if (RPC_FD_NOTIN_FDSET(fd)) { 141 errno = EBADF; 142 t_errno = TBADF; 143 syslog(LOG_ERR, svc_dg_str, svc_dg_err3); 144 return (NULL); 145 } 146 147 if (t_getinfo(fd, &tinfo) == -1) { 148 syslog(LOG_ERR, svc_dg_str, svc_dg_err1); 149 return (NULL); 150 } 151 /* 152 * Find the receive and the send size 153 */ 154 sendsize = __rpc_get_t_size((int)sendsize, tinfo.tsdu); 155 recvsize = __rpc_get_t_size((int)recvsize, tinfo.tsdu); 156 if ((sendsize == 0) || (recvsize == 0)) { 157 syslog(LOG_ERR, svc_dg_str, svc_dg_err2); 158 return (NULL); 159 } 160 161 if ((xprt = svc_xprt_alloc()) == NULL) 162 goto freedata; 163 /* LINTED pointer alignment */ 164 svc_flags(xprt) |= SVC_DGRAM; 165 166 su = malloc(sizeof (*su)); 167 if (su == NULL) 168 goto freedata; 169 su->su_iosz = ((MAX(sendsize, recvsize) + 3) / 4) * 4; 170 if ((rpc_buffer(xprt) = malloc(su->su_iosz)) == NULL) 171 goto freedata; 172 xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, 173 XDR_DECODE); 174 su->su_cache = NULL; 175 xprt->xp_fd = fd; 176 xprt->xp_p2 = (caddr_t)su; 177 xprt->xp_verf.oa_base = su->su_verfbody; 178 xprt->xp_ops = svc_dg_ops(); 179 180 su->su_tudata.addr.maxlen = 0; /* Fill in later */ 181 182 su->su_tudata.udata.buf = (char *)rpc_buffer(xprt); 183 su->su_tudata.opt.buf = (char *)su->opts; 184 su->su_tudata.udata.maxlen = su->su_iosz; 185 su->su_tudata.opt.maxlen = MAX_OPT_WORDS << 2; /* no of bytes */ 186 /* LINTED pointer alignment */ 187 SVC_XP_AUTH(xprt).svc_ah_ops = svc_auth_any_ops; 188 /* LINTED pointer alignment */ 189 SVC_XP_AUTH(xprt).svc_ah_private = NULL; 190 return (xprt); 191 freedata: 192 (void) syslog(LOG_ERR, svc_dg_str, __no_mem_str); 193 if (xprt) 194 svc_dg_xprtfree(xprt); 195 return (NULL); 196 } 197 198 SVCXPRT * 199 svc_dg_create(const int fd, const uint_t sendsize, const uint_t recvsize) 200 { 201 SVCXPRT *xprt; 202 203 if ((xprt = svc_dg_create_private(fd, sendsize, recvsize)) != NULL) 204 xprt_register(xprt); 205 return (xprt); 206 } 207 208 SVCXPRT * 209 svc_dg_xprtcopy(SVCXPRT *parent) 210 { 211 SVCXPRT *xprt; 212 struct svc_dg_data *su; 213 214 if ((xprt = svc_xprt_alloc()) == NULL) 215 return (NULL); 216 217 /* LINTED pointer alignment */ 218 SVCEXT(xprt)->parent = parent; 219 /* LINTED pointer alignment */ 220 SVCEXT(xprt)->flags = SVCEXT(parent)->flags; 221 222 xprt->xp_fd = parent->xp_fd; 223 xprt->xp_port = parent->xp_port; 224 xprt->xp_ops = svc_dg_ops(); 225 if (parent->xp_tp) { 226 xprt->xp_tp = (char *)strdup(parent->xp_tp); 227 if (xprt->xp_tp == NULL) { 228 syslog(LOG_ERR, "svc_dg_xprtcopy: strdup failed"); 229 svc_dg_xprtfree(xprt); 230 return (NULL); 231 } 232 } 233 if (parent->xp_netid) { 234 xprt->xp_netid = (char *)strdup(parent->xp_netid); 235 if (xprt->xp_netid == NULL) { 236 syslog(LOG_ERR, "svc_dg_xprtcopy: strdup failed"); 237 if (parent->xp_tp) 238 free(parent->xp_tp); 239 svc_dg_xprtfree(xprt); 240 return (NULL); 241 } 242 } 243 xprt->xp_ltaddr = parent->xp_ltaddr; /* shared with parent */ 244 245 xprt->xp_rtaddr = parent->xp_rtaddr; 246 xprt->xp_rtaddr.buf = malloc(xprt->xp_rtaddr.maxlen); 247 if (xprt->xp_rtaddr.buf == NULL) { 248 svc_dg_xprtfree(xprt); 249 return (NULL); 250 } 251 (void) memcpy(xprt->xp_rtaddr.buf, parent->xp_rtaddr.buf, 252 xprt->xp_rtaddr.maxlen); 253 xprt->xp_type = parent->xp_type; 254 255 if ((su = malloc(sizeof (struct svc_dg_data))) == NULL) { 256 svc_dg_xprtfree(xprt); 257 return (NULL); 258 } 259 /* LINTED pointer alignment */ 260 su->su_iosz = su_data(parent)->su_iosz; 261 if ((rpc_buffer(xprt) = malloc(su->su_iosz)) == NULL) { 262 svc_dg_xprtfree(xprt); 263 free(su); 264 return (NULL); 265 } 266 xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, 267 XDR_DECODE); 268 su->su_cache = NULL; 269 su->su_tudata.addr.maxlen = 0; /* Fill in later */ 270 su->su_tudata.udata.buf = (char *)rpc_buffer(xprt); 271 su->su_tudata.opt.buf = (char *)su->opts; 272 su->su_tudata.udata.maxlen = su->su_iosz; 273 su->su_tudata.opt.maxlen = MAX_OPT_WORDS << 2; /* no of bytes */ 274 xprt->xp_p2 = (caddr_t)su; /* su_data(xprt) = su */ 275 xprt->xp_verf.oa_base = su->su_verfbody; 276 277 return (xprt); 278 } 279 280 /*ARGSUSED*/ 281 static enum xprt_stat 282 svc_dg_stat(SVCXPRT *xprt) 283 { 284 return (XPRT_IDLE); 285 } 286 287 static bool_t 288 svc_dg_recv(SVCXPRT *xprt, struct rpc_msg *msg) 289 { 290 /* LINTED pointer alignment */ 291 struct svc_dg_data *su = su_data(xprt); 292 XDR *xdrs = &(su->su_xdrs); 293 struct t_unitdata *tu_data = &(su->su_tudata); 294 int moreflag; 295 struct netbuf *nbufp; 296 struct netconfig *nconf; 297 298 /* XXX: tudata should have been made a part of the server handle */ 299 if (tu_data->addr.maxlen == 0) 300 tu_data->addr = xprt->xp_rtaddr; 301 again: 302 tu_data->addr.len = 0; 303 tu_data->opt.len = 0; 304 tu_data->udata.len = 0; 305 306 moreflag = 0; 307 if (t_rcvudata(xprt->xp_fd, tu_data, &moreflag) == -1) { 308 #ifdef RPC_DEBUG 309 syslog(LOG_ERR, "svc_dg_recv: t_rcvudata t_errno=%d errno=%d\n", 310 t_errno, errno); 311 #endif 312 if (t_errno == TLOOK) { 313 int lookres; 314 315 lookres = t_look(xprt->xp_fd); 316 if ((lookres & T_UDERR) && 317 (t_rcvuderr(xprt->xp_fd, 318 (struct t_uderr *)0) < 0)) { 319 /*EMPTY*/ 320 #ifdef RPC_DEBUG 321 syslog(LOG_ERR, 322 "svc_dg_recv: t_rcvuderr t_errno = %d\n", 323 t_errno); 324 #endif 325 } 326 if (lookres & T_DATA) 327 goto again; 328 } else if ((errno == EINTR) && (t_errno == TSYSERR)) 329 goto again; 330 else { 331 return (FALSE); 332 } 333 } 334 335 if ((moreflag) || 336 (tu_data->udata.len < 4 * (uint_t)sizeof (uint32_t))) { 337 /* 338 * If moreflag is set, drop that data packet. Something wrong 339 */ 340 return (FALSE); 341 } 342 su->optbuf = tu_data->opt; 343 xprt->xp_rtaddr.len = tu_data->addr.len; 344 xdrs->x_op = XDR_DECODE; 345 XDR_SETPOS(xdrs, 0); 346 if (!xdr_callmsg(xdrs, msg)) 347 return (FALSE); 348 su->su_xid = msg->rm_xid; 349 if (su->su_cache != NULL) { 350 char *reply; 351 uint32_t replylen; 352 353 if (cache_get(xprt, msg, &reply, &replylen)) { 354 /* tu_data.addr is already set */ 355 tu_data->udata.buf = reply; 356 tu_data->udata.len = (uint_t)replylen; 357 tu_data->opt.len = 0; 358 (void) t_sndudata(xprt->xp_fd, tu_data); 359 tu_data->udata.buf = (char *)rpc_buffer(xprt); 360 return (FALSE); 361 } 362 } 363 364 /* 365 * get local ip address 366 */ 367 368 if ((nconf = getnetconfigent(xprt->xp_netid)) != NULL) { 369 if (strcmp(nconf->nc_protofmly, NC_INET) == 0 || 370 strcmp(nconf->nc_protofmly, NC_INET6) == 0) { 371 if (nconf->nc_semantics == NC_TPI_CLTS) { 372 /* LINTED pointer cast */ 373 nbufp = (struct netbuf *)(xprt->xp_p2); 374 if (__rpc_get_ltaddr(nbufp, &xprt->xp_ltaddr) < 0) { 375 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 376 syslog(LOG_ERR, 377 "svc_dg_recv: ip(udp), t_errno=%d, errno=%d", 378 t_errno, errno); 379 } 380 if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) { 381 syslog(LOG_ERR, 382 "svc_dg_recv: ip (udp6), t_errno=%d, errno=%d", 383 t_errno, errno); 384 } 385 freenetconfigent(nconf); 386 return (FALSE); 387 } 388 } 389 } 390 freenetconfigent(nconf); 391 } 392 return (TRUE); 393 } 394 395 static bool_t 396 svc_dg_reply(SVCXPRT *xprt, struct rpc_msg *msg) 397 { 398 /* LINTED pointer alignment */ 399 struct svc_dg_data *su = su_data(xprt); 400 XDR *xdrs = &(su->su_xdrs); 401 bool_t stat = FALSE; 402 xdrproc_t xdr_results; 403 caddr_t xdr_location; 404 bool_t has_args; 405 406 if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 407 msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 408 has_args = TRUE; 409 xdr_results = msg->acpted_rply.ar_results.proc; 410 xdr_location = msg->acpted_rply.ar_results.where; 411 msg->acpted_rply.ar_results.proc = xdr_void; 412 msg->acpted_rply.ar_results.where = NULL; 413 } else 414 has_args = FALSE; 415 416 xdrs->x_op = XDR_ENCODE; 417 XDR_SETPOS(xdrs, 0); 418 msg->rm_xid = su->su_xid; 419 if (xdr_replymsg(xdrs, msg) && (!has_args || 420 /* LINTED pointer alignment */ 421 SVCAUTH_WRAP(&SVC_XP_AUTH(xprt), xdrs, xdr_results, 422 xdr_location))) { 423 int slen; 424 struct t_unitdata *tu_data = &(su->su_tudata); 425 426 slen = (int)XDR_GETPOS(xdrs); 427 tu_data->udata.len = slen; 428 tu_data->opt.len = 0; 429 try_again: 430 if (t_sndudata(xprt->xp_fd, tu_data) == 0) { 431 stat = TRUE; 432 if (su->su_cache && slen >= 0) { 433 cache_set(xprt, (uint32_t)slen); 434 } 435 } else { 436 if (errno == EINTR) 437 goto try_again; 438 439 syslog(LOG_ERR, 440 "svc_dg_reply: t_sndudata error t_errno=%d errno=%d\n", 441 t_errno, errno); 442 } 443 } 444 return (stat); 445 } 446 447 static bool_t 448 svc_dg_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) 449 { 450 if (svc_mt_mode != RPC_SVC_MT_NONE) 451 svc_args_done(xprt); 452 /* LINTED pointer alignment */ 453 return (SVCAUTH_UNWRAP(&SVC_XP_AUTH(xprt), 454 &(su_data(xprt)->su_xdrs), xdr_args, args_ptr)); 455 } 456 457 static bool_t 458 svc_dg_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) 459 { 460 /* LINTED pointer alignment */ 461 XDR *xdrs = &(su_data(xprt)->su_xdrs); 462 463 xdrs->x_op = XDR_FREE; 464 return ((*xdr_args)(xdrs, args_ptr)); 465 } 466 467 static void 468 svc_dg_destroy(SVCXPRT *xprt) 469 { 470 (void) mutex_lock(&svc_mutex); 471 _svc_dg_destroy_private(xprt); 472 (void) mutex_unlock(&svc_mutex); 473 } 474 475 void 476 _svc_dg_destroy_private(SVCXPRT *xprt) 477 { 478 if (svc_mt_mode != RPC_SVC_MT_NONE) { 479 /* LINTED pointer alignment */ 480 if (SVCEXT(xprt)->parent) 481 /* LINTED pointer alignment */ 482 xprt = SVCEXT(xprt)->parent; 483 /* LINTED pointer alignment */ 484 svc_flags(xprt) |= SVC_DEFUNCT; 485 /* LINTED pointer alignment */ 486 if (SVCEXT(xprt)->refcnt > 0) 487 return; 488 } 489 490 xprt_unregister(xprt); 491 (void) t_close(xprt->xp_fd); 492 493 if (svc_mt_mode != RPC_SVC_MT_NONE) 494 svc_xprt_destroy(xprt); 495 else 496 svc_dg_xprtfree(xprt); 497 } 498 499 /*ARGSUSED*/ 500 static bool_t 501 svc_dg_control(SVCXPRT *xprt, const uint_t rq, void *in) 502 { 503 switch (rq) { 504 case SVCGET_XID: 505 if (xprt->xp_p2 == NULL) 506 return (FALSE); 507 /* LINTED pointer alignment */ 508 *(uint32_t *)in = ((struct svc_dg_data *)(xprt->xp_p2))->su_xid; 509 return (TRUE); 510 default: 511 return (FALSE); 512 } 513 } 514 515 static struct xp_ops * 516 svc_dg_ops(void) 517 { 518 static struct xp_ops ops; 519 extern mutex_t ops_lock; 520 521 /* VARIABLES PROTECTED BY ops_lock: ops */ 522 523 (void) mutex_lock(&ops_lock); 524 if (ops.xp_recv == NULL) { 525 ops.xp_recv = svc_dg_recv; 526 ops.xp_stat = svc_dg_stat; 527 ops.xp_getargs = svc_dg_getargs; 528 ops.xp_reply = svc_dg_reply; 529 ops.xp_freeargs = svc_dg_freeargs; 530 ops.xp_destroy = svc_dg_destroy; 531 ops.xp_control = svc_dg_control; 532 } 533 (void) mutex_unlock(&ops_lock); 534 return (&ops); 535 } 536 537 /* The CACHING COMPONENT */ 538 539 /* 540 * Could have been a separate file, but some part of it depends upon the 541 * private structure of the client handle. 542 * 543 * Fifo cache for cl server 544 * Copies pointers to reply buffers into fifo cache 545 * Buffers are sent again if retransmissions are detected. 546 */ 547 548 #define SPARSENESS 4 /* 75% sparse */ 549 550 /* 551 * An entry in the cache 552 */ 553 typedef struct cache_node *cache_ptr; 554 struct cache_node { 555 /* 556 * Index into cache is xid, proc, vers, prog and address 557 */ 558 uint32_t cache_xid; 559 rpcproc_t cache_proc; 560 rpcvers_t cache_vers; 561 rpcprog_t cache_prog; 562 struct netbuf cache_addr; 563 /* 564 * The cached reply and length 565 */ 566 char *cache_reply; 567 uint32_t cache_replylen; 568 /* 569 * Next node on the list, if there is a collision 570 */ 571 cache_ptr cache_next; 572 }; 573 574 /* 575 * The entire cache 576 */ 577 struct cl_cache { 578 uint32_t uc_size; /* size of cache */ 579 cache_ptr *uc_entries; /* hash table of entries in cache */ 580 cache_ptr *uc_fifo; /* fifo list of entries in cache */ 581 uint32_t uc_nextvictim; /* points to next victim in fifo list */ 582 rpcprog_t uc_prog; /* saved program number */ 583 rpcvers_t uc_vers; /* saved version number */ 584 rpcproc_t uc_proc; /* saved procedure number */ 585 }; 586 587 588 /* 589 * the hashing function 590 */ 591 #define CACHE_LOC(transp, xid) \ 592 (xid % (SPARSENESS * ((struct cl_cache *) \ 593 su_data(transp)->su_cache)->uc_size)) 594 595 extern mutex_t dupreq_lock; 596 597 /* 598 * Enable use of the cache. Returns 1 on success, 0 on failure. 599 * Note: there is no disable. 600 */ 601 static const char cache_enable_str[] = "svc_enablecache: %s %s"; 602 static const char alloc_err[] = "could not allocate cache "; 603 static const char enable_err[] = "cache already enabled"; 604 605 int 606 svc_dg_enablecache(SVCXPRT *xprt, const uint_t size) 607 { 608 SVCXPRT *transp; 609 struct svc_dg_data *su; 610 struct cl_cache *uc; 611 612 /* LINTED pointer alignment */ 613 if (svc_mt_mode != RPC_SVC_MT_NONE && SVCEXT(xprt)->parent != NULL) 614 /* LINTED pointer alignment */ 615 transp = SVCEXT(xprt)->parent; 616 else 617 transp = xprt; 618 /* LINTED pointer alignment */ 619 su = su_data(transp); 620 621 (void) mutex_lock(&dupreq_lock); 622 if (su->su_cache != NULL) { 623 (void) syslog(LOG_ERR, cache_enable_str, 624 enable_err, " "); 625 (void) mutex_unlock(&dupreq_lock); 626 return (0); 627 } 628 uc = malloc(sizeof (struct cl_cache)); 629 if (uc == NULL) { 630 (void) syslog(LOG_ERR, cache_enable_str, 631 alloc_err, " "); 632 (void) mutex_unlock(&dupreq_lock); 633 return (0); 634 } 635 uc->uc_size = size; 636 uc->uc_nextvictim = 0; 637 uc->uc_entries = calloc(size * SPARSENESS, sizeof (cache_ptr)); 638 if (uc->uc_entries == NULL) { 639 (void) syslog(LOG_ERR, cache_enable_str, alloc_err, "data"); 640 free(uc); 641 (void) mutex_unlock(&dupreq_lock); 642 return (0); 643 } 644 uc->uc_fifo = calloc(size, sizeof (cache_ptr)); 645 if (uc->uc_fifo == NULL) { 646 (void) syslog(LOG_ERR, cache_enable_str, alloc_err, "fifo"); 647 free(uc->uc_entries); 648 free(uc); 649 (void) mutex_unlock(&dupreq_lock); 650 return (0); 651 } 652 su->su_cache = (char *)uc; 653 (void) mutex_unlock(&dupreq_lock); 654 return (1); 655 } 656 657 /* 658 * Set an entry in the cache. It assumes that the uc entry is set from 659 * the earlier call to cache_get() for the same procedure. This will always 660 * happen because cache_get() is calle by svc_dg_recv and cache_set() is called 661 * by svc_dg_reply(). All this hoopla because the right RPC parameters are 662 * not available at svc_dg_reply time. 663 */ 664 665 static const char cache_set_str[] = "cache_set: %s"; 666 static const char cache_set_err1[] = "victim not found"; 667 static const char cache_set_err2[] = "victim alloc failed"; 668 static const char cache_set_err3[] = "could not allocate new rpc buffer"; 669 670 static void 671 cache_set(SVCXPRT *xprt, uint32_t replylen) 672 { 673 SVCXPRT *parent; 674 cache_ptr victim; 675 cache_ptr *vicp; 676 struct svc_dg_data *su; 677 struct cl_cache *uc; 678 uint_t loc; 679 char *newbuf, *newbuf2; 680 int my_mallocs = 0; 681 #ifdef RPC_CACHE_DEBUG 682 struct netconfig *nconf; 683 char *uaddr; 684 #endif 685 686 /* LINTED pointer alignment */ 687 if (svc_mt_mode != RPC_SVC_MT_NONE && SVCEXT(xprt)->parent != NULL) 688 /* LINTED pointer alignment */ 689 parent = SVCEXT(xprt)->parent; 690 else 691 parent = xprt; 692 /* LINTED pointer alignment */ 693 su = su_data(xprt); 694 /* LINTED pointer alignment */ 695 uc = (struct cl_cache *)su_data(parent)->su_cache; 696 697 (void) mutex_lock(&dupreq_lock); 698 /* 699 * Find space for the new entry, either by 700 * reusing an old entry, or by mallocing a new one 701 */ 702 victim = uc->uc_fifo[uc->uc_nextvictim]; 703 if (victim != NULL) { 704 /* LINTED pointer alignment */ 705 loc = CACHE_LOC(parent, victim->cache_xid); 706 for (vicp = &uc->uc_entries[loc]; 707 *vicp != NULL && *vicp != victim; 708 vicp = &(*vicp)->cache_next) 709 ; 710 if (*vicp == NULL) { 711 (void) syslog(LOG_ERR, cache_set_str, cache_set_err1); 712 (void) mutex_unlock(&dupreq_lock); 713 return; 714 } 715 *vicp = victim->cache_next; /* remove from cache */ 716 newbuf = victim->cache_reply; 717 } else { 718 victim = malloc(sizeof (struct cache_node)); 719 if (victim == NULL) { 720 (void) syslog(LOG_ERR, cache_set_str, cache_set_err2); 721 (void) mutex_unlock(&dupreq_lock); 722 return; 723 } 724 newbuf = malloc(su->su_iosz); 725 if (newbuf == NULL) { 726 (void) syslog(LOG_ERR, cache_set_str, cache_set_err3); 727 free(victim); 728 (void) mutex_unlock(&dupreq_lock); 729 return; 730 } 731 my_mallocs = 1; 732 } 733 734 /* 735 * Store it away 736 */ 737 #ifdef RPC_CACHE_DEBUG 738 if (nconf = getnetconfigent(xprt->xp_netid)) { 739 uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr); 740 freenetconfigent(nconf); 741 printf( 742 "cache set for xid= %x prog=%d vers=%d proc=%d for rmtaddr=%s\n", 743 su->su_xid, uc->uc_prog, uc->uc_vers, 744 uc->uc_proc, uaddr); 745 free(uaddr); 746 } 747 #endif 748 newbuf2 = malloc(sizeof (char) * xprt->xp_rtaddr.len); 749 if (newbuf2 == NULL) { 750 syslog(LOG_ERR, "cache_set : out of memory"); 751 if (my_mallocs) { 752 free(victim); 753 free(newbuf); 754 } 755 (void) mutex_unlock(&dupreq_lock); 756 return; 757 } 758 victim->cache_replylen = replylen; 759 victim->cache_reply = rpc_buffer(xprt); 760 rpc_buffer(xprt) = newbuf; 761 xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), 762 su->su_iosz, XDR_ENCODE); 763 su->su_tudata.udata.buf = (char *)rpc_buffer(xprt); 764 victim->cache_xid = su->su_xid; 765 victim->cache_proc = uc->uc_proc; 766 victim->cache_vers = uc->uc_vers; 767 victim->cache_prog = uc->uc_prog; 768 victim->cache_addr = xprt->xp_rtaddr; 769 victim->cache_addr.buf = newbuf2; 770 (void) memcpy(victim->cache_addr.buf, xprt->xp_rtaddr.buf, 771 (int)xprt->xp_rtaddr.len); 772 /* LINTED pointer alignment */ 773 loc = CACHE_LOC(parent, victim->cache_xid); 774 victim->cache_next = uc->uc_entries[loc]; 775 uc->uc_entries[loc] = victim; 776 uc->uc_fifo[uc->uc_nextvictim++] = victim; 777 uc->uc_nextvictim %= uc->uc_size; 778 (void) mutex_unlock(&dupreq_lock); 779 } 780 781 /* 782 * Try to get an entry from the cache 783 * return 1 if found, 0 if not found and set the stage for cache_set() 784 */ 785 static int 786 cache_get(SVCXPRT *xprt, struct rpc_msg *msg, char **replyp, 787 uint32_t *replylenp) 788 { 789 SVCXPRT *parent; 790 uint_t loc; 791 cache_ptr ent; 792 struct svc_dg_data *su; 793 struct cl_cache *uc; 794 #ifdef RPC_CACHE_DEBUG 795 struct netconfig *nconf; 796 char *uaddr; 797 #endif 798 799 /* LINTED pointer alignment */ 800 if (svc_mt_mode != RPC_SVC_MT_NONE && SVCEXT(xprt)->parent != NULL) 801 /* LINTED pointer alignment */ 802 parent = SVCEXT(xprt)->parent; 803 else 804 parent = xprt; 805 /* LINTED pointer alignment */ 806 su = su_data(xprt); 807 /* LINTED pointer alignment */ 808 uc = (struct cl_cache *)su_data(parent)->su_cache; 809 810 (void) mutex_lock(&dupreq_lock); 811 /* LINTED pointer alignment */ 812 loc = CACHE_LOC(parent, su->su_xid); 813 for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) { 814 if (ent->cache_xid == su->su_xid && 815 ent->cache_proc == msg->rm_call.cb_proc && 816 ent->cache_vers == msg->rm_call.cb_vers && 817 ent->cache_prog == msg->rm_call.cb_prog && 818 ent->cache_addr.len == xprt->xp_rtaddr.len && 819 (memcmp(ent->cache_addr.buf, xprt->xp_rtaddr.buf, 820 xprt->xp_rtaddr.len) == 0)) { 821 #ifdef RPC_CACHE_DEBUG 822 if (nconf = getnetconfigent(xprt->xp_netid)) { 823 uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr); 824 freenetconfigent(nconf); 825 printf( 826 "cache entry found for xid=%x prog=%d vers=%d proc=%d for rmtaddr=%s\n", 827 su->su_xid, msg->rm_call.cb_prog, 828 msg->rm_call.cb_vers, 829 msg->rm_call.cb_proc, uaddr); 830 free(uaddr); 831 } 832 #endif 833 *replyp = ent->cache_reply; 834 *replylenp = ent->cache_replylen; 835 (void) mutex_unlock(&dupreq_lock); 836 return (1); 837 } 838 } 839 /* 840 * Failed to find entry 841 * Remember a few things so we can do a set later 842 */ 843 uc->uc_proc = msg->rm_call.cb_proc; 844 uc->uc_vers = msg->rm_call.cb_vers; 845 uc->uc_prog = msg->rm_call.cb_prog; 846 (void) mutex_unlock(&dupreq_lock); 847 return (0); 848 } 849