2N/A * The contents of this file are subject to the terms of the 2N/A * Common Development and Distribution License (the "License"). 2N/A * You may not use this file except in compliance with the License. 2N/A * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 2N/A * If applicable, add the following below this CDDL HEADER, with the 2N/A * fields enclosed by brackets "[]" replaced with your own identifying 2N/A * information: Portions Copyright [yyyy] [name of copyright owner] 2N/A * Copyright (c) 1989, 2011, Oracle and/or its affiliates. All rights reserved. 2N/A * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. 2N/A/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 2N/A/* All Rights Reserved */ 2N/A * Portions of this source code were derived from Berkeley 2N/A * 4.3 BSD under license from the Regents of the University of 2N/A * svc.c, Server-side remote procedure call interface. 2N/A * There are two sets of procedures here. The xprt routines are 2N/A * for handling transport handles. The svc routines handle the 2N/A * list of service routines. 2N/A * Each entry represents a set of procedures (an rpc program). 2N/A * The dispatch routine takes request structs and runs the 2N/A * appropriate procedure. 2N/A * If the allocated array of reactor is too small, this value is used as a 2N/A * margin. This reduces the number of allocations. 2N/A * Data used to handle reactor: 2N/A * - one file descriptor we listen to, 2N/A * - one callback we call if the fd pops, 2N/A * - and a cookie passed as a parameter to the callback. 2N/A * The structure is an array indexed on the file descriptor. Each entry is 2N/A * pointing to the first element of a double-linked list of callback. 2N/A * only one callback may be associated to a couple (fd, event). 2N/A /* The lnk field must be the first field. */ 2N/A /* The lnk field must be the first field. */ 2N/A unsigned int mask;
/* logical OR of all sub-masks */ 2N/A/* Define some macros to manage the linked list. */ 2N/A/* Array of defined reactor - indexed on file descriptor */ 2N/A/* current size of file descriptor */ 2N/A/* Mutex to ensure MT safe operations for user fds callbacks. */ 2N/A * This structure is used to have constant time alogrithms. There is an array 2N/A * of this structure as large as svc_nuserfds. When the user is registering a 2N/A * new callback, the address of the created structure is stored in a cell of 2N/A * this array. The address of this cell is the returned unique identifier. 2N/A * On removing, the id is given by the user, then we know if this cell is 2N/A * filled or not (with free). If it is free, we return an error. Otherwise, 2N/A * we can free the structure pointed by fd_node. 2N/A * On insertion, we use the linked list created by (first_free, 2N/A * next_free). In this way with a constant time computation, we can give a 2N/A * correct index to the user. 2N/A/* index to the first free elem */ 2N/A/* the size of this array is the same as svc_nuserfds */ 2N/A/* current size of user_fd_mgt_array */ 2N/A/* Define some macros to access data associated to registration ids. */ 2N/A * To free an Id, we set the cell as free and insert its address in the list 2N/A * To get a free cell, we just have to take it from the free linked list and 2N/A * set the flag to "not free". This function also allocates new memory if 2N/A /* Allocate new entries */ 2N/A * Access to a pollfd treatment. Scan all the associated callbacks that have 2N/A * at least one bit in their mask that masks a received event. 2N/A * If event POLLNVAL is received, we check that one callback processes it, if 2N/A * not, then remove the file descriptor from the poll. If there is one, let 2N/A * the user do the work. 2N/A /* check if at least one mask fits */ 2N/A * If one of the received events maps the ones the node listens 2N/A * The lock must be released before calling the 2N/A * user function, as this function can call 2N/A * svc_remove_input() for example. 2N/A * Do not use the node structure anymore, as it 2N/A * could have been deallocated by the previous 2N/A * Check if a file descriptor is associated with a user reactor. 2N/A * To do this, just check that the array indexed on fd has a non-void linked 2N/A * list (ie. first element is not NULL) 2N/A /* Checks argument */ 2N/A/* free everything concerning user fd */ 2N/A * Remove all the callback associated with a fd => useful when the fd is 2N/A * closed for instance 2N/A * Allow user to add an fd in the poll list. If it does not succeed, return 2N/A * -1. Otherwise, return a svc_id 2N/A /* Already registrated call-back */ 2N/A /* Handle memory allocation. */ 2N/A /* create a new node */ 2N/A /* Add the new element at the beginning of the list. */ 2N/A /* refresh global mask for this file desciptor */ 2N/A /* refresh mask for the poll */ 2N/A int fd;
/* caching optim */ 2N/A /* Immediately update data for id management */ 2N/A /* Remove this node from the list. */ 2N/A /* Remove the node flags from the global mask */ 2N/A /* <=> CLEAN NEEDED TO SHRINK MEMORY USAGE */ 2N/A * Provides default service-side functions for authentication flavors 2N/A * that do not use all the fields in struct svc_auth_ops. 2N/A * Return pointer to server authentication structure. 2N/A/* LINTED pointer alignment */ 2N/A * A callback routine to cleanup after a procedure is executed. 2N/A/* *************** SVCXPRT related stuff **************** */ 2N/A * Add fd to svc_pollfd 2N/A * give an error message; undo fdset setting 2N/A * above; reset the pollfd_shrinking flag. 2N/A * because of this poll will not be done 2N/A * the fd is still active but only the bit in fdset is cleared. 2N/A * do not subtract svc_nfds or svc_npollfds 2N/A * sets the bit in fdset for an active fd so that poll() is done for that 2N/A * remove a svc_pollfd entry; it does not shrink the memory 2N/A * delete a svc_pollfd entry; it shrinks the memory 2N/A * use remove_pollfd if you do not want to shrink 2N/A * Activate a transport handle. 2N/A/* VARIABLES PROTECTED BY svc_fd_lock: svc_xports, svc_fdset */ 2N/A /* allocate some small amount first */ 2N/A * XXX: This code does not keep track of the server state. 2N/A * This provides for callback support. When a client 2N/A * recv's a call from another client on the server fd's, 2N/A * it calls _svc_getreqset_proc() which would return 2N/A * after serving all the server requests. Also look under 2N/A /* time to expand svc_xprts */ 2N/A * This happens only in one of the MT modes. 2N/A * If already dispatching door based services, start 2N/A * dispatching TLI based services now. 2N/A /* allocate initial chunk */ 2N/A * De-activate a transport handle. 2N/A/* ********************** CALLOUT list related stuff ************* */ 2N/A * Add a service program to the callout list. 2N/A * The dispatch routine will be called when a rpc request for this 2N/A * program number comes in. 2N/A/* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */ 2N/A }
/* must have been created with svc_raw_create */ 2N/A goto rpcb_it;
/* he is registering another xptr */ 2N/A * The ordering of transports is such that the most frequently used 2N/A * one appears first. So add the new entry to the end of the list. 2N/A /* now register the information with the local binder service */ 2N/A * Remove a service program from the callout list. 2N/A /* unregister the information anyway */ 2N/A * Add a service program to the callout list. 2N/A * The dispatch routine will be called when a rpc request for this 2N/A * program number comes in. 2N/A * For version 2 portmappers. 2N/A /* fill in missing netid field in SVCXPRT */ 2N/A }
/* must be svc_raw_create */ 2N/A goto pmap_it;
/* he is registering another xptr */ 2N/A /* now register the information with the local binder service */ 2N/A * Remove a service program from the callout list. 2N/A * For version 2 portmappers. 2N/A /* unregister the information with the local binder service */ 2N/A * Search the callout list for a program number, return the callout 2N/A * Also check for transport as well. Many routines such as svc_unreg 2N/A * dont give any corresponding transport, so dont check for transport if 2N/A/* WRITE LOCK HELD ON ENTRY: svc_lock */ 2N/A/* assert(RW_WRITE_HELD(&svc_lock)); */ 2N/A/* ******************* REPLY GENERATION ROUTINES ************ */ 2N/A * Send a reply to an rpc request 2N/A * No procedure error reply 2N/A * Can't decode args error reply 2N/A * Tell RPC package to not complain about version errors to the client. This 2N/A * is useful when revving broadcast protocols that sit on a fixed address. 2N/A * There is really one (or should be only one) example of this kind of 2N/A * protocol: the portmapper (or rpc binder). 2N/A/* LINTED pointer alignment */ 2N/A/* LINTED pointer alignment */ 2N/A/* LINTED pointer alignment */ 2N/A * Authentication error reply 2N/A * Auth too weak error reply 2N/A * Program unavailable error reply 2N/A * Program version mismatch error reply 2N/A/* ******************* SERVER INPUT STUFF ******************* */ 2N/A * Get server side input from some transport. 2N/A * Statement of authentication parameters management: 2N/A * This function owns and manages all authentication parameters, specifically 2N/A * the "cooked" credentials (rqst->rq_clntcred). 2N/A * However, this function does not know the structure of the cooked 2N/A * credentials, so it make the following assumptions: 2N/A * a) the structure is contiguous (no pointers), and 2N/A * b) the cred structure size does not exceed RQCRED_SIZE bytes. 2N/A * In all events, all three parameters are freed upon exit from this routine. 2N/A * The storage is trivially management on the call stack in user land, but 2N/A * is mallocated in kernel land. 2N/A /* fd has input waiting */ 2N/A /* fd has input waiting */ 2N/A * We assume that this function is only called 2N/A * via someone select()ing from svc_fdset or 2N/A * poll()ing from svc_pollset[]. Thus it's safe 2N/A * to handle the POLLNVAL event by simply turning 2N/A * the corresponding bit off in svc_fdset. The 2N/A * svc_pollset[] array is derived from svc_fdset 2N/A * and so will also be updated eventually. 2N/A * XXX Should we do an xprt_unregister() instead? 2N/A /* Handle user callback */ 2N/A /* HANDLE USER CALLBACK */ 2N/A * The transport associated with this fd could have been 2N/A * removed from svc_timeout_nonblock_xprt_and_LRU, for instance. 2N/A * This can happen if two or more fds get read events and are 2N/A * the dispatch routine and cleans up any dead transports. If 2N/A * one of the dead transports removed is the other fd that 2N/A * had a read event then svc_getreq_common() will be called with no 2N/A * xprt associated with the fd that had the original read event. 2N/A/* LINTED pointer alignment */ 2N/A/* LINTED pointer alignment */ 2N/A/* LINTED pointer alignment */ 2N/A /* receive msgs from xprtprt (support batch calls) */ 2N/A * Check if the xprt has been disconnected in a recursive call 2N/A * in the service dispatch routine. If so, then break 2N/A * Call cleanup procedure if set. 2N/A/* LINTED pointer alignment */ 2N/A/* LINTED pointer alignment */ 2N/A /* first authenticate the message */ 2N/A /* Check for null flavor and bypass these calls if possible */ 2N/A /* match message with a registered service */ 2N/A }
/* found correct program */ 2N/A * if we got here, the program or version 2N/A/* LINTED pointer alignment */ 2N/A/* ******************* SVCXPRT allocation and deallocation ***************** */ 2N/A * svc_xprt_alloc() - allocate a service transport handle 2N/A/* LINTED pointer alignment */ 2N/A * svc_xprt_free() - free a service handle 2N/A/* LINTED pointer alignment */ 2N/A * svc_xprt_destroy() - free parent and child xprt list 2N/A/* LINTED pointer alignment */ 2N/A/* LINTED pointer alignment */ 2N/A/* LINTED pointer alignment */ 2N/A/* LINTED pointer alignment */ 2N/A * svc_copy() - make a copy of parent 2N/A/* LINTED pointer alignment */ 2N/A * _svc_destroy_private() - private SVC_DESTROY interface 2N/A/* LINTED pointer alignment */ 2N/A * svc_get_local_cred() - fetch local user credentials. This always 2N/A * works over doors based transports. For local transports, this 2N/A * does not yield correct results unless the __rpc_negotiate_uid() 2N/A * call has been invoked to enable this feature. 2N/A /* LINTED pointer alignment */ 2N/A/* ******************* DUPLICATE ENTRY HANDLING ROUTINES ************** */ 2N/A * the dup cacheing routines below provide a cache of received 2N/A * transactions. rpc service routines can use this to detect 2N/A * retransmissions and re-send a non-failure response. Uses a 2N/A * lru scheme to find entries to get rid of entries in the cache, 2N/A * though only DUP_DONE entries are placed on the lru list. 2N/A * the routines were written towards development of a generic 2N/A * SVC_DUP() interface, which can be expanded to encompass the 2N/A * svc_dg_enablecache() routines as well. the cache is currently 2N/A * private to the automounter. 2N/A/* dupcache header contains xprt specific information */ 2N/A * private duplicate cache request routines 2N/A#
endif /* DUP_DEBUG */ 2N/A/* default parameters for the dupcache */ 2N/A * __svc_dupcache_init(void *condition, int basis, char *xprt_cache) 2N/A * initialize the duprequest cache and assign it to the xprt_cache 2N/A * Use default values depending on the cache condition and basis. 2N/A * return TRUE on success and FALSE on failure 2N/A "__svc_dupcache_init: multiply defined dup cache");
2N/A "__svc_dupcache_init: memory alloc failed");
2N/A "__svc_dupcache_init: memory alloc failed");
2N/A "__svc_dupcache_init: undefined dup cache basis");
2N/A * __svc_dup(struct svc_req *req, caddr_t *resp_buf, uint_t *resp_bufsz, 2N/A * searches the request cache. Creates an entry and returns DUP_NEW if 2N/A * the request is not found in the cache. If it is found, then it 2N/A * returns the state of the request (in progress, drop, or done) and 2N/A * also allocates, and passes back results to the user (if any) in 2N/A * resp_buf, and its length in resp_bufsz. DUP_ERROR is returned on error. 2N/A /* LINTED pointer alignment */ 2N/A /* get the xid of the request */ 2N/A * __svc_dupcache_check(struct svc_req *req, caddr_t *resp_buf, 2N/A * uint_t *resp_bufsz,truct dupcache *dc, uint32_t drxid, 2N/A * Checks to see whether an entry already exists in the cache. If it does 2N/A * copy back into the resp_buf, if appropriate. Return the status of 2N/A * the request, or DUP_NEW if the entry is not in the cache 2N/A "\n__svc_dupdone: hashing error");
2N/A * return results for requests on lru list, if 2N/A * appropriate requests must be DUP_DROP or DUP_DONE 2N/A * to have a result. A NULL buffer in the cache 2N/A * implies no results were sent during dupdone. 2N/A * A NULL buffer in the call implies not interested 2N/A "__svc_dupcache_check: malloc failed");
2N/A * __svc_dupcache_victim(struct dupcache *dc, time_t timenow) 2N/A * Return a victim dupreq entry to the caller, depending on cache policy. 2N/A * The hash policy is to free up a bit of the hash 2N/A * table before allocating a new entry as the victim. 2N/A * Freeing up the hash table each time should split 2N/A * the cost of keeping the hash table clean among threads. 2N/A * Note that only DONE or DROPPED entries are on the lru 2N/A * list but we do a sanity check anyway. 2N/A /* clean and then free the entry */ 2N/A * The LRU list can't contain an 2N/A * entry where the status is other than 2N/A * DUP_DONE or DUP_DROP. 2N/A "__svc_dupcache_victim: bad victim");
2N/A * print the cache info, since we already 2N/A * hold the writers lock, we shall continue 2N/A * calling __svc_dupcache_debug() 2N/A#
endif /* DUP_DEBUG */ 2N/A /* unhash the entry */ 2N/A /* modify the lru pointers */ 2N/A * Allocate and return new clean entry as victim 2N/A "__svc_dupcache_victim: malloc failed");
2N/A "__svc_dupcache_victim: undefined dup cache_basis");
2N/A * __svc_dupcache_enter(struct svc_req *req, struct dupreq *dr, 2N/A * struct dupcache *dc, uint32_t drxid, uint32_t drhash, time_t timenow) 2N/A * build new duprequest entry and then insert into the cache 2N/A /* place entry at head of hash table */ 2N/A * __svc_dupdone(struct svc_req *req, caddr_t resp_buf, uint_t resp_bufsz, 2N/A * int status, char *xprt_cache) 2N/A * Marks the request done (DUP_DONE or DUP_DROP) and stores the response. 2N/A * Only DONE and DROP requests can be marked as done. Sets the lru pointers 2N/A * to make the entry the most recently used. Returns DUP_ERROR or status. 2N/A /* LINTED pointer alignment */ 2N/A /* find the xid of the entry in the cache */ 2N/A /* update the status of the entry and result buffers, if required */ 2N/A * __svc_dupcache_update(struct svc_req *req, caddr_t resp_buf, 2N/A * uint_t resp_bufsz, int status, struct dupcache *dc, uint32_t drxid, 2N/A * Check if entry exists in the dupcacache. If it does, update its status 2N/A * and time and also its buffer, if appropriate. Its possible, but unlikely 2N/A * for DONE requests to not exist in the cache. Return DUP_ERROR or status. 2N/A "\n__svc_dupdone: hashing error");
2N/A /* store the results if bufer is not NULL */ 2N/A "__svc_dupdone: malloc failed");
2N/A /* update status and done time */ 2N/A /* move the entry to the mru position */ 2N/A * __svc_dupcache_debug(struct dupcache *dc) 2N/A * print out the hash table stuff 2N/A * This function requires the caller to hold the reader 2N/A * or writer version of the duplicate request cache lock (dc_lock). 2N/A if (!
bval) {
/* ensures bucket printed only once */ 2N/A#
endif /* DUP_DEBUG */