/* $NetBSD: svc.h,v 1.17 2000/06/02 22:57:56 fvdl Exp $ */12/*-3* SPDX-License-Identifier: BSD-3-Clause4*5* Copyright (c) 2009, Sun Microsystems, Inc.6* All rights reserved.7*8* Redistribution and use in source and binary forms, with or without9* modification, are permitted provided that the following conditions are met:10* - Redistributions of source code must retain the above copyright notice,11* this list of conditions and the following disclaimer.12* - Redistributions in binary form must reproduce the above copyright notice,13* this list of conditions and the following disclaimer in the documentation14* and/or other materials provided with the distribution.15* - Neither the name of Sun Microsystems, Inc. nor the names of its16* contributors may be used to endorse or promote products derived17* from this software without specific prior written permission.18*19* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"20* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE21* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE22* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE23* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR24* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF25* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS26* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN27* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)28* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE29* POSSIBILITY OF SUCH DAMAGE.30*/3132/*33* svc.h, Server-side remote procedure call interface.34*35* Copyright (C) 1986-1993 by Sun Microsystems, Inc.36*/3738#ifndef _RPC_SVC_H39#define _RPC_SVC_H40#include <sys/cdefs.h>4142#include <sys/queue.h>43#include <sys/_lock.h>44#include <sys/_mutex.h>45#include <sys/_sx.h>46#include <sys/condvar.h>47#include <sys/sysctl.h>4849/*50* This interface must manage two items concerning remote procedure calling:51*52* 1) An arbitrary number of transport connections upon which rpc requests53* are received. The two most notable transports are TCP and UDP; they are54* created and registered by routines in svc_tcp.c and svc_udp.c, respectively;55* they in turn call xprt_register and xprt_unregister.56*57* 2) An arbitrary number of locally registered services. Services are58* described by the following four data: program number, version number,59* "service dispatch" function, a transport handle, and a boolean that60* indicates whether or not the exported program should be registered with a61* local binder service; if true the program's number and version and the62* port number from the transport handle are registered with the binder.63* These data are registered with the rpc svc system via svc_register.64*65* A service's dispatch function is called whenever an rpc request comes in66* on a transport. The request's program and version numbers must match67* those of the registered service. The dispatch function is passed two68* parameters, struct svc_req * and SVCXPRT *, defined below.69*/7071/*72* Service control requests73*/74#define SVCGET_VERSQUIET 175#define SVCSET_VERSQUIET 276#define SVCGET_CONNMAXREC 377#define SVCSET_CONNMAXREC 47879/*80* Operations for rpc_control().81*/82#define RPC_SVC_CONNMAXREC_SET 0 /* set max rec size, enable nonblock */83#define RPC_SVC_CONNMAXREC_GET 18485enum xprt_stat {86XPRT_DIED,87XPRT_MOREREQS,88XPRT_IDLE89};9091struct __rpc_svcxprt;92struct mbuf;9394struct xp_ops {95/* receive incoming requests */96bool_t (*xp_recv)(struct __rpc_svcxprt *, struct rpc_msg *,97struct sockaddr **, struct mbuf **);98/* get transport status */99enum xprt_stat (*xp_stat)(struct __rpc_svcxprt *);100/* get transport acknowledge sequence */101bool_t (*xp_ack)(struct __rpc_svcxprt *, uint32_t *);102/* send reply */103bool_t (*xp_reply)(struct __rpc_svcxprt *, struct rpc_msg *,104struct sockaddr *, struct mbuf *, uint32_t *);105/* destroy this struct */106void (*xp_destroy)(struct __rpc_svcxprt *);107/* catch-all function */108bool_t (*xp_control)(struct __rpc_svcxprt *, const u_int, void *);109};110111struct __rpc_svcpool;112struct __rpc_svcgroup;113struct __rpc_svcthread;114115/*116* Server side transport handle. In the kernel, transports have a117* reference count which tracks the number of currently assigned118* worker threads plus one for the service pool's reference.119* For NFSv4.1 sessions, a reference is also held for a backchannel.120* xp_p2 - Points to the CLIENT structure for the RPC server end121* (the client end for callbacks).122* Points to the private structure (cl_private) for the123* CLIENT structure for the RPC client end (the server124* end for callbacks).125*/126typedef struct __rpc_svcxprt {127volatile u_int xp_refs;128struct sx xp_lock;129struct __rpc_svcpool *xp_pool; /* owning pool (see below) */130struct __rpc_svcgroup *xp_group; /* owning group (see below) */131TAILQ_ENTRY(__rpc_svcxprt) xp_link;132TAILQ_ENTRY(__rpc_svcxprt) xp_alink;133bool_t xp_registered; /* xprt_register has been called */134bool_t xp_active; /* xprt_active has been called */135struct __rpc_svcthread *xp_thread; /* assigned service thread */136struct socket* xp_socket;137const struct xp_ops *xp_ops;138char *xp_netid; /* network token */139struct sockaddr_storage xp_ltaddr; /* local transport address */140struct sockaddr_storage xp_rtaddr; /* remote transport address */141void *xp_p1; /* private: for use by svc ops */142void *xp_p2; /* private: for use by svc ops */143void *xp_p3; /* private: for use by svc lib */144int xp_type; /* transport type */145int xp_idletimeout; /* idle time before closing */146time_t xp_lastactive; /* time of last RPC */147uint64_t xp_sockref; /* set by nfsv4 to identify socket */148int xp_upcallset; /* socket upcall is set up */149uint32_t xp_snd_cnt; /* # of bytes to send to socket */150uint32_t xp_snt_cnt; /* # of bytes sent to socket */151bool_t xp_dontrcv; /* Do not receive on the socket */152uint32_t xp_tls; /* RPC-over-TLS on socket */153int xp_ngrps; /* Cred. from TLS cert. */154uid_t xp_uid;155gid_t *xp_gidp;156int xp_doneddp;157} SVCXPRT;158159/*160* Interface to server-side authentication flavors.161*/162typedef struct __rpc_svcauth {163const struct svc_auth_ops {164int (*svc_ah_wrap)(struct __rpc_svcauth *, struct mbuf **);165int (*svc_ah_unwrap)(struct __rpc_svcauth *, struct mbuf **);166void (*svc_ah_release)(struct __rpc_svcauth *);167} *svc_ah_ops;168void *svc_ah_private;169} SVCAUTH;170171/*172* Server transport extensions (accessed via xp_p3).173*/174typedef struct __rpc_svcxprt_ext {175int xp_flags; /* versquiet */176SVCAUTH xp_auth; /* interface to auth methods */177} SVCXPRT_EXT;178179/*180* The services list181* Each entry represents a set of procedures (an rpc program).182* The dispatch routine takes request structs and runs the183* appropriate procedure.184*/185struct svc_callout {186TAILQ_ENTRY(svc_callout) sc_link;187rpcprog_t sc_prog;188rpcvers_t sc_vers;189char *sc_netid;190void (*sc_dispatch)(struct svc_req *, SVCXPRT *);191};192TAILQ_HEAD(svc_callout_list, svc_callout);193194/*195* The services connection loss list196* The dispatch routine takes request structs and runs the197* appropriate procedure.198*/199struct svc_loss_callout {200TAILQ_ENTRY(svc_loss_callout) slc_link;201void (*slc_dispatch)(SVCXPRT *);202};203TAILQ_HEAD(svc_loss_callout_list, svc_loss_callout);204205/*206* Service request207*/208struct svc_req {209STAILQ_ENTRY(svc_req) rq_link; /* list of requests for a thread */210struct __rpc_svcthread *rq_thread; /* thread which is to execute this */211uint32_t rq_xid; /* RPC transaction ID */212uint32_t rq_prog; /* service program number */213uint32_t rq_vers; /* service protocol version */214uint32_t rq_proc; /* the desired procedure */215size_t rq_size; /* space used by request */216struct mbuf *rq_args; /* XDR-encoded procedure arguments */217struct opaque_auth rq_cred; /* raw creds from the wire */218struct opaque_auth rq_verf; /* verifier for the reply */219void *rq_clntcred; /* read only cooked cred */220SVCAUTH rq_auth; /* interface to auth methods */221SVCXPRT *rq_xprt; /* associated transport */222struct sockaddr *rq_addr; /* reply address or NULL if connected */223void *rq_p1; /* application workspace */224int rq_p2; /* application workspace */225uint64_t rq_p3; /* application workspace */226uint32_t rq_reply_seq; /* reply socket sequence # */227char rq_credarea[3*MAX_AUTH_BYTES];228};229STAILQ_HEAD(svc_reqlist, svc_req);230231#define svc_getrpccaller(rq) \232((rq)->rq_addr ? (rq)->rq_addr : \233(struct sockaddr *) &(rq)->rq_xprt->xp_rtaddr)234235/*236* This structure is used to manage a thread which is executing237* requests from a service pool. A service thread is in one of three238* states:239*240* SVCTHREAD_SLEEPING waiting for a request to process241* SVCTHREAD_ACTIVE processing a request242* SVCTHREAD_EXITING exiting after finishing current request243*244* Threads which have no work to process sleep on the pool's sp_active245* list. When a transport becomes active, it is assigned a service246* thread to read and execute pending RPCs.247*/248typedef struct __rpc_svcthread {249struct mtx_padalign st_lock; /* protects st_reqs field */250struct __rpc_svcpool *st_pool;251SVCXPRT *st_xprt; /* transport we are processing */252struct svc_reqlist st_reqs; /* RPC requests to execute */253struct cv st_cond; /* sleeping for work */254LIST_ENTRY(__rpc_svcthread) st_ilink; /* idle threads list */255LIST_ENTRY(__rpc_svcthread) st_alink; /* application thread list */256int st_p2; /* application workspace */257uint64_t st_p3; /* application workspace */258} SVCTHREAD;259LIST_HEAD(svcthread_list, __rpc_svcthread);260261/*262* A thread group contain all information needed to assign subset of263* transports to subset of threads. On systems with many CPUs and many264* threads that allows to reduce lock congestion and improve performance.265* Hundreds of threads on dozens of CPUs sharing the single pool lock do266* not scale well otherwise.267*/268TAILQ_HEAD(svcxprt_list, __rpc_svcxprt);269enum svcpool_state {270SVCPOOL_INIT, /* svc_run not called yet */271SVCPOOL_ACTIVE, /* normal running state */272SVCPOOL_THREADWANTED, /* new service thread requested */273SVCPOOL_THREADSTARTING, /* new service thread started */274SVCPOOL_CLOSING /* svc_exit called */275};276typedef struct __rpc_svcgroup {277struct mtx_padalign sg_lock; /* protect the thread/req lists */278struct __rpc_svcpool *sg_pool;279enum svcpool_state sg_state; /* current pool state */280struct svcxprt_list sg_xlist; /* all transports in the group */281struct svcxprt_list sg_active; /* transports needing service */282struct svcthread_list sg_idlethreads; /* idle service threads */283284int sg_minthreads; /* minimum service thread count */285int sg_maxthreads; /* maximum service thread count */286int sg_threadcount; /* current service thread count */287time_t sg_lastcreatetime; /* when we last started a thread */288time_t sg_lastidlecheck; /* when we last checked idle transports */289} SVCGROUP;290291/*292* In the kernel, we can't use global variables to store lists of293* transports etc. since otherwise we could not have two unrelated RPC294* services running, each on its own thread. We solve this by295* importing a tiny part of a Solaris kernel concept, SVCPOOL.296*297* A service pool contains a set of transports and service callbacks298* for a set of related RPC services. The pool handle should be passed299* when creating new transports etc. Future work may include extending300* this to support something similar to the Solaris multi-threaded RPC301* server.302*/303typedef SVCTHREAD *pool_assign_fn(SVCTHREAD *, struct svc_req *);304typedef void pool_done_fn(SVCTHREAD *, struct svc_req *);305#define SVC_MAXGROUPS 16306typedef struct __rpc_svcpool {307struct mtx_padalign sp_lock; /* protect the transport lists */308const char *sp_name; /* pool name (e.g. "nfsd", "NLM" */309enum svcpool_state sp_state; /* current pool state */310struct proc *sp_proc; /* process which is in svc_run */311struct svc_callout_list sp_callouts; /* (prog,vers)->dispatch list */312struct svc_loss_callout_list sp_lcallouts; /* loss->dispatch list */313int sp_minthreads; /* minimum service thread count */314int sp_maxthreads; /* maximum service thread count */315316/*317* Hooks to allow an application to control request to thread318* placement.319*/320pool_assign_fn *sp_assign;321pool_done_fn *sp_done;322323/*324* These variables are used to put an upper bound on the325* amount of memory used by RPC requests which are queued326* waiting for execution.327*/328unsigned long sp_space_low;329unsigned long sp_space_high;330unsigned long sp_space_used;331unsigned long sp_space_used_highest;332bool_t sp_space_throttled;333int sp_space_throttle_count;334335struct replay_cache *sp_rcache; /* optional replay cache */336struct sysctl_ctx_list sp_sysctl;337338int sp_groupcount; /* Number of groups in the pool. */339int sp_nextgroup; /* Next group to assign port. */340SVCGROUP sp_groups[SVC_MAXGROUPS]; /* Thread/port groups. */341} SVCPOOL;342343/*344* Operations defined on an SVCXPRT handle345*346* SVCXPRT *xprt;347* struct rpc_msg *msg;348* xdrproc_t xargs;349* void * argsp;350*/351#define SVC_ACQUIRE(xprt) \352refcount_acquire(&(xprt)->xp_refs)353354#define SVC_RELEASE(xprt) \355if (refcount_release(&(xprt)->xp_refs)) \356SVC_DESTROY(xprt)357358#define SVC_RECV(xprt, msg, addr, args) \359(*(xprt)->xp_ops->xp_recv)((xprt), (msg), (addr), (args))360361#define SVC_STAT(xprt) \362(*(xprt)->xp_ops->xp_stat)(xprt)363364#define SVC_ACK(xprt, ack) \365((xprt)->xp_ops->xp_ack == NULL ? FALSE : \366((ack) == NULL ? TRUE : (*(xprt)->xp_ops->xp_ack)((xprt), (ack))))367368#define SVC_REPLY(xprt, msg, addr, m, seq) \369(*(xprt)->xp_ops->xp_reply) ((xprt), (msg), (addr), (m), (seq))370371#define SVC_DESTROY(xprt) \372(*(xprt)->xp_ops->xp_destroy)(xprt)373374#define SVC_CONTROL(xprt, rq, in) \375(*(xprt)->xp_ops->xp_control)((xprt), (rq), (in))376377#define SVC_EXT(xprt) \378((SVCXPRT_EXT *) xprt->xp_p3)379380#define SVC_AUTH(xprt) \381(SVC_EXT(xprt)->xp_auth)382383/*384* Operations defined on an SVCAUTH handle385*/386#define SVCAUTH_WRAP(auth, mp) \387((auth)->svc_ah_ops->svc_ah_wrap(auth, mp))388#define SVCAUTH_UNWRAP(auth, mp) \389((auth)->svc_ah_ops->svc_ah_unwrap(auth, mp))390#define SVCAUTH_RELEASE(auth) \391((auth)->svc_ah_ops->svc_ah_release(auth))392393/*394* Service registration395*396* svc_reg(xprt, prog, vers, dispatch, nconf)397* const SVCXPRT *xprt;398* const rpcprog_t prog;399* const rpcvers_t vers;400* const void (*dispatch)();401* const struct netconfig *nconf;402*/403404__BEGIN_DECLS405extern bool_t svc_reg(SVCXPRT *, const rpcprog_t, const rpcvers_t,406void (*)(struct svc_req *, SVCXPRT *),407const struct netconfig *);408__END_DECLS409410/*411* Service un-registration412*413* svc_unreg(prog, vers)414* const rpcprog_t prog;415* const rpcvers_t vers;416*/417418__BEGIN_DECLS419extern void svc_unreg(SVCPOOL *, const rpcprog_t, const rpcvers_t);420__END_DECLS421422/*423* Service connection loss registration424*425* svc_loss_reg(xprt, dispatch)426* const SVCXPRT *xprt;427* const void (*dispatch)();428*/429430__BEGIN_DECLS431extern bool_t svc_loss_reg(SVCXPRT *, void (*)(SVCXPRT *));432__END_DECLS433434/*435* Service connection loss un-registration436*437* svc_loss_unreg(xprt, dispatch)438* const SVCXPRT *xprt;439* const void (*dispatch)();440*/441442__BEGIN_DECLS443extern void svc_loss_unreg(SVCPOOL *, void (*)(SVCXPRT *));444__END_DECLS445446/*447* Transport registration.448*449* xprt_register(xprt)450* SVCXPRT *xprt;451*/452__BEGIN_DECLS453extern void xprt_register(SVCXPRT *);454__END_DECLS455456/*457* Transport un-register458*459* xprt_unregister(xprt)460* SVCXPRT *xprt;461*/462__BEGIN_DECLS463extern void xprt_unregister(SVCXPRT *);464extern void __xprt_unregister_unlocked(SVCXPRT *);465__END_DECLS466467/*468* Called when a transport has pending requests.469*/470__BEGIN_DECLS471extern void xprt_active(SVCXPRT *);472extern void xprt_inactive(SVCXPRT *);473extern void xprt_inactive_locked(SVCXPRT *);474extern void xprt_inactive_self(SVCXPRT *);475__END_DECLS476477/*478* When the service routine is called, it must first check to see if it479* knows about the procedure; if not, it should call svcerr_noproc480* and return. If so, it should deserialize its arguments via481* SVC_GETARGS (defined above). If the deserialization does not work,482* svcerr_decode should be called followed by a return. Successful483* decoding of the arguments should be followed the execution of the484* procedure's code and a call to svc_sendreply.485*486* Also, if the service refuses to execute the procedure due to too-487* weak authentication parameters, svcerr_weakauth should be called.488* Note: do not confuse access-control failure with weak authentication!489*490* NB: In pure implementations of rpc, the caller always waits for a reply491* msg. This message is sent when svc_sendreply is called.492* Therefore pure service implementations should always call493* svc_sendreply even if the function logically returns void; use494* xdr.h - xdr_void for the xdr routine. HOWEVER, tcp based rpc allows495* for the abuse of pure rpc via batched calling or pipelining. In the496* case of a batched call, svc_sendreply should NOT be called since497* this would send a return message, which is what batching tries to avoid.498* It is the service/protocol writer's responsibility to know which calls are499* batched and which are not. Warning: responding to batch calls may500* deadlock the caller and server processes!501*/502503__BEGIN_DECLS504extern bool_t svc_sendreply(struct svc_req *, xdrproc_t, void *);505extern bool_t svc_sendreply_mbuf(struct svc_req *, struct mbuf *);506extern void svcerr_decode(struct svc_req *);507extern void svcerr_weakauth(struct svc_req *);508extern void svcerr_noproc(struct svc_req *);509extern void svcerr_progvers(struct svc_req *, rpcvers_t, rpcvers_t);510extern void svcerr_auth(struct svc_req *, enum auth_stat);511extern void svcerr_noprog(struct svc_req *);512extern void svcerr_systemerr(struct svc_req *);513extern int rpc_reg(rpcprog_t, rpcvers_t, rpcproc_t,514char *(*)(char *), xdrproc_t, xdrproc_t,515char *);516__END_DECLS517518/*519* Lowest level dispatching -OR- who owns this process anyway.520* Somebody has to wait for incoming requests and then call the correct521* service routine. The routine svc_run does infinite waiting; i.e.,522* svc_run never returns.523* Since another (co-existent) package may wish to selectively wait for524* incoming calls or other events outside of the rpc architecture, the525* routine svc_getreq is provided. It must be passed readfds, the526* "in-place" results of a select system call (see select, section 2).527*/528529/*530* a small program implemented by the svc_rpc implementation itself;531* also see clnt.h for protocol numbers.532*/533__BEGIN_DECLS534extern void rpctest_service(void);535__END_DECLS536537__BEGIN_DECLS538extern SVCXPRT *svc_xprt_alloc(void);539extern void svc_xprt_free(SVCXPRT *);540extern void svc_run(SVCPOOL *);541extern void svc_exit(SVCPOOL *);542extern bool_t svc_getargs(struct svc_req *, xdrproc_t, void *);543extern bool_t svc_freeargs(struct svc_req *, xdrproc_t, void *);544extern void svc_freereq(struct svc_req *);545__END_DECLS546547/*548* Socket to use on svcxxx_create call to get default socket549*/550#define RPC_ANYSOCK -1551#define RPC_ANYFD RPC_ANYSOCK552553/*554* These are the existing service side transport implementations555*/556557__BEGIN_DECLS558559/*560* Create a new service pool.561*/562extern SVCPOOL* svcpool_create(const char *name,563struct sysctl_oid_list *sysctl_base);564565/*566* Destroy a service pool, including all registered transports.567*/568extern void svcpool_destroy(SVCPOOL *pool);569570/*571* Close a service pool. Similar to svcpool_destroy(), but it does not572* free the data structures. As such, the pool can be used again.573*/574extern void svcpool_close(SVCPOOL *pool);575576/*577* Generic server creation routine. It takes a netconfig structure578* instead of a nettype.579*/580581extern SVCXPRT *svc_tp_create(SVCPOOL *, void (*)(struct svc_req *, SVCXPRT *),582const rpcprog_t, const rpcvers_t, const char *uaddr,583const struct netconfig *);584/*585* void (*dispatch)(); -- dispatch routine586* const rpcprog_t prognum; -- program number587* const rpcvers_t versnum; -- version number588* const char *uaddr; -- universal address of service589* const struct netconfig *nconf; -- netconfig structure590*/591592extern SVCXPRT *svc_dg_create(SVCPOOL *, struct socket *,593const size_t, const size_t);594/*595* struct socket *; -- open connection596* const size_t sendsize; -- max send size597* const size_t recvsize; -- max recv size598*/599600extern SVCXPRT *svc_vc_create(SVCPOOL *, struct socket *,601const size_t, const size_t);602/*603* struct socket *; -- open connection604* const size_t sendsize; -- max send size605* const size_t recvsize; -- max recv size606*/607608extern SVCXPRT *svc_vc_create_backchannel(SVCPOOL *);609610extern void *clnt_bck_create(struct socket *, const rpcprog_t, const rpcvers_t);611/*612* struct socket *; -- server transport socket613* const rpcprog_t prog; -- RPC program number614* const rpcvers_t vers; -- RPC program version615*/616617/*618* Generic TLI create routine619*/620extern SVCXPRT *svc_tli_create(SVCPOOL *, const struct netconfig *,621const struct t_bind *, const size_t, const size_t);622/*623* const struct netconfig *nconf; -- netconfig structure for network624* const struct t_bind *bindaddr; -- local bind address625* const size_t sendsz; -- max sendsize626* const size_t recvsz; -- max recvsize627*/628__END_DECLS629630#endif /* !_RPC_SVC_H */631632633