17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 22*61961e0fSrobinson 237c478bd9Sstevel@tonic-gate /* 24*61961e0fSrobinson * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate * Use is subject to license terms. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. 297c478bd9Sstevel@tonic-gate */ 307c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 317c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 327c478bd9Sstevel@tonic-gate /* 337c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 347c478bd9Sstevel@tonic-gate * 4.3 BSD under license from the Regents of the University of 357c478bd9Sstevel@tonic-gate * California. 367c478bd9Sstevel@tonic-gate */ 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate /* 417c478bd9Sstevel@tonic-gate * svc.c, Server-side remote procedure call interface. 427c478bd9Sstevel@tonic-gate * 437c478bd9Sstevel@tonic-gate * There are two sets of procedures here. The xprt routines are 447c478bd9Sstevel@tonic-gate * for handling transport handles. The svc routines handle the 457c478bd9Sstevel@tonic-gate * list of service routines. 467c478bd9Sstevel@tonic-gate * 477c478bd9Sstevel@tonic-gate */ 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate #include "mt.h" 517c478bd9Sstevel@tonic-gate #include "rpc_mt.h" 527c478bd9Sstevel@tonic-gate #include <assert.h> 537c478bd9Sstevel@tonic-gate #include <errno.h> 547c478bd9Sstevel@tonic-gate #include <sys/types.h> 557c478bd9Sstevel@tonic-gate #include <stropts.h> 567c478bd9Sstevel@tonic-gate #include <sys/conf.h> 577c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 587c478bd9Sstevel@tonic-gate #ifdef PORTMAP 597c478bd9Sstevel@tonic-gate #include <rpc/pmap_clnt.h> 607c478bd9Sstevel@tonic-gate #endif 617c478bd9Sstevel@tonic-gate #include <sys/poll.h> 627c478bd9Sstevel@tonic-gate #include <netconfig.h> 637c478bd9Sstevel@tonic-gate #include <syslog.h> 647c478bd9Sstevel@tonic-gate #include <stdlib.h> 657c478bd9Sstevel@tonic-gate #include <unistd.h> 667c478bd9Sstevel@tonic-gate #include <string.h> 677c478bd9Sstevel@tonic-gate #include <limits.h> 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate extern bool_t __svc_get_door_cred(); 707c478bd9Sstevel@tonic-gate extern bool_t __rpc_get_local_cred(); 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate SVCXPRT **svc_xports; 737c478bd9Sstevel@tonic-gate static int nsvc_xports; /* total number of svc_xports allocated */ 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate XDR **svc_xdrs; /* common XDR receive area */ 767c478bd9Sstevel@tonic-gate int nsvc_xdrs; /* total number of svc_xdrs allocated */ 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate int __rpc_use_pollfd_done; /* to unlimit the number of connections */ 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate #define NULL_SVC ((struct svc_callout *)0) 817c478bd9Sstevel@tonic-gate #define RQCRED_SIZE 400 /* this size is excessive */ 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* 847c478bd9Sstevel@tonic-gate * The services list 857c478bd9Sstevel@tonic-gate * Each entry represents a set of procedures (an rpc program). 867c478bd9Sstevel@tonic-gate * The dispatch routine takes request structs and runs the 877c478bd9Sstevel@tonic-gate * appropriate procedure. 887c478bd9Sstevel@tonic-gate */ 897c478bd9Sstevel@tonic-gate static struct svc_callout { 907c478bd9Sstevel@tonic-gate struct svc_callout *sc_next; 917c478bd9Sstevel@tonic-gate rpcprog_t sc_prog; 927c478bd9Sstevel@tonic-gate rpcvers_t sc_vers; 937c478bd9Sstevel@tonic-gate char *sc_netid; 947c478bd9Sstevel@tonic-gate void (*sc_dispatch)(); 957c478bd9Sstevel@tonic-gate } *svc_head; 967c478bd9Sstevel@tonic-gate extern rwlock_t svc_lock; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate static struct svc_callout *svc_find(); 997c478bd9Sstevel@tonic-gate int _svc_prog_dispatch(); 1007c478bd9Sstevel@tonic-gate void svc_getreq_common(); 1017c478bd9Sstevel@tonic-gate char *strdup(); 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate extern mutex_t svc_door_mutex; 1047c478bd9Sstevel@tonic-gate extern cond_t svc_door_waitcv; 1057c478bd9Sstevel@tonic-gate extern int svc_ndoorfds; 1067c478bd9Sstevel@tonic-gate extern SVCXPRT_LIST *_svc_xprtlist; 1077c478bd9Sstevel@tonic-gate extern mutex_t xprtlist_lock; 1087c478bd9Sstevel@tonic-gate extern void __svc_rm_from_xlist(); 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate extern fd_set _new_svc_fdset; 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate /* 1137c478bd9Sstevel@tonic-gate * If the allocated array of reactor is too small, this value is used as a 1147c478bd9Sstevel@tonic-gate * margin. This reduces the number of allocations. 1157c478bd9Sstevel@tonic-gate */ 1167c478bd9Sstevel@tonic-gate #define USER_FD_INCREMENT 5 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate static void add_pollfd(int fd, short events); 1197c478bd9Sstevel@tonic-gate static void remove_pollfd(int fd); 1207c478bd9Sstevel@tonic-gate static void __svc_remove_input_of_fd(int fd); 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate /* 1247c478bd9Sstevel@tonic-gate * Data used to handle reactor: 1257c478bd9Sstevel@tonic-gate * - one file descriptor we listen to, 1267c478bd9Sstevel@tonic-gate * - one callback we call if the fd pops, 1277c478bd9Sstevel@tonic-gate * - and a cookie passed as a parameter to the callback. 1287c478bd9Sstevel@tonic-gate * 1297c478bd9Sstevel@tonic-gate * The structure is an array indexed on the file descriptor. Each entry is 1307c478bd9Sstevel@tonic-gate * pointing to the first element of a double-linked list of callback. 1317c478bd9Sstevel@tonic-gate * only one callback may be associated to a couple (fd, event). 1327c478bd9Sstevel@tonic-gate */ 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate struct _svc_user_fd_head; 1357c478bd9Sstevel@tonic-gate 136*61961e0fSrobinson typedef struct { 1377c478bd9Sstevel@tonic-gate struct _svc_user_fd_node *next; 1387c478bd9Sstevel@tonic-gate struct _svc_user_fd_node *previous; 1397c478bd9Sstevel@tonic-gate } _svc_user_link; 1407c478bd9Sstevel@tonic-gate 141*61961e0fSrobinson typedef struct _svc_user_fd_node { 1427c478bd9Sstevel@tonic-gate /* The lnk field must be the first field. */ 1437c478bd9Sstevel@tonic-gate _svc_user_link lnk; 1447c478bd9Sstevel@tonic-gate svc_input_id_t id; 1457c478bd9Sstevel@tonic-gate int fd; 1467c478bd9Sstevel@tonic-gate unsigned int events; 1477c478bd9Sstevel@tonic-gate svc_callback_t callback; 1487c478bd9Sstevel@tonic-gate void* cookie; 1497c478bd9Sstevel@tonic-gate } _svc_user_fd_node; 1507c478bd9Sstevel@tonic-gate 151*61961e0fSrobinson typedef struct _svc_user_fd_head { 1527c478bd9Sstevel@tonic-gate /* The lnk field must be the first field. */ 1537c478bd9Sstevel@tonic-gate _svc_user_link lnk; 1547c478bd9Sstevel@tonic-gate unsigned int mask; /* logical OR of all sub-masks */ 1557c478bd9Sstevel@tonic-gate } _svc_user_fd_head; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate /* Define some macros to manage the linked list. */ 1597c478bd9Sstevel@tonic-gate #define LIST_ISEMPTY(l) ((_svc_user_fd_node *) &(l.lnk) == l.lnk.next) 1607c478bd9Sstevel@tonic-gate #define LIST_CLR(l) \ 1617c478bd9Sstevel@tonic-gate (l.lnk.previous = l.lnk.next = (_svc_user_fd_node *) &(l.lnk)) 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate /* Array of defined reactor - indexed on file descriptor */ 1647c478bd9Sstevel@tonic-gate static _svc_user_fd_head *svc_userfds = NULL; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate /* current size of file descriptor */ 1677c478bd9Sstevel@tonic-gate static int svc_nuserfds = 0; 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* Mutex to ensure MT safe operations for user fds callbacks. */ 1707c478bd9Sstevel@tonic-gate static mutex_t svc_userfds_lock = DEFAULTMUTEX; 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate /* 1747c478bd9Sstevel@tonic-gate * This structure is used to have constant time alogrithms. There is an array 1757c478bd9Sstevel@tonic-gate * of this structure as large as svc_nuserfds. When the user is registering a 1767c478bd9Sstevel@tonic-gate * new callback, the address of the created structure is stored in a cell of 1777c478bd9Sstevel@tonic-gate * this array. The address of this cell is the returned unique identifier. 1787c478bd9Sstevel@tonic-gate * 1797c478bd9Sstevel@tonic-gate * On removing, the id is given by the user, then we know if this cell is 1807c478bd9Sstevel@tonic-gate * filled or not (with free). If it is free, we return an error. Otherwise, 1817c478bd9Sstevel@tonic-gate * we can free the structure pointed by fd_node. 1827c478bd9Sstevel@tonic-gate * 1837c478bd9Sstevel@tonic-gate * On insertion, we use the linked list created by (first_free, 1847c478bd9Sstevel@tonic-gate * next_free). In this way with a constant time computation, we can give a 1857c478bd9Sstevel@tonic-gate * correct index to the user. 1867c478bd9Sstevel@tonic-gate */ 1877c478bd9Sstevel@tonic-gate 188*61961e0fSrobinson typedef struct _svc_management_user_fd { 1897c478bd9Sstevel@tonic-gate bool_t free; 1907c478bd9Sstevel@tonic-gate union { 1917c478bd9Sstevel@tonic-gate svc_input_id_t next_free; 1927c478bd9Sstevel@tonic-gate _svc_user_fd_node *fd_node; 1937c478bd9Sstevel@tonic-gate } data; 1947c478bd9Sstevel@tonic-gate } _svc_management_user_fd; 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate /* index to the first free elem */ 1977c478bd9Sstevel@tonic-gate static svc_input_id_t first_free = (svc_input_id_t)-1; 1987c478bd9Sstevel@tonic-gate /* the size of this array is the same as svc_nuserfds */ 1997c478bd9Sstevel@tonic-gate static _svc_management_user_fd* user_fd_mgt_array = NULL; 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate /* current size of user_fd_mgt_array */ 2027c478bd9Sstevel@tonic-gate static int svc_nmgtuserfds = 0; 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate /* Define some macros to access data associated to registration ids. */ 2067c478bd9Sstevel@tonic-gate #define node_from_id(id) (user_fd_mgt_array[(int)id].data.fd_node) 2077c478bd9Sstevel@tonic-gate #define is_free_id(id) (user_fd_mgt_array[(int)id].free) 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate #ifndef POLLSTANDARD 2107c478bd9Sstevel@tonic-gate #define POLLSTANDARD \ 2117c478bd9Sstevel@tonic-gate (POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLRDBAND| \ 2127c478bd9Sstevel@tonic-gate POLLWRBAND|POLLERR|POLLHUP|POLLNVAL) 2137c478bd9Sstevel@tonic-gate #endif 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate /* 2167c478bd9Sstevel@tonic-gate * To free an Id, we set the cell as free and insert its address in the list 2177c478bd9Sstevel@tonic-gate * of free cell. 2187c478bd9Sstevel@tonic-gate */ 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate static void 2217c478bd9Sstevel@tonic-gate _svc_free_id(const svc_input_id_t id) 2227c478bd9Sstevel@tonic-gate { 2237c478bd9Sstevel@tonic-gate assert(((int)id >= 0) && ((int)id < svc_nmgtuserfds)); 2247c478bd9Sstevel@tonic-gate user_fd_mgt_array[(int)id].free = TRUE; 2257c478bd9Sstevel@tonic-gate user_fd_mgt_array[(int)id].data.next_free = first_free; 2267c478bd9Sstevel@tonic-gate first_free = id; 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate /* 2307c478bd9Sstevel@tonic-gate * To get a free cell, we just have to take it from the free linked list and 2317c478bd9Sstevel@tonic-gate * set the flag to "not free". This function also allocates new memory if 2327c478bd9Sstevel@tonic-gate * necessary 2337c478bd9Sstevel@tonic-gate */ 2347c478bd9Sstevel@tonic-gate static svc_input_id_t 2357c478bd9Sstevel@tonic-gate _svc_attribute_new_id(_svc_user_fd_node *node) 2367c478bd9Sstevel@tonic-gate { 2377c478bd9Sstevel@tonic-gate int selected_index = (int)first_free; 2387c478bd9Sstevel@tonic-gate assert(node != NULL); 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate if (selected_index == -1) { 2417c478bd9Sstevel@tonic-gate /* Allocate new entries */ 2427c478bd9Sstevel@tonic-gate int L_inOldSize = svc_nmgtuserfds; 2437c478bd9Sstevel@tonic-gate int i; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate svc_nmgtuserfds += USER_FD_INCREMENT; 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate user_fd_mgt_array = (_svc_management_user_fd *) 2487c478bd9Sstevel@tonic-gate realloc(user_fd_mgt_array, svc_nmgtuserfds 2497c478bd9Sstevel@tonic-gate * sizeof (_svc_management_user_fd)); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate if (user_fd_mgt_array == NULL) { 2527c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "_svc_attribute_new_id: out of memory"); 2537c478bd9Sstevel@tonic-gate errno = ENOMEM; 2547c478bd9Sstevel@tonic-gate return ((svc_input_id_t)-1); 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate for (i = svc_nmgtuserfds - 1; i >= L_inOldSize; i--) 2587c478bd9Sstevel@tonic-gate _svc_free_id((svc_input_id_t)i); 2597c478bd9Sstevel@tonic-gate selected_index = (int)first_free; 2607c478bd9Sstevel@tonic-gate } 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate node->id = (svc_input_id_t)selected_index; 2637c478bd9Sstevel@tonic-gate first_free = user_fd_mgt_array[selected_index].data.next_free; 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate user_fd_mgt_array[selected_index].data.fd_node = node; 2667c478bd9Sstevel@tonic-gate user_fd_mgt_array[selected_index].free = FALSE; 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate return ((svc_input_id_t)selected_index); 2697c478bd9Sstevel@tonic-gate } 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate /* 2727c478bd9Sstevel@tonic-gate * Access to a pollfd treatment. Scan all the associated callbacks that have 2737c478bd9Sstevel@tonic-gate * at least one bit in their mask that masks a received event. 2747c478bd9Sstevel@tonic-gate * 2757c478bd9Sstevel@tonic-gate * If event POLLNVAL is received, we check that one callback processes it, if 2767c478bd9Sstevel@tonic-gate * not, then remove the file descriptor from the poll. If there is one, let 2777c478bd9Sstevel@tonic-gate * the user do the work. 2787c478bd9Sstevel@tonic-gate */ 2797c478bd9Sstevel@tonic-gate void 2807c478bd9Sstevel@tonic-gate __svc_getreq_user(struct pollfd *pfd) 2817c478bd9Sstevel@tonic-gate { 2827c478bd9Sstevel@tonic-gate int fd = pfd->fd; 2837c478bd9Sstevel@tonic-gate short revents = pfd->revents; 2847c478bd9Sstevel@tonic-gate bool_t invalHandled = FALSE; 2857c478bd9Sstevel@tonic-gate _svc_user_fd_node *node; 2867c478bd9Sstevel@tonic-gate 287*61961e0fSrobinson (void) mutex_lock(&svc_userfds_lock); 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate if ((fd < 0) || (fd >= svc_nuserfds)) { 290*61961e0fSrobinson (void) mutex_unlock(&svc_userfds_lock); 2917c478bd9Sstevel@tonic-gate return; 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate node = svc_userfds[fd].lnk.next; 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /* check if at least one mask fits */ 2977c478bd9Sstevel@tonic-gate if (0 == (revents & svc_userfds[fd].mask)) { 298*61961e0fSrobinson (void) mutex_unlock(&svc_userfds_lock); 2997c478bd9Sstevel@tonic-gate return; 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate while ((svc_userfds[fd].mask != 0) && 3037c478bd9Sstevel@tonic-gate ((_svc_user_link *)node != &(svc_userfds[fd].lnk))) { 3047c478bd9Sstevel@tonic-gate /* 3057c478bd9Sstevel@tonic-gate * If one of the received events maps the ones the node listens 3067c478bd9Sstevel@tonic-gate * to 3077c478bd9Sstevel@tonic-gate */ 3087c478bd9Sstevel@tonic-gate _svc_user_fd_node *next = node->lnk.next; 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate if (node->callback != NULL) { 3117c478bd9Sstevel@tonic-gate if (node->events & revents) { 3127c478bd9Sstevel@tonic-gate if (revents & POLLNVAL) { 3137c478bd9Sstevel@tonic-gate invalHandled = TRUE; 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate /* 3177c478bd9Sstevel@tonic-gate * The lock must be released before calling the 3187c478bd9Sstevel@tonic-gate * user function, as this function can call 3197c478bd9Sstevel@tonic-gate * svc_remove_input() for example. 3207c478bd9Sstevel@tonic-gate */ 321*61961e0fSrobinson (void) mutex_unlock(&svc_userfds_lock); 3227c478bd9Sstevel@tonic-gate node->callback(node->id, node->fd, 3237c478bd9Sstevel@tonic-gate node->events & revents, node->cookie); 3247c478bd9Sstevel@tonic-gate /* 3257c478bd9Sstevel@tonic-gate * Do not use the node structure anymore, as it 3267c478bd9Sstevel@tonic-gate * could have been deallocated by the previous 3277c478bd9Sstevel@tonic-gate * callback. 3287c478bd9Sstevel@tonic-gate */ 329*61961e0fSrobinson (void) mutex_lock(&svc_userfds_lock); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate node = next; 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate if ((revents & POLLNVAL) && !invalHandled) 3367c478bd9Sstevel@tonic-gate __svc_remove_input_of_fd(fd); 337*61961e0fSrobinson (void) mutex_unlock(&svc_userfds_lock); 3387c478bd9Sstevel@tonic-gate } 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* 3427c478bd9Sstevel@tonic-gate * Check if a file descriptor is associated with a user reactor. 3437c478bd9Sstevel@tonic-gate * To do this, just check that the array indexed on fd has a non-void linked 3447c478bd9Sstevel@tonic-gate * list (ie. first element is not NULL) 3457c478bd9Sstevel@tonic-gate */ 3467c478bd9Sstevel@tonic-gate bool_t 3477c478bd9Sstevel@tonic-gate __is_a_userfd(int fd) 3487c478bd9Sstevel@tonic-gate { 3497c478bd9Sstevel@tonic-gate /* Checks argument */ 3507c478bd9Sstevel@tonic-gate if ((fd < 0) || (fd >= svc_nuserfds)) 3517c478bd9Sstevel@tonic-gate return (FALSE); 3527c478bd9Sstevel@tonic-gate return ((svc_userfds[fd].mask == 0x0000)? FALSE:TRUE); 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate /* free everything concerning user fd */ 3567c478bd9Sstevel@tonic-gate /* used in svc_run.c => no static */ 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate void 359*61961e0fSrobinson __destroy_userfd(void) 3607c478bd9Sstevel@tonic-gate { 3617c478bd9Sstevel@tonic-gate int one_fd; 3627c478bd9Sstevel@tonic-gate /* Clean user fd */ 3637c478bd9Sstevel@tonic-gate if (svc_userfds != NULL) { 3647c478bd9Sstevel@tonic-gate for (one_fd = 0; one_fd < svc_nuserfds; one_fd++) { 3657c478bd9Sstevel@tonic-gate _svc_user_fd_node *node; 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate node = svc_userfds[one_fd].lnk.next; 3687c478bd9Sstevel@tonic-gate while ((_svc_user_link *) node 3697c478bd9Sstevel@tonic-gate != (_svc_user_link *) &(svc_userfds[one_fd])) { 3707c478bd9Sstevel@tonic-gate _svc_free_id(node->id); 3717c478bd9Sstevel@tonic-gate node = node->lnk.next; 3727c478bd9Sstevel@tonic-gate free(node->lnk.previous); 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate free(user_fd_mgt_array); 3777c478bd9Sstevel@tonic-gate user_fd_mgt_array = NULL; 3787c478bd9Sstevel@tonic-gate first_free = (svc_input_id_t)-1; 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate free(svc_userfds); 3817c478bd9Sstevel@tonic-gate svc_userfds = NULL; 3827c478bd9Sstevel@tonic-gate svc_nuserfds = 0; 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * Remove all the callback associated with a fd => useful when the fd is 3887c478bd9Sstevel@tonic-gate * closed for instance 3897c478bd9Sstevel@tonic-gate */ 3907c478bd9Sstevel@tonic-gate static void 3917c478bd9Sstevel@tonic-gate __svc_remove_input_of_fd(int fd) 3927c478bd9Sstevel@tonic-gate { 3937c478bd9Sstevel@tonic-gate _svc_user_fd_node *one_node; 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate if ((fd < 0) || (fd >= svc_nuserfds)) 3967c478bd9Sstevel@tonic-gate return; 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate one_node = svc_userfds[fd].lnk.next; 3997c478bd9Sstevel@tonic-gate while ((_svc_user_link *) one_node 4007c478bd9Sstevel@tonic-gate != (_svc_user_link *) &(svc_userfds[fd].lnk)) { 4017c478bd9Sstevel@tonic-gate _svc_free_id(one_node->id); 4027c478bd9Sstevel@tonic-gate one_node = one_node->lnk.next; 4037c478bd9Sstevel@tonic-gate free(one_node->lnk.previous); 4047c478bd9Sstevel@tonic-gate } 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate LIST_CLR(svc_userfds[fd]); 4077c478bd9Sstevel@tonic-gate svc_userfds[fd].mask = 0; 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate /* 4117c478bd9Sstevel@tonic-gate * Allow user to add an fd in the poll list. If it does not succeed, return 4127c478bd9Sstevel@tonic-gate * -1. Otherwise, return a svc_id 4137c478bd9Sstevel@tonic-gate */ 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate svc_input_id_t 4167c478bd9Sstevel@tonic-gate svc_add_input(int user_fd, unsigned int events, 4177c478bd9Sstevel@tonic-gate svc_callback_t user_callback, void *cookie) 4187c478bd9Sstevel@tonic-gate { 4197c478bd9Sstevel@tonic-gate _svc_user_fd_node *new_node; 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate if (user_fd < 0) { 4227c478bd9Sstevel@tonic-gate errno = EINVAL; 4237c478bd9Sstevel@tonic-gate return ((svc_input_id_t)-1); 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate if ((events == 0x0000) || 4277c478bd9Sstevel@tonic-gate (events & ~(POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLRDBAND|\ 4287c478bd9Sstevel@tonic-gate POLLWRBAND|POLLERR|POLLHUP|POLLNVAL))) { 4297c478bd9Sstevel@tonic-gate errno = EINVAL; 4307c478bd9Sstevel@tonic-gate return ((svc_input_id_t)-1); 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate 433*61961e0fSrobinson (void) mutex_lock(&svc_userfds_lock); 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate if ((user_fd < svc_nuserfds) && 4367c478bd9Sstevel@tonic-gate (svc_userfds[user_fd].mask & events) != 0) { 4377c478bd9Sstevel@tonic-gate /* Already registrated call-back */ 4387c478bd9Sstevel@tonic-gate errno = EEXIST; 439*61961e0fSrobinson (void) mutex_unlock(&svc_userfds_lock); 4407c478bd9Sstevel@tonic-gate return ((svc_input_id_t)-1); 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate /* Handle memory allocation. */ 4447c478bd9Sstevel@tonic-gate if (user_fd >= svc_nuserfds) { 4457c478bd9Sstevel@tonic-gate int oldSize = svc_nuserfds; 4467c478bd9Sstevel@tonic-gate int i; 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate svc_nuserfds = (user_fd + 1) + USER_FD_INCREMENT; 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate svc_userfds = (_svc_user_fd_head *) 4517c478bd9Sstevel@tonic-gate realloc(svc_userfds, 4527c478bd9Sstevel@tonic-gate svc_nuserfds * sizeof (_svc_user_fd_head)); 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate if (svc_userfds == NULL) { 4557c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "svc_add_input: out of memory"); 4567c478bd9Sstevel@tonic-gate errno = ENOMEM; 457*61961e0fSrobinson (void) mutex_unlock(&svc_userfds_lock); 4587c478bd9Sstevel@tonic-gate return ((svc_input_id_t)-1); 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate for (i = oldSize; i < svc_nuserfds; i++) { 4627c478bd9Sstevel@tonic-gate LIST_CLR(svc_userfds[i]); 4637c478bd9Sstevel@tonic-gate svc_userfds[i].mask = 0; 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate 467*61961e0fSrobinson new_node = malloc(sizeof (_svc_user_fd_node)); 4687c478bd9Sstevel@tonic-gate if (new_node == NULL) { 4697c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "svc_add_input: out of memory"); 4707c478bd9Sstevel@tonic-gate errno = ENOMEM; 471*61961e0fSrobinson (void) mutex_unlock(&svc_userfds_lock); 4727c478bd9Sstevel@tonic-gate return ((svc_input_id_t)-1); 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate /* create a new node */ 4767c478bd9Sstevel@tonic-gate new_node->fd = user_fd; 4777c478bd9Sstevel@tonic-gate new_node->events = events; 4787c478bd9Sstevel@tonic-gate new_node->callback = user_callback; 4797c478bd9Sstevel@tonic-gate new_node->cookie = cookie; 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate (void) _svc_attribute_new_id(new_node); 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate /* Add the new element at the beginning of the list. */ 4847c478bd9Sstevel@tonic-gate if (LIST_ISEMPTY(svc_userfds[user_fd])) { 4857c478bd9Sstevel@tonic-gate svc_userfds[user_fd].lnk.previous = new_node; 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate new_node->lnk.next = svc_userfds[user_fd].lnk.next; 4887c478bd9Sstevel@tonic-gate new_node->lnk.previous = (_svc_user_fd_node *)&(svc_userfds[user_fd]); 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate svc_userfds[user_fd].lnk.next = new_node; 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate /* refresh global mask for this file desciptor */ 4937c478bd9Sstevel@tonic-gate svc_userfds[user_fd].mask |= events; 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate /* refresh mask for the poll */ 4967c478bd9Sstevel@tonic-gate add_pollfd(user_fd, (svc_userfds[user_fd].mask)); 4977c478bd9Sstevel@tonic-gate 498*61961e0fSrobinson (void) mutex_unlock(&svc_userfds_lock); 4997c478bd9Sstevel@tonic-gate return (new_node->id); 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate int 5047c478bd9Sstevel@tonic-gate svc_remove_input(svc_input_id_t id) 5057c478bd9Sstevel@tonic-gate { 5067c478bd9Sstevel@tonic-gate _svc_user_fd_node* node; 5077c478bd9Sstevel@tonic-gate _svc_user_fd_node* next; 5087c478bd9Sstevel@tonic-gate _svc_user_fd_node* previous; 5097c478bd9Sstevel@tonic-gate int fd; /* caching optim */ 5107c478bd9Sstevel@tonic-gate 511*61961e0fSrobinson (void) mutex_lock(&svc_userfds_lock); 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate /* Immediately update data for id management */ 5147c478bd9Sstevel@tonic-gate if (user_fd_mgt_array == NULL || id >= svc_nmgtuserfds || 5157c478bd9Sstevel@tonic-gate is_free_id(id)) { 5167c478bd9Sstevel@tonic-gate errno = EINVAL; 517*61961e0fSrobinson (void) mutex_unlock(&svc_userfds_lock); 5187c478bd9Sstevel@tonic-gate return (-1); 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate node = node_from_id(id); 5227c478bd9Sstevel@tonic-gate assert(node != NULL); 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate _svc_free_id(id); 5257c478bd9Sstevel@tonic-gate next = node->lnk.next; 5267c478bd9Sstevel@tonic-gate previous = node->lnk.previous; 5277c478bd9Sstevel@tonic-gate fd = node->fd; /* caching optim */ 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate /* Remove this node from the list. */ 5307c478bd9Sstevel@tonic-gate previous->lnk.next = next; 5317c478bd9Sstevel@tonic-gate next->lnk.previous = previous; 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate /* Remove the node flags from the global mask */ 5347c478bd9Sstevel@tonic-gate svc_userfds[fd].mask ^= node->events; 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate free(node); 5377c478bd9Sstevel@tonic-gate if (svc_userfds[fd].mask == 0) { 5387c478bd9Sstevel@tonic-gate LIST_CLR(svc_userfds[fd]); 5397c478bd9Sstevel@tonic-gate assert(LIST_ISEMPTY(svc_userfds[fd])); 5407c478bd9Sstevel@tonic-gate remove_pollfd(fd); 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate /* <=> CLEAN NEEDED TO SHRINK MEMORY USAGE */ 5437c478bd9Sstevel@tonic-gate 544*61961e0fSrobinson (void) mutex_unlock(&svc_userfds_lock); 5457c478bd9Sstevel@tonic-gate return (0); 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate /* 5507c478bd9Sstevel@tonic-gate * Provides default service-side functions for authentication flavors 5517c478bd9Sstevel@tonic-gate * that do not use all the fields in struct svc_auth_ops. 5527c478bd9Sstevel@tonic-gate */ 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5557c478bd9Sstevel@tonic-gate static int 556*61961e0fSrobinson authany_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xfunc, caddr_t xwhere) 5577c478bd9Sstevel@tonic-gate { 5587c478bd9Sstevel@tonic-gate return (*xfunc)(xdrs, xwhere); 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate struct svc_auth_ops svc_auth_any_ops = { 5627c478bd9Sstevel@tonic-gate authany_wrap, 5637c478bd9Sstevel@tonic-gate authany_wrap, 5647c478bd9Sstevel@tonic-gate }; 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate /* 5677c478bd9Sstevel@tonic-gate * Return pointer to server authentication structure. 5687c478bd9Sstevel@tonic-gate */ 5697c478bd9Sstevel@tonic-gate SVCAUTH * 570*61961e0fSrobinson __svc_get_svcauth(SVCXPRT *xprt) 5717c478bd9Sstevel@tonic-gate { 5727c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 5737c478bd9Sstevel@tonic-gate return (&SVC_XP_AUTH(xprt)); 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate /* 5777c478bd9Sstevel@tonic-gate * A callback routine to cleanup after a procedure is executed. 5787c478bd9Sstevel@tonic-gate */ 5797c478bd9Sstevel@tonic-gate void (*__proc_cleanup_cb)() = NULL; 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate void * 582*61961e0fSrobinson __svc_set_proc_cleanup_cb(void *cb) 5837c478bd9Sstevel@tonic-gate { 5847c478bd9Sstevel@tonic-gate void *tmp = (void *)__proc_cleanup_cb; 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate __proc_cleanup_cb = (void (*)())cb; 5877c478bd9Sstevel@tonic-gate return (tmp); 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate /* *************** SVCXPRT related stuff **************** */ 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate static int pollfd_shrinking = 1; 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate /* 5977c478bd9Sstevel@tonic-gate * Add fd to svc_pollfd 5987c478bd9Sstevel@tonic-gate */ 5997c478bd9Sstevel@tonic-gate static void 6007c478bd9Sstevel@tonic-gate add_pollfd(int fd, short events) 6017c478bd9Sstevel@tonic-gate { 6027c478bd9Sstevel@tonic-gate if (fd < FD_SETSIZE) { 6037c478bd9Sstevel@tonic-gate FD_SET(fd, &svc_fdset); 6047c478bd9Sstevel@tonic-gate #if !defined(_LP64) 6057c478bd9Sstevel@tonic-gate FD_SET(fd, &_new_svc_fdset); 6067c478bd9Sstevel@tonic-gate #endif 6077c478bd9Sstevel@tonic-gate svc_nfds++; 6087c478bd9Sstevel@tonic-gate svc_nfds_set++; 6097c478bd9Sstevel@tonic-gate if (fd >= svc_max_fd) 6107c478bd9Sstevel@tonic-gate svc_max_fd = fd + 1; 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate if (fd >= svc_max_pollfd) 6137c478bd9Sstevel@tonic-gate svc_max_pollfd = fd + 1; 6147c478bd9Sstevel@tonic-gate if (svc_max_pollfd > svc_pollfd_allocd) { 6157c478bd9Sstevel@tonic-gate int i = svc_pollfd_allocd; 6167c478bd9Sstevel@tonic-gate pollfd_t *tmp; 6177c478bd9Sstevel@tonic-gate do { 6187c478bd9Sstevel@tonic-gate svc_pollfd_allocd += POLLFD_EXTEND; 6197c478bd9Sstevel@tonic-gate } while (svc_max_pollfd > svc_pollfd_allocd); 6207c478bd9Sstevel@tonic-gate tmp = realloc(svc_pollfd, 6217c478bd9Sstevel@tonic-gate sizeof (pollfd_t) * svc_pollfd_allocd); 6227c478bd9Sstevel@tonic-gate if (tmp != NULL) { 6237c478bd9Sstevel@tonic-gate svc_pollfd = tmp; 6247c478bd9Sstevel@tonic-gate for (; i < svc_pollfd_allocd; i++) 6257c478bd9Sstevel@tonic-gate POLLFD_CLR(i, tmp); 6267c478bd9Sstevel@tonic-gate } else { 6277c478bd9Sstevel@tonic-gate /* 6287c478bd9Sstevel@tonic-gate * give an error message; undo fdset setting 6297c478bd9Sstevel@tonic-gate * above; reset the pollfd_shrinking flag. 6307c478bd9Sstevel@tonic-gate * because of this poll will not be done 6317c478bd9Sstevel@tonic-gate * on these fds. 6327c478bd9Sstevel@tonic-gate */ 6337c478bd9Sstevel@tonic-gate if (fd < FD_SETSIZE) { 6347c478bd9Sstevel@tonic-gate FD_CLR(fd, &svc_fdset); 6357c478bd9Sstevel@tonic-gate #if !defined(_LP64) 6367c478bd9Sstevel@tonic-gate FD_CLR(fd, &_new_svc_fdset); 6377c478bd9Sstevel@tonic-gate #endif 6387c478bd9Sstevel@tonic-gate svc_nfds--; 6397c478bd9Sstevel@tonic-gate svc_nfds_set--; 6407c478bd9Sstevel@tonic-gate if (fd == (svc_max_fd - 1)) 6417c478bd9Sstevel@tonic-gate svc_max_fd--; 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate if (fd == (svc_max_pollfd - 1)) 6447c478bd9Sstevel@tonic-gate svc_max_pollfd--; 6457c478bd9Sstevel@tonic-gate pollfd_shrinking = 0; 6467c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "add_pollfd: out of memory"); 6477c478bd9Sstevel@tonic-gate _exit(1); 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate svc_pollfd[fd].fd = fd; 6517c478bd9Sstevel@tonic-gate svc_pollfd[fd].events = events; 6527c478bd9Sstevel@tonic-gate svc_npollfds++; 6537c478bd9Sstevel@tonic-gate svc_npollfds_set++; 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate /* 6577c478bd9Sstevel@tonic-gate * the fd is still active but only the bit in fdset is cleared. 6587c478bd9Sstevel@tonic-gate * do not subtract svc_nfds or svc_npollfds 6597c478bd9Sstevel@tonic-gate */ 6607c478bd9Sstevel@tonic-gate void 6617c478bd9Sstevel@tonic-gate clear_pollfd(int fd) 6627c478bd9Sstevel@tonic-gate { 6637c478bd9Sstevel@tonic-gate if (fd < FD_SETSIZE && FD_ISSET(fd, &svc_fdset)) { 6647c478bd9Sstevel@tonic-gate FD_CLR(fd, &svc_fdset); 6657c478bd9Sstevel@tonic-gate #if !defined(_LP64) 6667c478bd9Sstevel@tonic-gate FD_CLR(fd, &_new_svc_fdset); 6677c478bd9Sstevel@tonic-gate #endif 6687c478bd9Sstevel@tonic-gate svc_nfds_set--; 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate if (fd < svc_pollfd_allocd && POLLFD_ISSET(fd, svc_pollfd)) { 6717c478bd9Sstevel@tonic-gate POLLFD_CLR(fd, svc_pollfd); 6727c478bd9Sstevel@tonic-gate svc_npollfds_set--; 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate /* 6777c478bd9Sstevel@tonic-gate * sets the bit in fdset for an active fd so that poll() is done for that 6787c478bd9Sstevel@tonic-gate */ 6797c478bd9Sstevel@tonic-gate void 6807c478bd9Sstevel@tonic-gate set_pollfd(int fd, short events) 6817c478bd9Sstevel@tonic-gate { 6827c478bd9Sstevel@tonic-gate if (fd < FD_SETSIZE) { 6837c478bd9Sstevel@tonic-gate FD_SET(fd, &svc_fdset); 6847c478bd9Sstevel@tonic-gate #if !defined(_LP64) 6857c478bd9Sstevel@tonic-gate FD_SET(fd, &_new_svc_fdset); 6867c478bd9Sstevel@tonic-gate #endif 6877c478bd9Sstevel@tonic-gate svc_nfds_set++; 6887c478bd9Sstevel@tonic-gate } 6897c478bd9Sstevel@tonic-gate if (fd < svc_pollfd_allocd) { 6907c478bd9Sstevel@tonic-gate svc_pollfd[fd].fd = fd; 6917c478bd9Sstevel@tonic-gate svc_pollfd[fd].events = events; 6927c478bd9Sstevel@tonic-gate svc_npollfds_set++; 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate /* 6977c478bd9Sstevel@tonic-gate * remove a svc_pollfd entry; it does not shrink the memory 6987c478bd9Sstevel@tonic-gate */ 6997c478bd9Sstevel@tonic-gate static void 700*61961e0fSrobinson remove_pollfd(int fd) 7017c478bd9Sstevel@tonic-gate { 7027c478bd9Sstevel@tonic-gate clear_pollfd(fd); 7037c478bd9Sstevel@tonic-gate if (fd == (svc_max_fd - 1)) 7047c478bd9Sstevel@tonic-gate svc_max_fd--; 7057c478bd9Sstevel@tonic-gate svc_nfds--; 7067c478bd9Sstevel@tonic-gate if (fd == (svc_max_pollfd - 1)) 7077c478bd9Sstevel@tonic-gate svc_max_pollfd--; 7087c478bd9Sstevel@tonic-gate svc_npollfds--; 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate /* 7127c478bd9Sstevel@tonic-gate * delete a svc_pollfd entry; it shrinks the memory 7137c478bd9Sstevel@tonic-gate * use remove_pollfd if you do not want to shrink 7147c478bd9Sstevel@tonic-gate */ 7157c478bd9Sstevel@tonic-gate static void 7167c478bd9Sstevel@tonic-gate delete_pollfd(int fd) 7177c478bd9Sstevel@tonic-gate { 7187c478bd9Sstevel@tonic-gate remove_pollfd(fd); 7197c478bd9Sstevel@tonic-gate if (pollfd_shrinking && svc_max_pollfd < 7207c478bd9Sstevel@tonic-gate (svc_pollfd_allocd - POLLFD_SHRINK)) { 7217c478bd9Sstevel@tonic-gate do { 7227c478bd9Sstevel@tonic-gate svc_pollfd_allocd -= POLLFD_SHRINK; 7237c478bd9Sstevel@tonic-gate } while (svc_max_pollfd < (svc_pollfd_allocd - POLLFD_SHRINK)); 7247c478bd9Sstevel@tonic-gate svc_pollfd = realloc(svc_pollfd, 7257c478bd9Sstevel@tonic-gate sizeof (pollfd_t) * svc_pollfd_allocd); 7267c478bd9Sstevel@tonic-gate if (svc_pollfd == NULL) { 7277c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "delete_pollfd: out of memory"); 7287c478bd9Sstevel@tonic-gate _exit(1); 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate } 7317c478bd9Sstevel@tonic-gate } 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate /* 7357c478bd9Sstevel@tonic-gate * Activate a transport handle. 7367c478bd9Sstevel@tonic-gate */ 7377c478bd9Sstevel@tonic-gate void 738*61961e0fSrobinson xprt_register(const SVCXPRT *xprt) 7397c478bd9Sstevel@tonic-gate { 7407c478bd9Sstevel@tonic-gate int fd = xprt->xp_fd; 7417c478bd9Sstevel@tonic-gate #ifdef CALLBACK 7427c478bd9Sstevel@tonic-gate extern void (*_svc_getreqset_proc)(); 7437c478bd9Sstevel@tonic-gate #endif 7447c478bd9Sstevel@tonic-gate /* VARIABLES PROTECTED BY svc_fd_lock: svc_xports, svc_fdset */ 7457c478bd9Sstevel@tonic-gate 746*61961e0fSrobinson (void) rw_wrlock(&svc_fd_lock); 7477c478bd9Sstevel@tonic-gate if (svc_xports == NULL) { 7487c478bd9Sstevel@tonic-gate /* allocate some small amount first */ 7497c478bd9Sstevel@tonic-gate svc_xports = calloc(FD_INCREMENT, sizeof (SVCXPRT *)); 7507c478bd9Sstevel@tonic-gate if (svc_xports == NULL) { 7517c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "xprt_register: out of memory"); 7527c478bd9Sstevel@tonic-gate _exit(1); 7537c478bd9Sstevel@tonic-gate } 7547c478bd9Sstevel@tonic-gate nsvc_xports = FD_INCREMENT; 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate #ifdef CALLBACK 7577c478bd9Sstevel@tonic-gate /* 7587c478bd9Sstevel@tonic-gate * XXX: This code does not keep track of the server state. 7597c478bd9Sstevel@tonic-gate * 7607c478bd9Sstevel@tonic-gate * This provides for callback support. When a client 7617c478bd9Sstevel@tonic-gate * recv's a call from another client on the server fd's, 7627c478bd9Sstevel@tonic-gate * it calls _svc_getreqset_proc() which would return 7637c478bd9Sstevel@tonic-gate * after serving all the server requests. Also look under 7647c478bd9Sstevel@tonic-gate * clnt_dg.c and clnt_vc.c (clnt_call part of it) 7657c478bd9Sstevel@tonic-gate */ 7667c478bd9Sstevel@tonic-gate _svc_getreqset_proc = svc_getreq_poll; 7677c478bd9Sstevel@tonic-gate #endif 7687c478bd9Sstevel@tonic-gate } 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate while (fd >= nsvc_xports) { 7717c478bd9Sstevel@tonic-gate SVCXPRT **tmp_xprts = svc_xports; 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate /* time to expand svc_xprts */ 7747c478bd9Sstevel@tonic-gate tmp_xprts = realloc(svc_xports, 7757c478bd9Sstevel@tonic-gate sizeof (SVCXPRT *) * (nsvc_xports + FD_INCREMENT)); 7767c478bd9Sstevel@tonic-gate if (tmp_xprts == NULL) { 7777c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "xprt_register : out of memory."); 7787c478bd9Sstevel@tonic-gate _exit(1); 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate svc_xports = tmp_xprts; 7827c478bd9Sstevel@tonic-gate (void) memset(&svc_xports[nsvc_xports], 0, 7837c478bd9Sstevel@tonic-gate sizeof (SVCXPRT *) * FD_INCREMENT); 7847c478bd9Sstevel@tonic-gate nsvc_xports += FD_INCREMENT; 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate svc_xports[fd] = (SVCXPRT *)xprt; 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate add_pollfd(fd, MASKVAL); 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate if (svc_polling) { 7927c478bd9Sstevel@tonic-gate char dummy; 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate /* 7957c478bd9Sstevel@tonic-gate * This happens only in one of the MT modes. 7967c478bd9Sstevel@tonic-gate * Wake up poller. 7977c478bd9Sstevel@tonic-gate */ 798*61961e0fSrobinson (void) write(svc_pipe[1], &dummy, sizeof (dummy)); 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate /* 8017c478bd9Sstevel@tonic-gate * If already dispatching door based services, start 8027c478bd9Sstevel@tonic-gate * dispatching TLI based services now. 8037c478bd9Sstevel@tonic-gate */ 804*61961e0fSrobinson (void) mutex_lock(&svc_door_mutex); 8057c478bd9Sstevel@tonic-gate if (svc_ndoorfds > 0) 806*61961e0fSrobinson (void) cond_signal(&svc_door_waitcv); 807*61961e0fSrobinson (void) mutex_unlock(&svc_door_mutex); 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate if (svc_xdrs == NULL) { 8107c478bd9Sstevel@tonic-gate /* allocate initial chunk */ 8117c478bd9Sstevel@tonic-gate svc_xdrs = calloc(FD_INCREMENT, sizeof (XDR *)); 8127c478bd9Sstevel@tonic-gate if (svc_xdrs != NULL) 8137c478bd9Sstevel@tonic-gate nsvc_xdrs = FD_INCREMENT; 8147c478bd9Sstevel@tonic-gate else { 8157c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "xprt_register : out of memory."); 8167c478bd9Sstevel@tonic-gate _exit(1); 8177c478bd9Sstevel@tonic-gate } 8187c478bd9Sstevel@tonic-gate } 819*61961e0fSrobinson (void) rw_unlock(&svc_fd_lock); 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate /* 8237c478bd9Sstevel@tonic-gate * De-activate a transport handle. 8247c478bd9Sstevel@tonic-gate */ 8257c478bd9Sstevel@tonic-gate void 8267c478bd9Sstevel@tonic-gate __xprt_unregister_private(const SVCXPRT *xprt, bool_t lock_not_held) 8277c478bd9Sstevel@tonic-gate { 8287c478bd9Sstevel@tonic-gate int fd = xprt->xp_fd; 8297c478bd9Sstevel@tonic-gate 8307c478bd9Sstevel@tonic-gate if (lock_not_held) 831*61961e0fSrobinson (void) rw_wrlock(&svc_fd_lock); 8327c478bd9Sstevel@tonic-gate if ((fd < nsvc_xports) && (svc_xports[fd] == xprt)) { 833*61961e0fSrobinson svc_xports[fd] = NULL; 8347c478bd9Sstevel@tonic-gate delete_pollfd(fd); 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate if (lock_not_held) 837*61961e0fSrobinson (void) rw_unlock(&svc_fd_lock); 8387c478bd9Sstevel@tonic-gate __svc_rm_from_xlist(&_svc_xprtlist, xprt, &xprtlist_lock); 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate void 842*61961e0fSrobinson xprt_unregister(const SVCXPRT *xprt) 8437c478bd9Sstevel@tonic-gate { 8447c478bd9Sstevel@tonic-gate __xprt_unregister_private(xprt, TRUE); 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate /* ********************** CALLOUT list related stuff ************* */ 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate /* 8507c478bd9Sstevel@tonic-gate * Add a service program to the callout list. 8517c478bd9Sstevel@tonic-gate * The dispatch routine will be called when a rpc request for this 8527c478bd9Sstevel@tonic-gate * program number comes in. 8537c478bd9Sstevel@tonic-gate */ 8547c478bd9Sstevel@tonic-gate bool_t 855*61961e0fSrobinson svc_reg(const SVCXPRT *xprt, const rpcprog_t prog, const rpcvers_t vers, 856*61961e0fSrobinson void (*dispatch)(), const struct netconfig *nconf) 8577c478bd9Sstevel@tonic-gate { 8587c478bd9Sstevel@tonic-gate struct svc_callout *prev; 8597c478bd9Sstevel@tonic-gate struct svc_callout *s, **s2; 8607c478bd9Sstevel@tonic-gate struct netconfig *tnconf; 8617c478bd9Sstevel@tonic-gate char *netid = NULL; 8627c478bd9Sstevel@tonic-gate int flag = 0; 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate /* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */ 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate if (xprt->xp_netid) { 8677c478bd9Sstevel@tonic-gate netid = strdup(xprt->xp_netid); 8687c478bd9Sstevel@tonic-gate flag = 1; 8697c478bd9Sstevel@tonic-gate } else if (nconf && nconf->nc_netid) { 8707c478bd9Sstevel@tonic-gate netid = strdup(nconf->nc_netid); 8717c478bd9Sstevel@tonic-gate flag = 1; 8727c478bd9Sstevel@tonic-gate } else if ((tnconf = __rpcfd_to_nconf(xprt->xp_fd, xprt->xp_type)) 8737c478bd9Sstevel@tonic-gate != NULL) { 8747c478bd9Sstevel@tonic-gate netid = strdup(tnconf->nc_netid); 8757c478bd9Sstevel@tonic-gate flag = 1; 8767c478bd9Sstevel@tonic-gate freenetconfigent(tnconf); 8777c478bd9Sstevel@tonic-gate } /* must have been created with svc_raw_create */ 878*61961e0fSrobinson if ((netid == NULL) && (flag == 1)) 8797c478bd9Sstevel@tonic-gate return (FALSE); 8807c478bd9Sstevel@tonic-gate 881*61961e0fSrobinson (void) rw_wrlock(&svc_lock); 8827c478bd9Sstevel@tonic-gate if ((s = svc_find(prog, vers, &prev, netid)) != NULL_SVC) { 8837c478bd9Sstevel@tonic-gate if (netid) 8847c478bd9Sstevel@tonic-gate free(netid); 8857c478bd9Sstevel@tonic-gate if (s->sc_dispatch == dispatch) 8867c478bd9Sstevel@tonic-gate goto rpcb_it; /* he is registering another xptr */ 887*61961e0fSrobinson (void) rw_unlock(&svc_lock); 8887c478bd9Sstevel@tonic-gate return (FALSE); 8897c478bd9Sstevel@tonic-gate } 890*61961e0fSrobinson s = malloc(sizeof (struct svc_callout)); 891*61961e0fSrobinson if (s == NULL) { 8927c478bd9Sstevel@tonic-gate if (netid) 8937c478bd9Sstevel@tonic-gate free(netid); 894*61961e0fSrobinson (void) rw_unlock(&svc_lock); 8957c478bd9Sstevel@tonic-gate return (FALSE); 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate s->sc_prog = prog; 8997c478bd9Sstevel@tonic-gate s->sc_vers = vers; 9007c478bd9Sstevel@tonic-gate s->sc_dispatch = dispatch; 9017c478bd9Sstevel@tonic-gate s->sc_netid = netid; 9027c478bd9Sstevel@tonic-gate s->sc_next = NULL; 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate /* 9057c478bd9Sstevel@tonic-gate * The ordering of transports is such that the most frequently used 9067c478bd9Sstevel@tonic-gate * one appears first. So add the new entry to the end of the list. 9077c478bd9Sstevel@tonic-gate */ 9087c478bd9Sstevel@tonic-gate for (s2 = &svc_head; *s2 != NULL; s2 = &(*s2)->sc_next) 9097c478bd9Sstevel@tonic-gate ; 9107c478bd9Sstevel@tonic-gate *s2 = s; 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate if ((xprt->xp_netid == NULL) && (flag == 1) && netid) 9137c478bd9Sstevel@tonic-gate if ((((SVCXPRT *)xprt)->xp_netid = strdup(netid)) == NULL) { 9147c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "svc_reg : strdup failed."); 9157c478bd9Sstevel@tonic-gate free(netid); 916*61961e0fSrobinson free(s); 9177c478bd9Sstevel@tonic-gate *s2 = NULL; 918*61961e0fSrobinson (void) rw_unlock(&svc_lock); 9197c478bd9Sstevel@tonic-gate return (FALSE); 9207c478bd9Sstevel@tonic-gate } 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate rpcb_it: 923*61961e0fSrobinson (void) rw_unlock(&svc_lock); 9247c478bd9Sstevel@tonic-gate /* now register the information with the local binder service */ 925*61961e0fSrobinson if (nconf) 926*61961e0fSrobinson return (rpcb_set(prog, vers, nconf, &xprt->xp_ltaddr)); 9277c478bd9Sstevel@tonic-gate return (TRUE); 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate /* 9317c478bd9Sstevel@tonic-gate * Remove a service program from the callout list. 9327c478bd9Sstevel@tonic-gate */ 9337c478bd9Sstevel@tonic-gate void 934*61961e0fSrobinson svc_unreg(const rpcprog_t prog, const rpcvers_t vers) 9357c478bd9Sstevel@tonic-gate { 9367c478bd9Sstevel@tonic-gate struct svc_callout *prev; 9377c478bd9Sstevel@tonic-gate struct svc_callout *s; 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate /* unregister the information anyway */ 9407c478bd9Sstevel@tonic-gate (void) rpcb_unset(prog, vers, NULL); 941*61961e0fSrobinson (void) rw_wrlock(&svc_lock); 9427c478bd9Sstevel@tonic-gate while ((s = svc_find(prog, vers, &prev, NULL)) != NULL_SVC) { 9437c478bd9Sstevel@tonic-gate if (prev == NULL_SVC) { 9447c478bd9Sstevel@tonic-gate svc_head = s->sc_next; 9457c478bd9Sstevel@tonic-gate } else { 9467c478bd9Sstevel@tonic-gate prev->sc_next = s->sc_next; 9477c478bd9Sstevel@tonic-gate } 9487c478bd9Sstevel@tonic-gate s->sc_next = NULL_SVC; 9497c478bd9Sstevel@tonic-gate if (s->sc_netid) 950*61961e0fSrobinson free(s->sc_netid); 951*61961e0fSrobinson free(s); 9527c478bd9Sstevel@tonic-gate } 953*61961e0fSrobinson (void) rw_unlock(&svc_lock); 9547c478bd9Sstevel@tonic-gate } 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate #ifdef PORTMAP 9577c478bd9Sstevel@tonic-gate /* 9587c478bd9Sstevel@tonic-gate * Add a service program to the callout list. 9597c478bd9Sstevel@tonic-gate * The dispatch routine will be called when a rpc request for this 9607c478bd9Sstevel@tonic-gate * program number comes in. 9617c478bd9Sstevel@tonic-gate * For version 2 portmappers. 9627c478bd9Sstevel@tonic-gate */ 9637c478bd9Sstevel@tonic-gate bool_t 964*61961e0fSrobinson svc_register(SVCXPRT *xprt, rpcprog_t prog, rpcvers_t vers, 965*61961e0fSrobinson void (*dispatch)(), int protocol) 9667c478bd9Sstevel@tonic-gate { 9677c478bd9Sstevel@tonic-gate struct svc_callout *prev; 9687c478bd9Sstevel@tonic-gate struct svc_callout *s; 9697c478bd9Sstevel@tonic-gate struct netconfig *nconf; 9707c478bd9Sstevel@tonic-gate char *netid = NULL; 9717c478bd9Sstevel@tonic-gate int flag = 0; 9727c478bd9Sstevel@tonic-gate 9737c478bd9Sstevel@tonic-gate if (xprt->xp_netid) { 9747c478bd9Sstevel@tonic-gate netid = strdup(xprt->xp_netid); 9757c478bd9Sstevel@tonic-gate flag = 1; 9767c478bd9Sstevel@tonic-gate } else if ((ioctl(xprt->xp_fd, I_FIND, "timod") > 0) && ((nconf = 9777c478bd9Sstevel@tonic-gate __rpcfd_to_nconf(xprt->xp_fd, xprt->xp_type)) != NULL)) { 9787c478bd9Sstevel@tonic-gate /* fill in missing netid field in SVCXPRT */ 9797c478bd9Sstevel@tonic-gate netid = strdup(nconf->nc_netid); 9807c478bd9Sstevel@tonic-gate flag = 1; 9817c478bd9Sstevel@tonic-gate freenetconfigent(nconf); 9827c478bd9Sstevel@tonic-gate } /* must be svc_raw_create */ 9837c478bd9Sstevel@tonic-gate 984*61961e0fSrobinson if ((netid == NULL) && (flag == 1)) 9857c478bd9Sstevel@tonic-gate return (FALSE); 9867c478bd9Sstevel@tonic-gate 987*61961e0fSrobinson (void) rw_wrlock(&svc_lock); 9887c478bd9Sstevel@tonic-gate if ((s = svc_find(prog, vers, &prev, netid)) != NULL_SVC) { 9897c478bd9Sstevel@tonic-gate if (netid) 9907c478bd9Sstevel@tonic-gate free(netid); 9917c478bd9Sstevel@tonic-gate if (s->sc_dispatch == dispatch) 9927c478bd9Sstevel@tonic-gate goto pmap_it; /* he is registering another xptr */ 993*61961e0fSrobinson (void) rw_unlock(&svc_lock); 9947c478bd9Sstevel@tonic-gate return (FALSE); 9957c478bd9Sstevel@tonic-gate } 996*61961e0fSrobinson s = malloc(sizeof (struct svc_callout)); 9977c478bd9Sstevel@tonic-gate if (s == (struct svc_callout *)0) { 9987c478bd9Sstevel@tonic-gate if (netid) 9997c478bd9Sstevel@tonic-gate free(netid); 1000*61961e0fSrobinson (void) rw_unlock(&svc_lock); 10017c478bd9Sstevel@tonic-gate return (FALSE); 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate s->sc_prog = prog; 10047c478bd9Sstevel@tonic-gate s->sc_vers = vers; 10057c478bd9Sstevel@tonic-gate s->sc_dispatch = dispatch; 10067c478bd9Sstevel@tonic-gate s->sc_netid = netid; 10077c478bd9Sstevel@tonic-gate s->sc_next = svc_head; 10087c478bd9Sstevel@tonic-gate svc_head = s; 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate if ((xprt->xp_netid == NULL) && (flag == 1) && netid) 10117c478bd9Sstevel@tonic-gate if ((xprt->xp_netid = strdup(netid)) == NULL) { 10127c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "svc_register : strdup failed."); 10137c478bd9Sstevel@tonic-gate free(netid); 10147c478bd9Sstevel@tonic-gate svc_head = s->sc_next; 1015*61961e0fSrobinson free(s); 1016*61961e0fSrobinson (void) rw_unlock(&svc_lock); 10177c478bd9Sstevel@tonic-gate return (FALSE); 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate pmap_it: 1021*61961e0fSrobinson (void) rw_unlock(&svc_lock); 10227c478bd9Sstevel@tonic-gate /* now register the information with the local binder service */ 1023*61961e0fSrobinson if (protocol) 1024*61961e0fSrobinson return (pmap_set(prog, vers, protocol, xprt->xp_port)); 10257c478bd9Sstevel@tonic-gate return (TRUE); 10267c478bd9Sstevel@tonic-gate } 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate /* 10297c478bd9Sstevel@tonic-gate * Remove a service program from the callout list. 10307c478bd9Sstevel@tonic-gate * For version 2 portmappers. 10317c478bd9Sstevel@tonic-gate */ 10327c478bd9Sstevel@tonic-gate void 1033*61961e0fSrobinson svc_unregister(rpcprog_t prog, rpcvers_t vers) 10347c478bd9Sstevel@tonic-gate { 10357c478bd9Sstevel@tonic-gate struct svc_callout *prev; 10367c478bd9Sstevel@tonic-gate struct svc_callout *s; 10377c478bd9Sstevel@tonic-gate 1038*61961e0fSrobinson (void) rw_wrlock(&svc_lock); 10397c478bd9Sstevel@tonic-gate while ((s = svc_find(prog, vers, &prev, NULL)) != NULL_SVC) { 10407c478bd9Sstevel@tonic-gate if (prev == NULL_SVC) { 10417c478bd9Sstevel@tonic-gate svc_head = s->sc_next; 10427c478bd9Sstevel@tonic-gate } else { 10437c478bd9Sstevel@tonic-gate prev->sc_next = s->sc_next; 10447c478bd9Sstevel@tonic-gate } 10457c478bd9Sstevel@tonic-gate s->sc_next = NULL_SVC; 10467c478bd9Sstevel@tonic-gate if (s->sc_netid) 1047*61961e0fSrobinson free(s->sc_netid); 1048*61961e0fSrobinson free(s); 10497c478bd9Sstevel@tonic-gate /* unregister the information with the local binder service */ 10507c478bd9Sstevel@tonic-gate (void) pmap_unset(prog, vers); 10517c478bd9Sstevel@tonic-gate } 1052*61961e0fSrobinson (void) rw_unlock(&svc_lock); 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate #endif /* PORTMAP */ 1055*61961e0fSrobinson 10567c478bd9Sstevel@tonic-gate /* 10577c478bd9Sstevel@tonic-gate * Search the callout list for a program number, return the callout 10587c478bd9Sstevel@tonic-gate * struct. 10597c478bd9Sstevel@tonic-gate * Also check for transport as well. Many routines such as svc_unreg 10607c478bd9Sstevel@tonic-gate * dont give any corresponding transport, so dont check for transport if 10617c478bd9Sstevel@tonic-gate * netid == NULL 10627c478bd9Sstevel@tonic-gate */ 10637c478bd9Sstevel@tonic-gate static struct svc_callout * 1064*61961e0fSrobinson svc_find(rpcprog_t prog, rpcvers_t vers, struct svc_callout **prev, char *netid) 10657c478bd9Sstevel@tonic-gate { 10667c478bd9Sstevel@tonic-gate struct svc_callout *s, *p; 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate /* WRITE LOCK HELD ON ENTRY: svc_lock */ 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate /* assert(RW_WRITE_HELD(&svc_lock)); */ 10717c478bd9Sstevel@tonic-gate p = NULL_SVC; 10727c478bd9Sstevel@tonic-gate for (s = svc_head; s != NULL_SVC; s = s->sc_next) { 10737c478bd9Sstevel@tonic-gate if (((s->sc_prog == prog) && (s->sc_vers == vers)) && 10747c478bd9Sstevel@tonic-gate ((netid == NULL) || (s->sc_netid == NULL) || 10757c478bd9Sstevel@tonic-gate (strcmp(netid, s->sc_netid) == 0))) 10767c478bd9Sstevel@tonic-gate break; 10777c478bd9Sstevel@tonic-gate p = s; 10787c478bd9Sstevel@tonic-gate } 10797c478bd9Sstevel@tonic-gate *prev = p; 10807c478bd9Sstevel@tonic-gate return (s); 10817c478bd9Sstevel@tonic-gate } 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate /* ******************* REPLY GENERATION ROUTINES ************ */ 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate /* 10877c478bd9Sstevel@tonic-gate * Send a reply to an rpc request 10887c478bd9Sstevel@tonic-gate */ 10897c478bd9Sstevel@tonic-gate bool_t 1090*61961e0fSrobinson svc_sendreply(const SVCXPRT *xprt, const xdrproc_t xdr_results, 1091*61961e0fSrobinson const caddr_t xdr_location) 10927c478bd9Sstevel@tonic-gate { 10937c478bd9Sstevel@tonic-gate struct rpc_msg rply; 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate rply.rm_direction = REPLY; 10967c478bd9Sstevel@tonic-gate rply.rm_reply.rp_stat = MSG_ACCEPTED; 10977c478bd9Sstevel@tonic-gate rply.acpted_rply.ar_verf = xprt->xp_verf; 10987c478bd9Sstevel@tonic-gate rply.acpted_rply.ar_stat = SUCCESS; 10997c478bd9Sstevel@tonic-gate rply.acpted_rply.ar_results.where = xdr_location; 11007c478bd9Sstevel@tonic-gate rply.acpted_rply.ar_results.proc = xdr_results; 1101*61961e0fSrobinson return (SVC_REPLY((SVCXPRT *)xprt, &rply)); 11027c478bd9Sstevel@tonic-gate } 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate /* 11057c478bd9Sstevel@tonic-gate * No procedure error reply 11067c478bd9Sstevel@tonic-gate */ 11077c478bd9Sstevel@tonic-gate void 1108*61961e0fSrobinson svcerr_noproc(const SVCXPRT *xprt) 11097c478bd9Sstevel@tonic-gate { 11107c478bd9Sstevel@tonic-gate struct rpc_msg rply; 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate rply.rm_direction = REPLY; 11137c478bd9Sstevel@tonic-gate rply.rm_reply.rp_stat = MSG_ACCEPTED; 11147c478bd9Sstevel@tonic-gate rply.acpted_rply.ar_verf = xprt->xp_verf; 11157c478bd9Sstevel@tonic-gate rply.acpted_rply.ar_stat = PROC_UNAVAIL; 11167c478bd9Sstevel@tonic-gate SVC_REPLY((SVCXPRT *)xprt, &rply); 11177c478bd9Sstevel@tonic-gate } 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate /* 11207c478bd9Sstevel@tonic-gate * Can't decode args error reply 11217c478bd9Sstevel@tonic-gate */ 11227c478bd9Sstevel@tonic-gate void 1123*61961e0fSrobinson svcerr_decode(const SVCXPRT *xprt) 11247c478bd9Sstevel@tonic-gate { 11257c478bd9Sstevel@tonic-gate struct rpc_msg rply; 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate rply.rm_direction = REPLY; 11287c478bd9Sstevel@tonic-gate rply.rm_reply.rp_stat = MSG_ACCEPTED; 11297c478bd9Sstevel@tonic-gate rply.acpted_rply.ar_verf = xprt->xp_verf; 11307c478bd9Sstevel@tonic-gate rply.acpted_rply.ar_stat = GARBAGE_ARGS; 11317c478bd9Sstevel@tonic-gate SVC_REPLY((SVCXPRT *)xprt, &rply); 11327c478bd9Sstevel@tonic-gate } 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate /* 11357c478bd9Sstevel@tonic-gate * Some system error 11367c478bd9Sstevel@tonic-gate */ 11377c478bd9Sstevel@tonic-gate void 1138*61961e0fSrobinson svcerr_systemerr(const SVCXPRT *xprt) 11397c478bd9Sstevel@tonic-gate { 11407c478bd9Sstevel@tonic-gate struct rpc_msg rply; 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate rply.rm_direction = REPLY; 11437c478bd9Sstevel@tonic-gate rply.rm_reply.rp_stat = MSG_ACCEPTED; 11447c478bd9Sstevel@tonic-gate rply.acpted_rply.ar_verf = xprt->xp_verf; 11457c478bd9Sstevel@tonic-gate rply.acpted_rply.ar_stat = SYSTEM_ERR; 11467c478bd9Sstevel@tonic-gate SVC_REPLY((SVCXPRT *)xprt, &rply); 11477c478bd9Sstevel@tonic-gate } 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate /* 11507c478bd9Sstevel@tonic-gate * Tell RPC package to not complain about version errors to the client. This 11517c478bd9Sstevel@tonic-gate * is useful when revving broadcast protocols that sit on a fixed address. 11527c478bd9Sstevel@tonic-gate * There is really one (or should be only one) example of this kind of 11537c478bd9Sstevel@tonic-gate * protocol: the portmapper (or rpc binder). 11547c478bd9Sstevel@tonic-gate */ 11557c478bd9Sstevel@tonic-gate void 1156*61961e0fSrobinson __svc_versquiet_on(const SVCXPRT *xprt) 11577c478bd9Sstevel@tonic-gate { 11587c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 11597c478bd9Sstevel@tonic-gate svc_flags(xprt) |= SVC_VERSQUIET; 11607c478bd9Sstevel@tonic-gate } 11617c478bd9Sstevel@tonic-gate 11627c478bd9Sstevel@tonic-gate void 1163*61961e0fSrobinson __svc_versquiet_off(const SVCXPRT *xprt) 11647c478bd9Sstevel@tonic-gate { 11657c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 11667c478bd9Sstevel@tonic-gate svc_flags(xprt) &= ~SVC_VERSQUIET; 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate void 1170*61961e0fSrobinson svc_versquiet(const SVCXPRT *xprt) 11717c478bd9Sstevel@tonic-gate { 11727c478bd9Sstevel@tonic-gate __svc_versquiet_on(xprt); 11737c478bd9Sstevel@tonic-gate } 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate int 1176*61961e0fSrobinson __svc_versquiet_get(const SVCXPRT *xprt) 11777c478bd9Sstevel@tonic-gate { 11787c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 11797c478bd9Sstevel@tonic-gate return (svc_flags(xprt) & SVC_VERSQUIET); 11807c478bd9Sstevel@tonic-gate } 11817c478bd9Sstevel@tonic-gate 11827c478bd9Sstevel@tonic-gate /* 11837c478bd9Sstevel@tonic-gate * Authentication error reply 11847c478bd9Sstevel@tonic-gate */ 11857c478bd9Sstevel@tonic-gate void 1186*61961e0fSrobinson svcerr_auth(const SVCXPRT *xprt, const enum auth_stat why) 11877c478bd9Sstevel@tonic-gate { 11887c478bd9Sstevel@tonic-gate struct rpc_msg rply; 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate rply.rm_direction = REPLY; 11917c478bd9Sstevel@tonic-gate rply.rm_reply.rp_stat = MSG_DENIED; 11927c478bd9Sstevel@tonic-gate rply.rjcted_rply.rj_stat = AUTH_ERROR; 11937c478bd9Sstevel@tonic-gate rply.rjcted_rply.rj_why = why; 11947c478bd9Sstevel@tonic-gate SVC_REPLY((SVCXPRT *)xprt, &rply); 11957c478bd9Sstevel@tonic-gate } 11967c478bd9Sstevel@tonic-gate 11977c478bd9Sstevel@tonic-gate /* 11987c478bd9Sstevel@tonic-gate * Auth too weak error reply 11997c478bd9Sstevel@tonic-gate */ 12007c478bd9Sstevel@tonic-gate void 1201*61961e0fSrobinson svcerr_weakauth(const SVCXPRT *xprt) 12027c478bd9Sstevel@tonic-gate { 12037c478bd9Sstevel@tonic-gate svcerr_auth(xprt, AUTH_TOOWEAK); 12047c478bd9Sstevel@tonic-gate } 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate /* 12077c478bd9Sstevel@tonic-gate * Program unavailable error reply 12087c478bd9Sstevel@tonic-gate */ 12097c478bd9Sstevel@tonic-gate void 1210*61961e0fSrobinson svcerr_noprog(const SVCXPRT *xprt) 12117c478bd9Sstevel@tonic-gate { 12127c478bd9Sstevel@tonic-gate struct rpc_msg rply; 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate rply.rm_direction = REPLY; 12157c478bd9Sstevel@tonic-gate rply.rm_reply.rp_stat = MSG_ACCEPTED; 12167c478bd9Sstevel@tonic-gate rply.acpted_rply.ar_verf = xprt->xp_verf; 12177c478bd9Sstevel@tonic-gate rply.acpted_rply.ar_stat = PROG_UNAVAIL; 12187c478bd9Sstevel@tonic-gate SVC_REPLY((SVCXPRT *)xprt, &rply); 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate /* 12227c478bd9Sstevel@tonic-gate * Program version mismatch error reply 12237c478bd9Sstevel@tonic-gate */ 12247c478bd9Sstevel@tonic-gate void 1225*61961e0fSrobinson svcerr_progvers(const SVCXPRT *xprt, const rpcvers_t low_vers, 1226*61961e0fSrobinson const rpcvers_t high_vers) 12277c478bd9Sstevel@tonic-gate { 12287c478bd9Sstevel@tonic-gate struct rpc_msg rply; 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate rply.rm_direction = REPLY; 12317c478bd9Sstevel@tonic-gate rply.rm_reply.rp_stat = MSG_ACCEPTED; 12327c478bd9Sstevel@tonic-gate rply.acpted_rply.ar_verf = xprt->xp_verf; 12337c478bd9Sstevel@tonic-gate rply.acpted_rply.ar_stat = PROG_MISMATCH; 12347c478bd9Sstevel@tonic-gate rply.acpted_rply.ar_vers.low = low_vers; 12357c478bd9Sstevel@tonic-gate rply.acpted_rply.ar_vers.high = high_vers; 12367c478bd9Sstevel@tonic-gate SVC_REPLY((SVCXPRT *)xprt, &rply); 12377c478bd9Sstevel@tonic-gate } 12387c478bd9Sstevel@tonic-gate 12397c478bd9Sstevel@tonic-gate /* ******************* SERVER INPUT STUFF ******************* */ 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate /* 12427c478bd9Sstevel@tonic-gate * Get server side input from some transport. 12437c478bd9Sstevel@tonic-gate * 12447c478bd9Sstevel@tonic-gate * Statement of authentication parameters management: 12457c478bd9Sstevel@tonic-gate * This function owns and manages all authentication parameters, specifically 12467c478bd9Sstevel@tonic-gate * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and 12477c478bd9Sstevel@tonic-gate * the "cooked" credentials (rqst->rq_clntcred). 12487c478bd9Sstevel@tonic-gate * However, this function does not know the structure of the cooked 12497c478bd9Sstevel@tonic-gate * credentials, so it make the following assumptions: 12507c478bd9Sstevel@tonic-gate * a) the structure is contiguous (no pointers), and 12517c478bd9Sstevel@tonic-gate * b) the cred structure size does not exceed RQCRED_SIZE bytes. 12527c478bd9Sstevel@tonic-gate * In all events, all three parameters are freed upon exit from this routine. 12537c478bd9Sstevel@tonic-gate * The storage is trivially management on the call stack in user land, but 12547c478bd9Sstevel@tonic-gate * is mallocated in kernel land. 12557c478bd9Sstevel@tonic-gate */ 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate void 1258*61961e0fSrobinson svc_getreq(int rdfds) 12597c478bd9Sstevel@tonic-gate { 12607c478bd9Sstevel@tonic-gate fd_set readfds; 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate FD_ZERO(&readfds); 12637c478bd9Sstevel@tonic-gate readfds.fds_bits[0] = rdfds; 12647c478bd9Sstevel@tonic-gate svc_getreqset(&readfds); 12657c478bd9Sstevel@tonic-gate } 12667c478bd9Sstevel@tonic-gate 12677c478bd9Sstevel@tonic-gate void 1268*61961e0fSrobinson svc_getreqset(fd_set *readfds) 12697c478bd9Sstevel@tonic-gate { 12707c478bd9Sstevel@tonic-gate int i; 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate for (i = 0; i < svc_max_fd; i++) { 12737c478bd9Sstevel@tonic-gate /* fd has input waiting */ 12747c478bd9Sstevel@tonic-gate if (FD_ISSET(i, readfds)) 12757c478bd9Sstevel@tonic-gate svc_getreq_common(i); 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate } 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate void 1280*61961e0fSrobinson svc_getreq_poll(struct pollfd *pfdp, const int pollretval) 12817c478bd9Sstevel@tonic-gate { 12827c478bd9Sstevel@tonic-gate int i; 12837c478bd9Sstevel@tonic-gate int fds_found; 12847c478bd9Sstevel@tonic-gate 12857c478bd9Sstevel@tonic-gate for (i = fds_found = 0; fds_found < pollretval; i++) { 12867c478bd9Sstevel@tonic-gate struct pollfd *p = &pfdp[i]; 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate if (p->revents) { 12897c478bd9Sstevel@tonic-gate /* fd has input waiting */ 12907c478bd9Sstevel@tonic-gate fds_found++; 12917c478bd9Sstevel@tonic-gate /* 12927c478bd9Sstevel@tonic-gate * We assume that this function is only called 12937c478bd9Sstevel@tonic-gate * via someone select()ing from svc_fdset or 12947c478bd9Sstevel@tonic-gate * poll()ing from svc_pollset[]. Thus it's safe 12957c478bd9Sstevel@tonic-gate * to handle the POLLNVAL event by simply turning 12967c478bd9Sstevel@tonic-gate * the corresponding bit off in svc_fdset. The 12977c478bd9Sstevel@tonic-gate * svc_pollset[] array is derived from svc_fdset 12987c478bd9Sstevel@tonic-gate * and so will also be updated eventually. 12997c478bd9Sstevel@tonic-gate * 13007c478bd9Sstevel@tonic-gate * XXX Should we do an xprt_unregister() instead? 13017c478bd9Sstevel@tonic-gate */ 13027c478bd9Sstevel@tonic-gate /* Handle user callback */ 13037c478bd9Sstevel@tonic-gate if (__is_a_userfd(p->fd) == TRUE) { 1304*61961e0fSrobinson (void) rw_rdlock(&svc_fd_lock); 13057c478bd9Sstevel@tonic-gate __svc_getreq_user(p); 1306*61961e0fSrobinson (void) rw_unlock(&svc_fd_lock); 13077c478bd9Sstevel@tonic-gate } else { 13087c478bd9Sstevel@tonic-gate if (p->revents & POLLNVAL) { 1309*61961e0fSrobinson (void) rw_wrlock(&svc_fd_lock); 13107c478bd9Sstevel@tonic-gate remove_pollfd(p->fd); /* XXX */ 1311*61961e0fSrobinson (void) rw_unlock(&svc_fd_lock); 1312*61961e0fSrobinson } else { 13137c478bd9Sstevel@tonic-gate svc_getreq_common(p->fd); 13147c478bd9Sstevel@tonic-gate } 13157c478bd9Sstevel@tonic-gate } 13167c478bd9Sstevel@tonic-gate } 1317*61961e0fSrobinson } 13187c478bd9Sstevel@tonic-gate } 13197c478bd9Sstevel@tonic-gate 13207c478bd9Sstevel@tonic-gate void 1321*61961e0fSrobinson svc_getreq_common(const int fd) 13227c478bd9Sstevel@tonic-gate { 13237c478bd9Sstevel@tonic-gate SVCXPRT *xprt; 13247c478bd9Sstevel@tonic-gate enum xprt_stat stat; 13257c478bd9Sstevel@tonic-gate struct rpc_msg *msg; 13267c478bd9Sstevel@tonic-gate struct svc_req *r; 13277c478bd9Sstevel@tonic-gate char *cred_area; 13287c478bd9Sstevel@tonic-gate 1329*61961e0fSrobinson (void) rw_rdlock(&svc_fd_lock); 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate /* HANDLE USER CALLBACK */ 13327c478bd9Sstevel@tonic-gate if (__is_a_userfd(fd) == TRUE) { 13337c478bd9Sstevel@tonic-gate struct pollfd virtual_fd; 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate virtual_fd.events = virtual_fd.revents = (short)0xFFFF; 13367c478bd9Sstevel@tonic-gate virtual_fd.fd = fd; 13377c478bd9Sstevel@tonic-gate __svc_getreq_user(&virtual_fd); 1338*61961e0fSrobinson (void) rw_unlock(&svc_fd_lock); 13397c478bd9Sstevel@tonic-gate return; 13407c478bd9Sstevel@tonic-gate } 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate /* 13437c478bd9Sstevel@tonic-gate * The transport associated with this fd could have been 13447c478bd9Sstevel@tonic-gate * removed from svc_timeout_nonblock_xprt_and_LRU, for instance. 13457c478bd9Sstevel@tonic-gate * This can happen if two or more fds get read events and are 13467c478bd9Sstevel@tonic-gate * passed to svc_getreq_poll/set, the first fd is seviced by 13477c478bd9Sstevel@tonic-gate * the dispatch routine and cleans up any dead transports. If 13487c478bd9Sstevel@tonic-gate * one of the dead transports removed is the other fd that 13497c478bd9Sstevel@tonic-gate * had a read event then svc_getreq_common() will be called with no 13507c478bd9Sstevel@tonic-gate * xprt associated with the fd that had the original read event. 13517c478bd9Sstevel@tonic-gate */ 13527c478bd9Sstevel@tonic-gate if ((fd >= nsvc_xports) || (xprt = svc_xports[fd]) == NULL) { 1353*61961e0fSrobinson (void) rw_unlock(&svc_fd_lock); 13547c478bd9Sstevel@tonic-gate return; 13557c478bd9Sstevel@tonic-gate } 1356*61961e0fSrobinson (void) rw_unlock(&svc_fd_lock); 13577c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 13587c478bd9Sstevel@tonic-gate msg = SVCEXT(xprt)->msg; 13597c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 13607c478bd9Sstevel@tonic-gate r = SVCEXT(xprt)->req; 13617c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 13627c478bd9Sstevel@tonic-gate cred_area = SVCEXT(xprt)->cred_area; 13637c478bd9Sstevel@tonic-gate msg->rm_call.cb_cred.oa_base = cred_area; 13647c478bd9Sstevel@tonic-gate msg->rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); 13657c478bd9Sstevel@tonic-gate r->rq_clntcred = &(cred_area[2 * MAX_AUTH_BYTES]); 13667c478bd9Sstevel@tonic-gate 13677c478bd9Sstevel@tonic-gate /* receive msgs from xprtprt (support batch calls) */ 13687c478bd9Sstevel@tonic-gate do { 13697c478bd9Sstevel@tonic-gate bool_t dispatch; 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate if (dispatch = SVC_RECV(xprt, msg)) 13727c478bd9Sstevel@tonic-gate (void) _svc_prog_dispatch(xprt, msg, r); 13737c478bd9Sstevel@tonic-gate /* 13747c478bd9Sstevel@tonic-gate * Check if the xprt has been disconnected in a recursive call 13757c478bd9Sstevel@tonic-gate * in the service dispatch routine. If so, then break 13767c478bd9Sstevel@tonic-gate */ 1377*61961e0fSrobinson (void) rw_rdlock(&svc_fd_lock); 13787c478bd9Sstevel@tonic-gate if (xprt != svc_xports[fd]) { 1379*61961e0fSrobinson (void) rw_unlock(&svc_fd_lock); 13807c478bd9Sstevel@tonic-gate break; 13817c478bd9Sstevel@tonic-gate } 1382*61961e0fSrobinson (void) rw_unlock(&svc_fd_lock); 13837c478bd9Sstevel@tonic-gate 13847c478bd9Sstevel@tonic-gate /* 13857c478bd9Sstevel@tonic-gate * Call cleanup procedure if set. 13867c478bd9Sstevel@tonic-gate */ 13877c478bd9Sstevel@tonic-gate if (__proc_cleanup_cb != NULL && dispatch) 13887c478bd9Sstevel@tonic-gate (*__proc_cleanup_cb)(xprt); 13897c478bd9Sstevel@tonic-gate 13907c478bd9Sstevel@tonic-gate if ((stat = SVC_STAT(xprt)) == XPRT_DIED) { 13917c478bd9Sstevel@tonic-gate SVC_DESTROY(xprt); 13927c478bd9Sstevel@tonic-gate break; 13937c478bd9Sstevel@tonic-gate } 13947c478bd9Sstevel@tonic-gate } while (stat == XPRT_MOREREQS); 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate int 1398*61961e0fSrobinson _svc_prog_dispatch(SVCXPRT *xprt, struct rpc_msg *msg, struct svc_req *r) 13997c478bd9Sstevel@tonic-gate { 14007c478bd9Sstevel@tonic-gate struct svc_callout *s; 14017c478bd9Sstevel@tonic-gate enum auth_stat why; 14027c478bd9Sstevel@tonic-gate int prog_found; 14037c478bd9Sstevel@tonic-gate rpcvers_t low_vers; 14047c478bd9Sstevel@tonic-gate rpcvers_t high_vers; 14057c478bd9Sstevel@tonic-gate void (*disp_fn)(); 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate r->rq_xprt = xprt; 14087c478bd9Sstevel@tonic-gate r->rq_prog = msg->rm_call.cb_prog; 14097c478bd9Sstevel@tonic-gate r->rq_vers = msg->rm_call.cb_vers; 14107c478bd9Sstevel@tonic-gate r->rq_proc = msg->rm_call.cb_proc; 14117c478bd9Sstevel@tonic-gate r->rq_cred = msg->rm_call.cb_cred; 14127c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 14137c478bd9Sstevel@tonic-gate SVC_XP_AUTH(r->rq_xprt).svc_ah_ops = svc_auth_any_ops; 14147c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 14157c478bd9Sstevel@tonic-gate SVC_XP_AUTH(r->rq_xprt).svc_ah_private = NULL; 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate /* first authenticate the message */ 14187c478bd9Sstevel@tonic-gate /* Check for null flavor and bypass these calls if possible */ 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate if (msg->rm_call.cb_cred.oa_flavor == AUTH_NULL) { 14217c478bd9Sstevel@tonic-gate r->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor; 14227c478bd9Sstevel@tonic-gate r->rq_xprt->xp_verf.oa_length = 0; 14237c478bd9Sstevel@tonic-gate } else { 14247c478bd9Sstevel@tonic-gate bool_t no_dispatch; 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate if ((why = __gss_authenticate(r, msg, 14277c478bd9Sstevel@tonic-gate &no_dispatch)) != AUTH_OK) { 14287c478bd9Sstevel@tonic-gate svcerr_auth(xprt, why); 14297c478bd9Sstevel@tonic-gate return (0); 14307c478bd9Sstevel@tonic-gate } 14317c478bd9Sstevel@tonic-gate if (no_dispatch) 14327c478bd9Sstevel@tonic-gate return (0); 14337c478bd9Sstevel@tonic-gate } 14347c478bd9Sstevel@tonic-gate /* match message with a registered service */ 14357c478bd9Sstevel@tonic-gate prog_found = FALSE; 14367c478bd9Sstevel@tonic-gate low_vers = (rpcvers_t)(0 - 1); 14377c478bd9Sstevel@tonic-gate high_vers = 0; 1438*61961e0fSrobinson (void) rw_rdlock(&svc_lock); 14397c478bd9Sstevel@tonic-gate for (s = svc_head; s != NULL_SVC; s = s->sc_next) { 14407c478bd9Sstevel@tonic-gate if (s->sc_prog == r->rq_prog) { 14417c478bd9Sstevel@tonic-gate prog_found = TRUE; 14427c478bd9Sstevel@tonic-gate if (s->sc_vers == r->rq_vers) { 14437c478bd9Sstevel@tonic-gate if ((xprt->xp_netid == NULL) || 14447c478bd9Sstevel@tonic-gate (s->sc_netid == NULL) || 14457c478bd9Sstevel@tonic-gate (strcmp(xprt->xp_netid, 14467c478bd9Sstevel@tonic-gate s->sc_netid) == 0)) { 14477c478bd9Sstevel@tonic-gate disp_fn = (*s->sc_dispatch); 1448*61961e0fSrobinson (void) rw_unlock(&svc_lock); 14497c478bd9Sstevel@tonic-gate disp_fn(r, xprt); 14507c478bd9Sstevel@tonic-gate return (1); 14517c478bd9Sstevel@tonic-gate } 1452*61961e0fSrobinson prog_found = FALSE; 14537c478bd9Sstevel@tonic-gate } 14547c478bd9Sstevel@tonic-gate if (s->sc_vers < low_vers) 14557c478bd9Sstevel@tonic-gate low_vers = s->sc_vers; 14567c478bd9Sstevel@tonic-gate if (s->sc_vers > high_vers) 14577c478bd9Sstevel@tonic-gate high_vers = s->sc_vers; 14587c478bd9Sstevel@tonic-gate } /* found correct program */ 14597c478bd9Sstevel@tonic-gate } 1460*61961e0fSrobinson (void) rw_unlock(&svc_lock); 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate /* 14637c478bd9Sstevel@tonic-gate * if we got here, the program or version 14647c478bd9Sstevel@tonic-gate * is not served ... 14657c478bd9Sstevel@tonic-gate */ 14667c478bd9Sstevel@tonic-gate if (prog_found) { 14677c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 14687c478bd9Sstevel@tonic-gate if (!version_keepquiet(xprt)) 14697c478bd9Sstevel@tonic-gate svcerr_progvers(xprt, low_vers, high_vers); 14707c478bd9Sstevel@tonic-gate } else { 14717c478bd9Sstevel@tonic-gate svcerr_noprog(xprt); 14727c478bd9Sstevel@tonic-gate } 14737c478bd9Sstevel@tonic-gate return (0); 14747c478bd9Sstevel@tonic-gate } 14757c478bd9Sstevel@tonic-gate 14767c478bd9Sstevel@tonic-gate /* ******************* SVCXPRT allocation and deallocation ***************** */ 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate /* 14797c478bd9Sstevel@tonic-gate * svc_xprt_alloc() - allocate a service transport handle 14807c478bd9Sstevel@tonic-gate */ 14817c478bd9Sstevel@tonic-gate SVCXPRT * 1482*61961e0fSrobinson svc_xprt_alloc(void) 14837c478bd9Sstevel@tonic-gate { 14847c478bd9Sstevel@tonic-gate SVCXPRT *xprt = NULL; 14857c478bd9Sstevel@tonic-gate SVCXPRT_EXT *xt = NULL; 14867c478bd9Sstevel@tonic-gate SVCXPRT_LIST *xlist = NULL; 14877c478bd9Sstevel@tonic-gate struct rpc_msg *msg = NULL; 14887c478bd9Sstevel@tonic-gate struct svc_req *req = NULL; 14897c478bd9Sstevel@tonic-gate char *cred_area = NULL; 14907c478bd9Sstevel@tonic-gate 1491*61961e0fSrobinson if ((xprt = calloc(1, sizeof (SVCXPRT))) == NULL) 14927c478bd9Sstevel@tonic-gate goto err_exit; 14937c478bd9Sstevel@tonic-gate 1494*61961e0fSrobinson if ((xt = calloc(1, sizeof (SVCXPRT_EXT))) == NULL) 14957c478bd9Sstevel@tonic-gate goto err_exit; 14967c478bd9Sstevel@tonic-gate xprt->xp_p3 = (caddr_t)xt; /* SVCEXT(xprt) = xt */ 14977c478bd9Sstevel@tonic-gate 1498*61961e0fSrobinson if ((xlist = calloc(1, sizeof (SVCXPRT_LIST))) == NULL) 14997c478bd9Sstevel@tonic-gate goto err_exit; 15007c478bd9Sstevel@tonic-gate xt->my_xlist = xlist; 15017c478bd9Sstevel@tonic-gate xlist->xprt = xprt; 15027c478bd9Sstevel@tonic-gate 1503*61961e0fSrobinson if ((msg = malloc(sizeof (struct rpc_msg))) == NULL) 15047c478bd9Sstevel@tonic-gate goto err_exit; 15057c478bd9Sstevel@tonic-gate xt->msg = msg; 15067c478bd9Sstevel@tonic-gate 1507*61961e0fSrobinson if ((req = malloc(sizeof (struct svc_req))) == NULL) 15087c478bd9Sstevel@tonic-gate goto err_exit; 15097c478bd9Sstevel@tonic-gate xt->req = req; 15107c478bd9Sstevel@tonic-gate 1511*61961e0fSrobinson if ((cred_area = malloc(2*MAX_AUTH_BYTES + RQCRED_SIZE)) == NULL) 15127c478bd9Sstevel@tonic-gate goto err_exit; 15137c478bd9Sstevel@tonic-gate xt->cred_area = cred_area; 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 1516*61961e0fSrobinson (void) mutex_init(&svc_send_mutex(xprt), USYNC_THREAD, (void *)0); 15177c478bd9Sstevel@tonic-gate return (xprt); 15187c478bd9Sstevel@tonic-gate 15197c478bd9Sstevel@tonic-gate err_exit: 15207c478bd9Sstevel@tonic-gate svc_xprt_free(xprt); 15217c478bd9Sstevel@tonic-gate return (NULL); 15227c478bd9Sstevel@tonic-gate } 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate 15257c478bd9Sstevel@tonic-gate /* 15267c478bd9Sstevel@tonic-gate * svc_xprt_free() - free a service handle 15277c478bd9Sstevel@tonic-gate */ 15287c478bd9Sstevel@tonic-gate void 1529*61961e0fSrobinson svc_xprt_free(SVCXPRT *xprt) 15307c478bd9Sstevel@tonic-gate { 15317c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 15327c478bd9Sstevel@tonic-gate SVCXPRT_EXT *xt = xprt ? SVCEXT(xprt) : NULL; 15337c478bd9Sstevel@tonic-gate SVCXPRT_LIST *my_xlist = xt ? xt->my_xlist: NULL; 15347c478bd9Sstevel@tonic-gate struct rpc_msg *msg = xt ? xt->msg : NULL; 15357c478bd9Sstevel@tonic-gate struct svc_req *req = xt ? xt->req : NULL; 15367c478bd9Sstevel@tonic-gate char *cred_area = xt ? xt->cred_area : NULL; 15377c478bd9Sstevel@tonic-gate 15387c478bd9Sstevel@tonic-gate if (xprt) 1539*61961e0fSrobinson free(xprt); 15407c478bd9Sstevel@tonic-gate if (xt) 1541*61961e0fSrobinson free(xt); 15427c478bd9Sstevel@tonic-gate if (my_xlist) 1543*61961e0fSrobinson free(my_xlist); 15447c478bd9Sstevel@tonic-gate if (msg) 1545*61961e0fSrobinson free(msg); 15467c478bd9Sstevel@tonic-gate if (req) 1547*61961e0fSrobinson free(req); 15487c478bd9Sstevel@tonic-gate if (cred_area) 1549*61961e0fSrobinson free(cred_area); 15507c478bd9Sstevel@tonic-gate } 15517c478bd9Sstevel@tonic-gate 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate /* 15547c478bd9Sstevel@tonic-gate * svc_xprt_destroy() - free parent and child xprt list 15557c478bd9Sstevel@tonic-gate */ 15567c478bd9Sstevel@tonic-gate void 1557*61961e0fSrobinson svc_xprt_destroy(SVCXPRT *xprt) 15587c478bd9Sstevel@tonic-gate { 15597c478bd9Sstevel@tonic-gate SVCXPRT_LIST *xlist, *xnext = NULL; 15607c478bd9Sstevel@tonic-gate int type; 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 15637c478bd9Sstevel@tonic-gate if (SVCEXT(xprt)->parent) 15647c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 15657c478bd9Sstevel@tonic-gate xprt = SVCEXT(xprt)->parent; 15667c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 15677c478bd9Sstevel@tonic-gate type = svc_type(xprt); 15687c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 15697c478bd9Sstevel@tonic-gate for (xlist = SVCEXT(xprt)->my_xlist; xlist != NULL; xlist = xnext) { 15707c478bd9Sstevel@tonic-gate xnext = xlist->next; 15717c478bd9Sstevel@tonic-gate xprt = xlist->xprt; 15727c478bd9Sstevel@tonic-gate switch (type) { 15737c478bd9Sstevel@tonic-gate case SVC_DGRAM: 15747c478bd9Sstevel@tonic-gate svc_dg_xprtfree(xprt); 15757c478bd9Sstevel@tonic-gate break; 15767c478bd9Sstevel@tonic-gate case SVC_RENDEZVOUS: 15777c478bd9Sstevel@tonic-gate svc_vc_xprtfree(xprt); 15787c478bd9Sstevel@tonic-gate break; 15797c478bd9Sstevel@tonic-gate case SVC_CONNECTION: 15807c478bd9Sstevel@tonic-gate svc_fd_xprtfree(xprt); 15817c478bd9Sstevel@tonic-gate break; 15827c478bd9Sstevel@tonic-gate case SVC_DOOR: 15837c478bd9Sstevel@tonic-gate svc_door_xprtfree(xprt); 15847c478bd9Sstevel@tonic-gate break; 15857c478bd9Sstevel@tonic-gate } 15867c478bd9Sstevel@tonic-gate } 15877c478bd9Sstevel@tonic-gate } 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate 15907c478bd9Sstevel@tonic-gate /* 15917c478bd9Sstevel@tonic-gate * svc_copy() - make a copy of parent 15927c478bd9Sstevel@tonic-gate */ 15937c478bd9Sstevel@tonic-gate SVCXPRT * 1594*61961e0fSrobinson svc_copy(SVCXPRT *xprt) 15957c478bd9Sstevel@tonic-gate { 15967c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 15977c478bd9Sstevel@tonic-gate switch (svc_type(xprt)) { 15987c478bd9Sstevel@tonic-gate case SVC_DGRAM: 15997c478bd9Sstevel@tonic-gate return (svc_dg_xprtcopy(xprt)); 16007c478bd9Sstevel@tonic-gate case SVC_RENDEZVOUS: 16017c478bd9Sstevel@tonic-gate return (svc_vc_xprtcopy(xprt)); 16027c478bd9Sstevel@tonic-gate case SVC_CONNECTION: 16037c478bd9Sstevel@tonic-gate return (svc_fd_xprtcopy(xprt)); 16047c478bd9Sstevel@tonic-gate } 1605*61961e0fSrobinson return (NULL); 16067c478bd9Sstevel@tonic-gate } 16077c478bd9Sstevel@tonic-gate 16087c478bd9Sstevel@tonic-gate 16097c478bd9Sstevel@tonic-gate /* 16107c478bd9Sstevel@tonic-gate * _svc_destroy_private() - private SVC_DESTROY interface 16117c478bd9Sstevel@tonic-gate */ 16127c478bd9Sstevel@tonic-gate void 1613*61961e0fSrobinson _svc_destroy_private(SVCXPRT *xprt) 16147c478bd9Sstevel@tonic-gate { 16157c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 16167c478bd9Sstevel@tonic-gate switch (svc_type(xprt)) { 16177c478bd9Sstevel@tonic-gate case SVC_DGRAM: 16187c478bd9Sstevel@tonic-gate _svc_dg_destroy_private(xprt); 16197c478bd9Sstevel@tonic-gate break; 16207c478bd9Sstevel@tonic-gate case SVC_RENDEZVOUS: 16217c478bd9Sstevel@tonic-gate case SVC_CONNECTION: 16227c478bd9Sstevel@tonic-gate _svc_vc_destroy_private(xprt, TRUE); 16237c478bd9Sstevel@tonic-gate break; 16247c478bd9Sstevel@tonic-gate } 16257c478bd9Sstevel@tonic-gate } 16267c478bd9Sstevel@tonic-gate 16277c478bd9Sstevel@tonic-gate /* 16287c478bd9Sstevel@tonic-gate * svc_get_local_cred() - fetch local user credentials. This always 16297c478bd9Sstevel@tonic-gate * works over doors based transports. For local transports, this 16307c478bd9Sstevel@tonic-gate * does not yield correct results unless the __rpc_negotiate_uid() 16317c478bd9Sstevel@tonic-gate * call has been invoked to enable this feature. 16327c478bd9Sstevel@tonic-gate */ 16337c478bd9Sstevel@tonic-gate bool_t 1634*61961e0fSrobinson svc_get_local_cred(SVCXPRT *xprt, svc_local_cred_t *lcred) 16357c478bd9Sstevel@tonic-gate { 16367c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 16377c478bd9Sstevel@tonic-gate if (svc_type(xprt) == SVC_DOOR) 16387c478bd9Sstevel@tonic-gate return (__svc_get_door_cred(xprt, lcred)); 16397c478bd9Sstevel@tonic-gate return (__rpc_get_local_cred(xprt, lcred)); 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate 16437c478bd9Sstevel@tonic-gate /* ******************* DUPLICATE ENTRY HANDLING ROUTINES ************** */ 16447c478bd9Sstevel@tonic-gate 16457c478bd9Sstevel@tonic-gate /* 16467c478bd9Sstevel@tonic-gate * the dup cacheing routines below provide a cache of received 16477c478bd9Sstevel@tonic-gate * transactions. rpc service routines can use this to detect 16487c478bd9Sstevel@tonic-gate * retransmissions and re-send a non-failure response. Uses a 16497c478bd9Sstevel@tonic-gate * lru scheme to find entries to get rid of entries in the cache, 16507c478bd9Sstevel@tonic-gate * though only DUP_DONE entries are placed on the lru list. 16517c478bd9Sstevel@tonic-gate * the routines were written towards development of a generic 16527c478bd9Sstevel@tonic-gate * SVC_DUP() interface, which can be expanded to encompass the 16537c478bd9Sstevel@tonic-gate * svc_dg_enablecache() routines as well. the cache is currently 16547c478bd9Sstevel@tonic-gate * private to the automounter. 16557c478bd9Sstevel@tonic-gate */ 16567c478bd9Sstevel@tonic-gate 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate /* dupcache header contains xprt specific information */ 1659*61961e0fSrobinson struct dupcache { 16607c478bd9Sstevel@tonic-gate rwlock_t dc_lock; 16617c478bd9Sstevel@tonic-gate time_t dc_time; 16627c478bd9Sstevel@tonic-gate int dc_buckets; 16637c478bd9Sstevel@tonic-gate int dc_maxsz; 16647c478bd9Sstevel@tonic-gate int dc_basis; 16657c478bd9Sstevel@tonic-gate struct dupreq *dc_mru; 16667c478bd9Sstevel@tonic-gate struct dupreq **dc_hashtbl; 16677c478bd9Sstevel@tonic-gate }; 16687c478bd9Sstevel@tonic-gate 16697c478bd9Sstevel@tonic-gate /* 16707c478bd9Sstevel@tonic-gate * private duplicate cache request routines 16717c478bd9Sstevel@tonic-gate */ 16727c478bd9Sstevel@tonic-gate static int __svc_dupcache_check(struct svc_req *, caddr_t *, uint_t *, 16737c478bd9Sstevel@tonic-gate struct dupcache *, uint32_t, uint32_t); 16747c478bd9Sstevel@tonic-gate static struct dupreq *__svc_dupcache_victim(struct dupcache *, time_t); 16757c478bd9Sstevel@tonic-gate static int __svc_dupcache_enter(struct svc_req *, struct dupreq *, 16767c478bd9Sstevel@tonic-gate struct dupcache *, uint32_t, uint32_t, time_t); 16777c478bd9Sstevel@tonic-gate static int __svc_dupcache_update(struct svc_req *, caddr_t, uint_t, int, 16787c478bd9Sstevel@tonic-gate struct dupcache *, uint32_t, uint32_t); 16797c478bd9Sstevel@tonic-gate #ifdef DUP_DEBUG 16807c478bd9Sstevel@tonic-gate static void __svc_dupcache_debug(struct dupcache *); 16817c478bd9Sstevel@tonic-gate #endif /* DUP_DEBUG */ 16827c478bd9Sstevel@tonic-gate 16837c478bd9Sstevel@tonic-gate /* default parameters for the dupcache */ 16847c478bd9Sstevel@tonic-gate #define DUPCACHE_BUCKETS 257 16857c478bd9Sstevel@tonic-gate #define DUPCACHE_TIME 900 16867c478bd9Sstevel@tonic-gate #define DUPCACHE_MAXSZ INT_MAX 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate /* 16897c478bd9Sstevel@tonic-gate * __svc_dupcache_init(void *condition, int basis, char *xprt_cache) 16907c478bd9Sstevel@tonic-gate * initialize the duprequest cache and assign it to the xprt_cache 16917c478bd9Sstevel@tonic-gate * Use default values depending on the cache condition and basis. 16927c478bd9Sstevel@tonic-gate * return TRUE on success and FALSE on failure 16937c478bd9Sstevel@tonic-gate */ 16947c478bd9Sstevel@tonic-gate bool_t 16957c478bd9Sstevel@tonic-gate __svc_dupcache_init(void *condition, int basis, char **xprt_cache) 16967c478bd9Sstevel@tonic-gate { 16977c478bd9Sstevel@tonic-gate static mutex_t initdc_lock = DEFAULTMUTEX; 16987c478bd9Sstevel@tonic-gate int i; 16997c478bd9Sstevel@tonic-gate struct dupcache *dc; 17007c478bd9Sstevel@tonic-gate 1701*61961e0fSrobinson (void) mutex_lock(&initdc_lock); 17027c478bd9Sstevel@tonic-gate if (*xprt_cache != NULL) { /* do only once per xprt */ 1703*61961e0fSrobinson (void) mutex_unlock(&initdc_lock); 17047c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 17057c478bd9Sstevel@tonic-gate "__svc_dupcache_init: multiply defined dup cache"); 17067c478bd9Sstevel@tonic-gate return (FALSE); 17077c478bd9Sstevel@tonic-gate } 17087c478bd9Sstevel@tonic-gate 17097c478bd9Sstevel@tonic-gate switch (basis) { 17107c478bd9Sstevel@tonic-gate case DUPCACHE_FIXEDTIME: 1711*61961e0fSrobinson dc = malloc(sizeof (struct dupcache)); 17127c478bd9Sstevel@tonic-gate if (dc == NULL) { 1713*61961e0fSrobinson (void) mutex_unlock(&initdc_lock); 17147c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 17157c478bd9Sstevel@tonic-gate "__svc_dupcache_init: memory alloc failed"); 17167c478bd9Sstevel@tonic-gate return (FALSE); 17177c478bd9Sstevel@tonic-gate } 1718*61961e0fSrobinson (void) rwlock_init(&(dc->dc_lock), USYNC_THREAD, NULL); 17197c478bd9Sstevel@tonic-gate if (condition != NULL) 17207c478bd9Sstevel@tonic-gate dc->dc_time = *((time_t *)condition); 17217c478bd9Sstevel@tonic-gate else 17227c478bd9Sstevel@tonic-gate dc->dc_time = DUPCACHE_TIME; 17237c478bd9Sstevel@tonic-gate dc->dc_buckets = DUPCACHE_BUCKETS; 17247c478bd9Sstevel@tonic-gate dc->dc_maxsz = DUPCACHE_MAXSZ; 17257c478bd9Sstevel@tonic-gate dc->dc_basis = basis; 17267c478bd9Sstevel@tonic-gate dc->dc_mru = NULL; 1727*61961e0fSrobinson dc->dc_hashtbl = malloc(dc->dc_buckets * 17287c478bd9Sstevel@tonic-gate sizeof (struct dupreq *)); 17297c478bd9Sstevel@tonic-gate if (dc->dc_hashtbl == NULL) { 1730*61961e0fSrobinson free(dc); 1731*61961e0fSrobinson (void) mutex_unlock(&initdc_lock); 17327c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 17337c478bd9Sstevel@tonic-gate "__svc_dupcache_init: memory alloc failed"); 17347c478bd9Sstevel@tonic-gate return (FALSE); 17357c478bd9Sstevel@tonic-gate } 17367c478bd9Sstevel@tonic-gate for (i = 0; i < DUPCACHE_BUCKETS; i++) 17377c478bd9Sstevel@tonic-gate dc->dc_hashtbl[i] = NULL; 17387c478bd9Sstevel@tonic-gate *xprt_cache = (char *)dc; 17397c478bd9Sstevel@tonic-gate break; 17407c478bd9Sstevel@tonic-gate default: 1741*61961e0fSrobinson (void) mutex_unlock(&initdc_lock); 17427c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 17437c478bd9Sstevel@tonic-gate "__svc_dupcache_init: undefined dup cache basis"); 17447c478bd9Sstevel@tonic-gate return (FALSE); 17457c478bd9Sstevel@tonic-gate } 17467c478bd9Sstevel@tonic-gate 1747*61961e0fSrobinson (void) mutex_unlock(&initdc_lock); 17487c478bd9Sstevel@tonic-gate 17497c478bd9Sstevel@tonic-gate return (TRUE); 17507c478bd9Sstevel@tonic-gate } 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate /* 17537c478bd9Sstevel@tonic-gate * __svc_dup(struct svc_req *req, caddr_t *resp_buf, uint_t *resp_bufsz, 17547c478bd9Sstevel@tonic-gate * char *xprt_cache) 17557c478bd9Sstevel@tonic-gate * searches the request cache. Creates an entry and returns DUP_NEW if 17567c478bd9Sstevel@tonic-gate * the request is not found in the cache. If it is found, then it 17577c478bd9Sstevel@tonic-gate * returns the state of the request (in progress, drop, or done) and 17587c478bd9Sstevel@tonic-gate * also allocates, and passes back results to the user (if any) in 17597c478bd9Sstevel@tonic-gate * resp_buf, and its length in resp_bufsz. DUP_ERROR is returned on error. 17607c478bd9Sstevel@tonic-gate */ 17617c478bd9Sstevel@tonic-gate int 17627c478bd9Sstevel@tonic-gate __svc_dup(struct svc_req *req, caddr_t *resp_buf, uint_t *resp_bufsz, 17637c478bd9Sstevel@tonic-gate char *xprt_cache) 17647c478bd9Sstevel@tonic-gate { 17657c478bd9Sstevel@tonic-gate uint32_t drxid, drhash; 17667c478bd9Sstevel@tonic-gate int rc; 17677c478bd9Sstevel@tonic-gate struct dupreq *dr = NULL; 17687c478bd9Sstevel@tonic-gate time_t timenow = time(NULL); 17697c478bd9Sstevel@tonic-gate 17707c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 17717c478bd9Sstevel@tonic-gate struct dupcache *dc = (struct dupcache *)xprt_cache; 17727c478bd9Sstevel@tonic-gate 17737c478bd9Sstevel@tonic-gate if (dc == NULL) { 17747c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "__svc_dup: undefined cache"); 17757c478bd9Sstevel@tonic-gate return (DUP_ERROR); 17767c478bd9Sstevel@tonic-gate } 17777c478bd9Sstevel@tonic-gate 17787c478bd9Sstevel@tonic-gate /* get the xid of the request */ 17797c478bd9Sstevel@tonic-gate if (SVC_CONTROL(req->rq_xprt, SVCGET_XID, (void*)&drxid) == FALSE) { 17807c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "__svc_dup: xid error"); 17817c478bd9Sstevel@tonic-gate return (DUP_ERROR); 17827c478bd9Sstevel@tonic-gate } 17837c478bd9Sstevel@tonic-gate drhash = drxid % dc->dc_buckets; 17847c478bd9Sstevel@tonic-gate 17857c478bd9Sstevel@tonic-gate if ((rc = __svc_dupcache_check(req, resp_buf, resp_bufsz, dc, drxid, 17867c478bd9Sstevel@tonic-gate drhash)) != DUP_NEW) 17877c478bd9Sstevel@tonic-gate return (rc); 17887c478bd9Sstevel@tonic-gate 17897c478bd9Sstevel@tonic-gate if ((dr = __svc_dupcache_victim(dc, timenow)) == NULL) 17907c478bd9Sstevel@tonic-gate return (DUP_ERROR); 17917c478bd9Sstevel@tonic-gate 17927c478bd9Sstevel@tonic-gate if ((rc = __svc_dupcache_enter(req, dr, dc, drxid, drhash, timenow)) 17937c478bd9Sstevel@tonic-gate == DUP_ERROR) 17947c478bd9Sstevel@tonic-gate return (rc); 17957c478bd9Sstevel@tonic-gate 17967c478bd9Sstevel@tonic-gate return (DUP_NEW); 17977c478bd9Sstevel@tonic-gate } 17987c478bd9Sstevel@tonic-gate 17997c478bd9Sstevel@tonic-gate 18007c478bd9Sstevel@tonic-gate 18017c478bd9Sstevel@tonic-gate /* 18027c478bd9Sstevel@tonic-gate * __svc_dupcache_check(struct svc_req *req, caddr_t *resp_buf, 18037c478bd9Sstevel@tonic-gate * uint_t *resp_bufsz,truct dupcache *dc, uint32_t drxid, 18047c478bd9Sstevel@tonic-gate * uint32_t drhash) 18057c478bd9Sstevel@tonic-gate * Checks to see whether an entry already exists in the cache. If it does 18067c478bd9Sstevel@tonic-gate * copy back into the resp_buf, if appropriate. Return the status of 18077c478bd9Sstevel@tonic-gate * the request, or DUP_NEW if the entry is not in the cache 18087c478bd9Sstevel@tonic-gate */ 18097c478bd9Sstevel@tonic-gate static int 18107c478bd9Sstevel@tonic-gate __svc_dupcache_check(struct svc_req *req, caddr_t *resp_buf, uint_t *resp_bufsz, 18117c478bd9Sstevel@tonic-gate struct dupcache *dc, uint32_t drxid, uint32_t drhash) 18127c478bd9Sstevel@tonic-gate { 18137c478bd9Sstevel@tonic-gate struct dupreq *dr = NULL; 18147c478bd9Sstevel@tonic-gate 1815*61961e0fSrobinson (void) rw_rdlock(&(dc->dc_lock)); 18167c478bd9Sstevel@tonic-gate dr = dc->dc_hashtbl[drhash]; 18177c478bd9Sstevel@tonic-gate while (dr != NULL) { 18187c478bd9Sstevel@tonic-gate if (dr->dr_xid == drxid && 18197c478bd9Sstevel@tonic-gate dr->dr_proc == req->rq_proc && 18207c478bd9Sstevel@tonic-gate dr->dr_prog == req->rq_prog && 18217c478bd9Sstevel@tonic-gate dr->dr_vers == req->rq_vers && 18227c478bd9Sstevel@tonic-gate dr->dr_addr.len == req->rq_xprt->xp_rtaddr.len && 1823*61961e0fSrobinson memcmp(dr->dr_addr.buf, 1824*61961e0fSrobinson req->rq_xprt->xp_rtaddr.buf, 18257c478bd9Sstevel@tonic-gate dr->dr_addr.len) == 0) { /* entry found */ 18267c478bd9Sstevel@tonic-gate if (dr->dr_hash != drhash) { 18277c478bd9Sstevel@tonic-gate /* sanity check */ 1828*61961e0fSrobinson (void) rw_unlock((&dc->dc_lock)); 18297c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 18307c478bd9Sstevel@tonic-gate "\n__svc_dupdone: hashing error"); 18317c478bd9Sstevel@tonic-gate return (DUP_ERROR); 18327c478bd9Sstevel@tonic-gate } 18337c478bd9Sstevel@tonic-gate 18347c478bd9Sstevel@tonic-gate /* 18357c478bd9Sstevel@tonic-gate * return results for requests on lru list, if 18367c478bd9Sstevel@tonic-gate * appropriate requests must be DUP_DROP or DUP_DONE 18377c478bd9Sstevel@tonic-gate * to have a result. A NULL buffer in the cache 18387c478bd9Sstevel@tonic-gate * implies no results were sent during dupdone. 18397c478bd9Sstevel@tonic-gate * A NULL buffer in the call implies not interested 18407c478bd9Sstevel@tonic-gate * in results. 18417c478bd9Sstevel@tonic-gate */ 18427c478bd9Sstevel@tonic-gate if (((dr->dr_status == DUP_DONE) || 18437c478bd9Sstevel@tonic-gate (dr->dr_status == DUP_DROP)) && 18447c478bd9Sstevel@tonic-gate resp_buf != NULL && 18457c478bd9Sstevel@tonic-gate dr->dr_resp.buf != NULL) { 1846*61961e0fSrobinson *resp_buf = malloc(dr->dr_resp.len); 18477c478bd9Sstevel@tonic-gate if (*resp_buf == NULL) { 18487c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 18497c478bd9Sstevel@tonic-gate "__svc_dupcache_check: malloc failed"); 1850*61961e0fSrobinson (void) rw_unlock(&(dc->dc_lock)); 18517c478bd9Sstevel@tonic-gate return (DUP_ERROR); 18527c478bd9Sstevel@tonic-gate } 1853*61961e0fSrobinson (void) memset(*resp_buf, 0, dr->dr_resp.len); 1854*61961e0fSrobinson (void) memcpy(*resp_buf, dr->dr_resp.buf, 18557c478bd9Sstevel@tonic-gate dr->dr_resp.len); 18567c478bd9Sstevel@tonic-gate *resp_bufsz = dr->dr_resp.len; 18577c478bd9Sstevel@tonic-gate } else { 18587c478bd9Sstevel@tonic-gate /* no result */ 18597c478bd9Sstevel@tonic-gate if (resp_buf) 18607c478bd9Sstevel@tonic-gate *resp_buf = NULL; 18617c478bd9Sstevel@tonic-gate if (resp_bufsz) 18627c478bd9Sstevel@tonic-gate *resp_bufsz = 0; 18637c478bd9Sstevel@tonic-gate } 1864*61961e0fSrobinson (void) rw_unlock(&(dc->dc_lock)); 18657c478bd9Sstevel@tonic-gate return (dr->dr_status); 18667c478bd9Sstevel@tonic-gate } 18677c478bd9Sstevel@tonic-gate dr = dr->dr_chain; 18687c478bd9Sstevel@tonic-gate } 1869*61961e0fSrobinson (void) rw_unlock(&(dc->dc_lock)); 18707c478bd9Sstevel@tonic-gate return (DUP_NEW); 18717c478bd9Sstevel@tonic-gate } 18727c478bd9Sstevel@tonic-gate 18737c478bd9Sstevel@tonic-gate /* 18747c478bd9Sstevel@tonic-gate * __svc_dupcache_victim(struct dupcache *dc, time_t timenow) 18757c478bd9Sstevel@tonic-gate * Return a victim dupreq entry to the caller, depending on cache policy. 18767c478bd9Sstevel@tonic-gate */ 18777c478bd9Sstevel@tonic-gate static struct dupreq * 18787c478bd9Sstevel@tonic-gate __svc_dupcache_victim(struct dupcache *dc, time_t timenow) 18797c478bd9Sstevel@tonic-gate { 18807c478bd9Sstevel@tonic-gate struct dupreq *dr = NULL; 18817c478bd9Sstevel@tonic-gate 18827c478bd9Sstevel@tonic-gate switch (dc->dc_basis) { 18837c478bd9Sstevel@tonic-gate case DUPCACHE_FIXEDTIME: 18847c478bd9Sstevel@tonic-gate /* 18857c478bd9Sstevel@tonic-gate * The hash policy is to free up a bit of the hash 18867c478bd9Sstevel@tonic-gate * table before allocating a new entry as the victim. 18877c478bd9Sstevel@tonic-gate * Freeing up the hash table each time should split 18887c478bd9Sstevel@tonic-gate * the cost of keeping the hash table clean among threads. 18897c478bd9Sstevel@tonic-gate * Note that only DONE or DROPPED entries are on the lru 18907c478bd9Sstevel@tonic-gate * list but we do a sanity check anyway. 18917c478bd9Sstevel@tonic-gate */ 1892*61961e0fSrobinson (void) rw_wrlock(&(dc->dc_lock)); 18937c478bd9Sstevel@tonic-gate while ((dc->dc_mru) && (dr = dc->dc_mru->dr_next) && 18947c478bd9Sstevel@tonic-gate ((timenow - dr->dr_time) > dc->dc_time)) { 18957c478bd9Sstevel@tonic-gate /* clean and then free the entry */ 18967c478bd9Sstevel@tonic-gate if (dr->dr_status != DUP_DONE && 18977c478bd9Sstevel@tonic-gate dr->dr_status != DUP_DROP) { 18987c478bd9Sstevel@tonic-gate /* 18997c478bd9Sstevel@tonic-gate * The LRU list can't contain an 19007c478bd9Sstevel@tonic-gate * entry where the status is other than 19017c478bd9Sstevel@tonic-gate * DUP_DONE or DUP_DROP. 19027c478bd9Sstevel@tonic-gate */ 19037c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 19047c478bd9Sstevel@tonic-gate "__svc_dupcache_victim: bad victim"); 19057c478bd9Sstevel@tonic-gate #ifdef DUP_DEBUG 19067c478bd9Sstevel@tonic-gate /* 19077c478bd9Sstevel@tonic-gate * Need to hold the reader/writers lock to 19087c478bd9Sstevel@tonic-gate * print the cache info, since we already 19097c478bd9Sstevel@tonic-gate * hold the writers lock, we shall continue 19107c478bd9Sstevel@tonic-gate * calling __svc_dupcache_debug() 19117c478bd9Sstevel@tonic-gate */ 19127c478bd9Sstevel@tonic-gate __svc_dupcache_debug(dc); 19137c478bd9Sstevel@tonic-gate #endif /* DUP_DEBUG */ 1914*61961e0fSrobinson (void) rw_unlock(&(dc->dc_lock)); 19157c478bd9Sstevel@tonic-gate return (NULL); 19167c478bd9Sstevel@tonic-gate } 19177c478bd9Sstevel@tonic-gate /* free buffers */ 19187c478bd9Sstevel@tonic-gate if (dr->dr_resp.buf) { 1919*61961e0fSrobinson free(dr->dr_resp.buf); 19207c478bd9Sstevel@tonic-gate dr->dr_resp.buf = NULL; 19217c478bd9Sstevel@tonic-gate } 19227c478bd9Sstevel@tonic-gate if (dr->dr_addr.buf) { 1923*61961e0fSrobinson free(dr->dr_addr.buf); 19247c478bd9Sstevel@tonic-gate dr->dr_addr.buf = NULL; 19257c478bd9Sstevel@tonic-gate } 19267c478bd9Sstevel@tonic-gate 19277c478bd9Sstevel@tonic-gate /* unhash the entry */ 19287c478bd9Sstevel@tonic-gate if (dr->dr_chain) 19297c478bd9Sstevel@tonic-gate dr->dr_chain->dr_prevchain = dr->dr_prevchain; 19307c478bd9Sstevel@tonic-gate if (dr->dr_prevchain) 19317c478bd9Sstevel@tonic-gate dr->dr_prevchain->dr_chain = dr->dr_chain; 19327c478bd9Sstevel@tonic-gate if (dc->dc_hashtbl[dr->dr_hash] == dr) 19337c478bd9Sstevel@tonic-gate dc->dc_hashtbl[dr->dr_hash] = dr->dr_chain; 19347c478bd9Sstevel@tonic-gate 19357c478bd9Sstevel@tonic-gate /* modify the lru pointers */ 1936*61961e0fSrobinson if (dc->dc_mru == dr) { 19377c478bd9Sstevel@tonic-gate dc->dc_mru = NULL; 1938*61961e0fSrobinson } else { 19397c478bd9Sstevel@tonic-gate dc->dc_mru->dr_next = dr->dr_next; 19407c478bd9Sstevel@tonic-gate dr->dr_next->dr_prev = dc->dc_mru; 19417c478bd9Sstevel@tonic-gate } 1942*61961e0fSrobinson free(dr); 19437c478bd9Sstevel@tonic-gate dr = NULL; 19447c478bd9Sstevel@tonic-gate } 1945*61961e0fSrobinson (void) rw_unlock(&(dc->dc_lock)); 19467c478bd9Sstevel@tonic-gate 19477c478bd9Sstevel@tonic-gate /* 19487c478bd9Sstevel@tonic-gate * Allocate and return new clean entry as victim 19497c478bd9Sstevel@tonic-gate */ 1950*61961e0fSrobinson if ((dr = malloc(sizeof (*dr))) == NULL) { 19517c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 1952*61961e0fSrobinson "__svc_dupcache_victim: malloc failed"); 19537c478bd9Sstevel@tonic-gate return (NULL); 19547c478bd9Sstevel@tonic-gate } 1955*61961e0fSrobinson (void) memset(dr, 0, sizeof (*dr)); 19567c478bd9Sstevel@tonic-gate return (dr); 19577c478bd9Sstevel@tonic-gate default: 19587c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 19597c478bd9Sstevel@tonic-gate "__svc_dupcache_victim: undefined dup cache_basis"); 19607c478bd9Sstevel@tonic-gate return (NULL); 19617c478bd9Sstevel@tonic-gate } 19627c478bd9Sstevel@tonic-gate } 19637c478bd9Sstevel@tonic-gate 19647c478bd9Sstevel@tonic-gate /* 19657c478bd9Sstevel@tonic-gate * __svc_dupcache_enter(struct svc_req *req, struct dupreq *dr, 19667c478bd9Sstevel@tonic-gate * struct dupcache *dc, uint32_t drxid, uint32_t drhash, time_t timenow) 19677c478bd9Sstevel@tonic-gate * build new duprequest entry and then insert into the cache 19687c478bd9Sstevel@tonic-gate */ 19697c478bd9Sstevel@tonic-gate static int 19707c478bd9Sstevel@tonic-gate __svc_dupcache_enter(struct svc_req *req, struct dupreq *dr, 19717c478bd9Sstevel@tonic-gate struct dupcache *dc, uint32_t drxid, uint32_t drhash, time_t timenow) 19727c478bd9Sstevel@tonic-gate { 19737c478bd9Sstevel@tonic-gate dr->dr_xid = drxid; 19747c478bd9Sstevel@tonic-gate dr->dr_prog = req->rq_prog; 19757c478bd9Sstevel@tonic-gate dr->dr_vers = req->rq_vers; 19767c478bd9Sstevel@tonic-gate dr->dr_proc = req->rq_proc; 19777c478bd9Sstevel@tonic-gate dr->dr_addr.maxlen = req->rq_xprt->xp_rtaddr.len; 19787c478bd9Sstevel@tonic-gate dr->dr_addr.len = dr->dr_addr.maxlen; 1979*61961e0fSrobinson if ((dr->dr_addr.buf = malloc(dr->dr_addr.maxlen)) == NULL) { 1980*61961e0fSrobinson syslog(LOG_ERR, "__svc_dupcache_enter: malloc failed"); 1981*61961e0fSrobinson free(dr); 19827c478bd9Sstevel@tonic-gate return (DUP_ERROR); 19837c478bd9Sstevel@tonic-gate } 1984*61961e0fSrobinson (void) memset(dr->dr_addr.buf, 0, dr->dr_addr.len); 1985*61961e0fSrobinson (void) memcpy(dr->dr_addr.buf, req->rq_xprt->xp_rtaddr.buf, 1986*61961e0fSrobinson dr->dr_addr.len); 19877c478bd9Sstevel@tonic-gate dr->dr_resp.buf = NULL; 19887c478bd9Sstevel@tonic-gate dr->dr_resp.maxlen = 0; 19897c478bd9Sstevel@tonic-gate dr->dr_resp.len = 0; 19907c478bd9Sstevel@tonic-gate dr->dr_status = DUP_INPROGRESS; 19917c478bd9Sstevel@tonic-gate dr->dr_time = timenow; 19927c478bd9Sstevel@tonic-gate dr->dr_hash = drhash; /* needed for efficient victim cleanup */ 19937c478bd9Sstevel@tonic-gate 19947c478bd9Sstevel@tonic-gate /* place entry at head of hash table */ 1995*61961e0fSrobinson (void) rw_wrlock(&(dc->dc_lock)); 19967c478bd9Sstevel@tonic-gate dr->dr_chain = dc->dc_hashtbl[drhash]; 19977c478bd9Sstevel@tonic-gate dr->dr_prevchain = NULL; 19987c478bd9Sstevel@tonic-gate if (dc->dc_hashtbl[drhash] != NULL) 19997c478bd9Sstevel@tonic-gate dc->dc_hashtbl[drhash]->dr_prevchain = dr; 20007c478bd9Sstevel@tonic-gate dc->dc_hashtbl[drhash] = dr; 2001*61961e0fSrobinson (void) rw_unlock(&(dc->dc_lock)); 20027c478bd9Sstevel@tonic-gate return (DUP_NEW); 20037c478bd9Sstevel@tonic-gate } 20047c478bd9Sstevel@tonic-gate 20057c478bd9Sstevel@tonic-gate /* 20067c478bd9Sstevel@tonic-gate * __svc_dupdone(struct svc_req *req, caddr_t resp_buf, uint_t resp_bufsz, 20077c478bd9Sstevel@tonic-gate * int status, char *xprt_cache) 20087c478bd9Sstevel@tonic-gate * Marks the request done (DUP_DONE or DUP_DROP) and stores the response. 20097c478bd9Sstevel@tonic-gate * Only DONE and DROP requests can be marked as done. Sets the lru pointers 20107c478bd9Sstevel@tonic-gate * to make the entry the most recently used. Returns DUP_ERROR or status. 20117c478bd9Sstevel@tonic-gate */ 20127c478bd9Sstevel@tonic-gate int 20137c478bd9Sstevel@tonic-gate __svc_dupdone(struct svc_req *req, caddr_t resp_buf, uint_t resp_bufsz, 20147c478bd9Sstevel@tonic-gate int status, char *xprt_cache) 20157c478bd9Sstevel@tonic-gate { 20167c478bd9Sstevel@tonic-gate uint32_t drxid, drhash; 20177c478bd9Sstevel@tonic-gate int rc; 20187c478bd9Sstevel@tonic-gate 20197c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 20207c478bd9Sstevel@tonic-gate struct dupcache *dc = (struct dupcache *)xprt_cache; 20217c478bd9Sstevel@tonic-gate 20227c478bd9Sstevel@tonic-gate if (dc == NULL) { 20237c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "__svc_dupdone: undefined cache"); 20247c478bd9Sstevel@tonic-gate return (DUP_ERROR); 20257c478bd9Sstevel@tonic-gate } 20267c478bd9Sstevel@tonic-gate 20277c478bd9Sstevel@tonic-gate if (status != DUP_DONE && status != DUP_DROP) { 20287c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "__svc_dupdone: invalid dupdone status"); 20297c478bd9Sstevel@tonic-gate syslog(LOG_ERR, " must be DUP_DONE or DUP_DROP"); 20307c478bd9Sstevel@tonic-gate return (DUP_ERROR); 20317c478bd9Sstevel@tonic-gate } 20327c478bd9Sstevel@tonic-gate 20337c478bd9Sstevel@tonic-gate /* find the xid of the entry in the cache */ 20347c478bd9Sstevel@tonic-gate if (SVC_CONTROL(req->rq_xprt, SVCGET_XID, (void*)&drxid) == FALSE) { 20357c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "__svc_dup: xid error"); 20367c478bd9Sstevel@tonic-gate return (DUP_ERROR); 20377c478bd9Sstevel@tonic-gate } 20387c478bd9Sstevel@tonic-gate drhash = drxid % dc->dc_buckets; 20397c478bd9Sstevel@tonic-gate 20407c478bd9Sstevel@tonic-gate /* update the status of the entry and result buffers, if required */ 20417c478bd9Sstevel@tonic-gate if ((rc = __svc_dupcache_update(req, resp_buf, resp_bufsz, status, 20427c478bd9Sstevel@tonic-gate dc, drxid, drhash)) == DUP_ERROR) { 20437c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "__svc_dupdone: cache entry error"); 20447c478bd9Sstevel@tonic-gate return (DUP_ERROR); 20457c478bd9Sstevel@tonic-gate } 20467c478bd9Sstevel@tonic-gate 20477c478bd9Sstevel@tonic-gate return (rc); 20487c478bd9Sstevel@tonic-gate } 20497c478bd9Sstevel@tonic-gate 20507c478bd9Sstevel@tonic-gate /* 20517c478bd9Sstevel@tonic-gate * __svc_dupcache_update(struct svc_req *req, caddr_t resp_buf, 20527c478bd9Sstevel@tonic-gate * uint_t resp_bufsz, int status, struct dupcache *dc, uint32_t drxid, 20537c478bd9Sstevel@tonic-gate * uint32_t drhash) 20547c478bd9Sstevel@tonic-gate * Check if entry exists in the dupcacache. If it does, update its status 20557c478bd9Sstevel@tonic-gate * and time and also its buffer, if appropriate. Its possible, but unlikely 20567c478bd9Sstevel@tonic-gate * for DONE requests to not exist in the cache. Return DUP_ERROR or status. 20577c478bd9Sstevel@tonic-gate */ 20587c478bd9Sstevel@tonic-gate static int 20597c478bd9Sstevel@tonic-gate __svc_dupcache_update(struct svc_req *req, caddr_t resp_buf, uint_t resp_bufsz, 20607c478bd9Sstevel@tonic-gate int status, struct dupcache *dc, uint32_t drxid, uint32_t drhash) 20617c478bd9Sstevel@tonic-gate { 20627c478bd9Sstevel@tonic-gate struct dupreq *dr = NULL; 20637c478bd9Sstevel@tonic-gate time_t timenow = time(NULL); 20647c478bd9Sstevel@tonic-gate 2065*61961e0fSrobinson (void) rw_wrlock(&(dc->dc_lock)); 20667c478bd9Sstevel@tonic-gate dr = dc->dc_hashtbl[drhash]; 20677c478bd9Sstevel@tonic-gate while (dr != NULL) { 20687c478bd9Sstevel@tonic-gate if (dr->dr_xid == drxid && 20697c478bd9Sstevel@tonic-gate dr->dr_proc == req->rq_proc && 20707c478bd9Sstevel@tonic-gate dr->dr_prog == req->rq_prog && 20717c478bd9Sstevel@tonic-gate dr->dr_vers == req->rq_vers && 20727c478bd9Sstevel@tonic-gate dr->dr_addr.len == req->rq_xprt->xp_rtaddr.len && 2073*61961e0fSrobinson memcmp(dr->dr_addr.buf, 2074*61961e0fSrobinson req->rq_xprt->xp_rtaddr.buf, 20757c478bd9Sstevel@tonic-gate dr->dr_addr.len) == 0) { /* entry found */ 20767c478bd9Sstevel@tonic-gate if (dr->dr_hash != drhash) { 20777c478bd9Sstevel@tonic-gate /* sanity check */ 2078*61961e0fSrobinson (void) rw_unlock(&(dc->dc_lock)); 20797c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 20807c478bd9Sstevel@tonic-gate "\n__svc_dupdone: hashing error"); 20817c478bd9Sstevel@tonic-gate return (DUP_ERROR); 20827c478bd9Sstevel@tonic-gate } 20837c478bd9Sstevel@tonic-gate 20847c478bd9Sstevel@tonic-gate /* store the results if bufer is not NULL */ 20857c478bd9Sstevel@tonic-gate if (resp_buf != NULL) { 2086*61961e0fSrobinson if ((dr->dr_resp.buf = 2087*61961e0fSrobinson malloc(resp_bufsz)) == NULL) { 2088*61961e0fSrobinson (void) rw_unlock(&(dc->dc_lock)); 20897c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 2090*61961e0fSrobinson "__svc_dupdone: malloc failed"); 20917c478bd9Sstevel@tonic-gate return (DUP_ERROR); 20927c478bd9Sstevel@tonic-gate } 2093*61961e0fSrobinson (void) memset(dr->dr_resp.buf, 0, resp_bufsz); 2094*61961e0fSrobinson (void) memcpy(dr->dr_resp.buf, resp_buf, 20957c478bd9Sstevel@tonic-gate (uint_t)resp_bufsz); 20967c478bd9Sstevel@tonic-gate dr->dr_resp.len = resp_bufsz; 20977c478bd9Sstevel@tonic-gate } 20987c478bd9Sstevel@tonic-gate 20997c478bd9Sstevel@tonic-gate /* update status and done time */ 21007c478bd9Sstevel@tonic-gate dr->dr_status = status; 21017c478bd9Sstevel@tonic-gate dr->dr_time = timenow; 21027c478bd9Sstevel@tonic-gate 21037c478bd9Sstevel@tonic-gate /* move the entry to the mru position */ 21047c478bd9Sstevel@tonic-gate if (dc->dc_mru == NULL) { 21057c478bd9Sstevel@tonic-gate dr->dr_next = dr; 21067c478bd9Sstevel@tonic-gate dr->dr_prev = dr; 21077c478bd9Sstevel@tonic-gate } else { 21087c478bd9Sstevel@tonic-gate dr->dr_next = dc->dc_mru->dr_next; 21097c478bd9Sstevel@tonic-gate dc->dc_mru->dr_next->dr_prev = dr; 21107c478bd9Sstevel@tonic-gate dr->dr_prev = dc->dc_mru; 21117c478bd9Sstevel@tonic-gate dc->dc_mru->dr_next = dr; 21127c478bd9Sstevel@tonic-gate } 21137c478bd9Sstevel@tonic-gate dc->dc_mru = dr; 21147c478bd9Sstevel@tonic-gate 2115*61961e0fSrobinson (void) rw_unlock(&(dc->dc_lock)); 21167c478bd9Sstevel@tonic-gate return (status); 21177c478bd9Sstevel@tonic-gate } 21187c478bd9Sstevel@tonic-gate dr = dr->dr_chain; 21197c478bd9Sstevel@tonic-gate } 2120*61961e0fSrobinson (void) rw_unlock(&(dc->dc_lock)); 21217c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "__svc_dupdone: entry not in dup cache"); 21227c478bd9Sstevel@tonic-gate return (DUP_ERROR); 21237c478bd9Sstevel@tonic-gate } 21247c478bd9Sstevel@tonic-gate 21257c478bd9Sstevel@tonic-gate #ifdef DUP_DEBUG 21267c478bd9Sstevel@tonic-gate /* 21277c478bd9Sstevel@tonic-gate * __svc_dupcache_debug(struct dupcache *dc) 21287c478bd9Sstevel@tonic-gate * print out the hash table stuff 21297c478bd9Sstevel@tonic-gate * 21307c478bd9Sstevel@tonic-gate * This function requires the caller to hold the reader 21317c478bd9Sstevel@tonic-gate * or writer version of the duplicate request cache lock (dc_lock). 21327c478bd9Sstevel@tonic-gate */ 21337c478bd9Sstevel@tonic-gate static void 21347c478bd9Sstevel@tonic-gate __svc_dupcache_debug(struct dupcache *dc) 21357c478bd9Sstevel@tonic-gate { 21367c478bd9Sstevel@tonic-gate struct dupreq *dr = NULL; 21377c478bd9Sstevel@tonic-gate int i; 21387c478bd9Sstevel@tonic-gate bool_t bval; 21397c478bd9Sstevel@tonic-gate 21407c478bd9Sstevel@tonic-gate fprintf(stderr, " HASHTABLE\n"); 21417c478bd9Sstevel@tonic-gate for (i = 0; i < dc->dc_buckets; i++) { 21427c478bd9Sstevel@tonic-gate bval = FALSE; 21437c478bd9Sstevel@tonic-gate dr = dc->dc_hashtbl[i]; 21447c478bd9Sstevel@tonic-gate while (dr != NULL) { 21457c478bd9Sstevel@tonic-gate if (!bval) { /* ensures bucket printed only once */ 21467c478bd9Sstevel@tonic-gate fprintf(stderr, " bucket : %d\n", i); 21477c478bd9Sstevel@tonic-gate bval = TRUE; 21487c478bd9Sstevel@tonic-gate } 21497c478bd9Sstevel@tonic-gate fprintf(stderr, "\txid: %u status: %d time: %ld", 21507c478bd9Sstevel@tonic-gate dr->dr_xid, dr->dr_status, dr->dr_time); 21517c478bd9Sstevel@tonic-gate fprintf(stderr, " dr: %x chain: %x prevchain: %x\n", 21527c478bd9Sstevel@tonic-gate dr, dr->dr_chain, dr->dr_prevchain); 21537c478bd9Sstevel@tonic-gate dr = dr->dr_chain; 21547c478bd9Sstevel@tonic-gate } 21557c478bd9Sstevel@tonic-gate } 21567c478bd9Sstevel@tonic-gate 21577c478bd9Sstevel@tonic-gate fprintf(stderr, " LRU\n"); 21587c478bd9Sstevel@tonic-gate if (dc->dc_mru) { 21597c478bd9Sstevel@tonic-gate dr = dc->dc_mru->dr_next; /* lru */ 21607c478bd9Sstevel@tonic-gate while (dr != dc->dc_mru) { 21617c478bd9Sstevel@tonic-gate fprintf(stderr, "\txid: %u status : %d time : %ld", 21627c478bd9Sstevel@tonic-gate dr->dr_xid, dr->dr_status, dr->dr_time); 21637c478bd9Sstevel@tonic-gate fprintf(stderr, " dr: %x next: %x prev: %x\n", 21647c478bd9Sstevel@tonic-gate dr, dr->dr_next, dr->dr_prev); 21657c478bd9Sstevel@tonic-gate dr = dr->dr_next; 21667c478bd9Sstevel@tonic-gate } 21677c478bd9Sstevel@tonic-gate fprintf(stderr, "\txid: %u status: %d time: %ld", 21687c478bd9Sstevel@tonic-gate dr->dr_xid, dr->dr_status, dr->dr_time); 21697c478bd9Sstevel@tonic-gate fprintf(stderr, " dr: %x next: %x prev: %x\n", dr, 21707c478bd9Sstevel@tonic-gate dr->dr_next, dr->dr_prev); 21717c478bd9Sstevel@tonic-gate } 21727c478bd9Sstevel@tonic-gate } 21737c478bd9Sstevel@tonic-gate #endif /* DUP_DEBUG */ 2174