diff --git a/sys/rpc/svc.h b/sys/rpc/svc.h index d8a8d0139cc4..92755a198488 100644 --- a/sys/rpc/svc.h +++ b/sys/rpc/svc.h @@ -1,648 +1,635 @@ /* $NetBSD: svc.h,v 1.17 2000/06/02 22:57:56 fvdl Exp $ */ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 2009, Sun Microsystems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of Sun Microsystems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * svc.h, Server-side remote procedure call interface. * * Copyright (C) 1986-1993 by Sun Microsystems, Inc. */ #ifndef _RPC_SVC_H #define _RPC_SVC_H #include #include #include #include #include #include #include /* * This interface must manage two items concerning remote procedure calling: * * 1) An arbitrary number of transport connections upon which rpc requests * are received. The two most notable transports are TCP and UDP; they are * created and registered by routines in svc_tcp.c and svc_udp.c, respectively; * they in turn call xprt_register and xprt_unregister. * * 2) An arbitrary number of locally registered services. Services are * described by the following four data: program number, version number, * "service dispatch" function, a transport handle, and a boolean that * indicates whether or not the exported program should be registered with a * local binder service; if true the program's number and version and the * port number from the transport handle are registered with the binder. * These data are registered with the rpc svc system via svc_register. * * A service's dispatch function is called whenever an rpc request comes in * on a transport. The request's program and version numbers must match * those of the registered service. The dispatch function is passed two * parameters, struct svc_req * and SVCXPRT *, defined below. */ /* * Service control requests */ #define SVCGET_VERSQUIET 1 #define SVCSET_VERSQUIET 2 #define SVCGET_CONNMAXREC 3 #define SVCSET_CONNMAXREC 4 /* * Operations for rpc_control(). */ #define RPC_SVC_CONNMAXREC_SET 0 /* set max rec size, enable nonblock */ #define RPC_SVC_CONNMAXREC_GET 1 enum xprt_stat { XPRT_DIED, XPRT_MOREREQS, XPRT_IDLE }; struct __rpc_svcxprt; struct mbuf; struct xp_ops { /* receive incoming requests */ bool_t (*xp_recv)(struct __rpc_svcxprt *, struct rpc_msg *, struct sockaddr **, struct mbuf **); /* get transport status */ enum xprt_stat (*xp_stat)(struct __rpc_svcxprt *); /* get transport acknowledge sequence */ bool_t (*xp_ack)(struct __rpc_svcxprt *, uint32_t *); /* send reply */ bool_t (*xp_reply)(struct __rpc_svcxprt *, struct rpc_msg *, struct sockaddr *, struct mbuf *, uint32_t *); /* destroy this struct */ void (*xp_destroy)(struct __rpc_svcxprt *); /* catch-all function */ bool_t (*xp_control)(struct __rpc_svcxprt *, const u_int, void *); }; struct __rpc_svcpool; struct __rpc_svcgroup; struct __rpc_svcthread; /* * Server side transport handle. In the kernel, transports have a * reference count which tracks the number of currently assigned * worker threads plus one for the service pool's reference. * For NFSv4.1 sessions, a reference is also held for a backchannel. * xp_p2 - Points to the CLIENT structure for the RPC server end * (the client end for callbacks). * Points to the private structure (cl_private) for the * CLIENT structure for the RPC client end (the server * end for callbacks). */ typedef struct __rpc_svcxprt { volatile u_int xp_refs; struct sx xp_lock; struct __rpc_svcpool *xp_pool; /* owning pool (see below) */ struct __rpc_svcgroup *xp_group; /* owning group (see below) */ TAILQ_ENTRY(__rpc_svcxprt) xp_link; TAILQ_ENTRY(__rpc_svcxprt) xp_alink; bool_t xp_registered; /* xprt_register has been called */ bool_t xp_active; /* xprt_active has been called */ struct __rpc_svcthread *xp_thread; /* assigned service thread */ struct socket* xp_socket; const struct xp_ops *xp_ops; char *xp_netid; /* network token */ struct sockaddr_storage xp_ltaddr; /* local transport address */ struct sockaddr_storage xp_rtaddr; /* remote transport address */ void *xp_p1; /* private: for use by svc ops */ void *xp_p2; /* private: for use by svc ops */ void *xp_p3; /* private: for use by svc lib */ int xp_type; /* transport type */ int xp_idletimeout; /* idle time before closing */ time_t xp_lastactive; /* time of last RPC */ uint64_t xp_sockref; /* set by nfsv4 to identify socket */ int xp_upcallset; /* socket upcall is set up */ uint32_t xp_snd_cnt; /* # of bytes to send to socket */ uint32_t xp_snt_cnt; /* # of bytes sent to socket */ bool_t xp_dontrcv; /* Do not receive on the socket */ uint32_t xp_tls; /* RPC-over-TLS on socket */ uint64_t xp_sslsec; /* Userland SSL * */ uint64_t xp_sslusec; uint64_t xp_sslrefno; int xp_sslproc; /* Which upcall daemon being used */ int xp_ngrps; /* Cred. from TLS cert. */ uid_t xp_uid; gid_t *xp_gidp; int xp_doneddp; } SVCXPRT; /* * Interface to server-side authentication flavors. */ typedef struct __rpc_svcauth { const struct svc_auth_ops { int (*svc_ah_wrap)(struct __rpc_svcauth *, struct mbuf **); int (*svc_ah_unwrap)(struct __rpc_svcauth *, struct mbuf **); void (*svc_ah_release)(struct __rpc_svcauth *); } *svc_ah_ops; void *svc_ah_private; } SVCAUTH; /* * Server transport extensions (accessed via xp_p3). */ typedef struct __rpc_svcxprt_ext { int xp_flags; /* versquiet */ SVCAUTH xp_auth; /* interface to auth methods */ } SVCXPRT_EXT; /* * The services list * Each entry represents a set of procedures (an rpc program). * The dispatch routine takes request structs and runs the * appropriate procedure. */ struct svc_callout { TAILQ_ENTRY(svc_callout) sc_link; rpcprog_t sc_prog; rpcvers_t sc_vers; char *sc_netid; void (*sc_dispatch)(struct svc_req *, SVCXPRT *); }; TAILQ_HEAD(svc_callout_list, svc_callout); /* * The services connection loss list * The dispatch routine takes request structs and runs the * appropriate procedure. */ struct svc_loss_callout { TAILQ_ENTRY(svc_loss_callout) slc_link; void (*slc_dispatch)(SVCXPRT *); }; TAILQ_HEAD(svc_loss_callout_list, svc_loss_callout); /* * Service request */ struct svc_req { STAILQ_ENTRY(svc_req) rq_link; /* list of requests for a thread */ struct __rpc_svcthread *rq_thread; /* thread which is to execute this */ uint32_t rq_xid; /* RPC transaction ID */ uint32_t rq_prog; /* service program number */ uint32_t rq_vers; /* service protocol version */ uint32_t rq_proc; /* the desired procedure */ size_t rq_size; /* space used by request */ struct mbuf *rq_args; /* XDR-encoded procedure arguments */ struct opaque_auth rq_cred; /* raw creds from the wire */ struct opaque_auth rq_verf; /* verifier for the reply */ void *rq_clntcred; /* read only cooked cred */ SVCAUTH rq_auth; /* interface to auth methods */ SVCXPRT *rq_xprt; /* associated transport */ struct sockaddr *rq_addr; /* reply address or NULL if connected */ void *rq_p1; /* application workspace */ int rq_p2; /* application workspace */ uint64_t rq_p3; /* application workspace */ uint32_t rq_reply_seq; /* reply socket sequence # */ char rq_credarea[3*MAX_AUTH_BYTES]; }; STAILQ_HEAD(svc_reqlist, svc_req); #define svc_getrpccaller(rq) \ ((rq)->rq_addr ? (rq)->rq_addr : \ (struct sockaddr *) &(rq)->rq_xprt->xp_rtaddr) /* * This structure is used to manage a thread which is executing * requests from a service pool. A service thread is in one of three * states: * * SVCTHREAD_SLEEPING waiting for a request to process * SVCTHREAD_ACTIVE processing a request * SVCTHREAD_EXITING exiting after finishing current request * * Threads which have no work to process sleep on the pool's sp_active * list. When a transport becomes active, it is assigned a service * thread to read and execute pending RPCs. */ typedef struct __rpc_svcthread { struct mtx_padalign st_lock; /* protects st_reqs field */ struct __rpc_svcpool *st_pool; SVCXPRT *st_xprt; /* transport we are processing */ struct svc_reqlist st_reqs; /* RPC requests to execute */ struct cv st_cond; /* sleeping for work */ LIST_ENTRY(__rpc_svcthread) st_ilink; /* idle threads list */ LIST_ENTRY(__rpc_svcthread) st_alink; /* application thread list */ int st_p2; /* application workspace */ uint64_t st_p3; /* application workspace */ } SVCTHREAD; LIST_HEAD(svcthread_list, __rpc_svcthread); /* * A thread group contain all information needed to assign subset of * transports to subset of threads. On systems with many CPUs and many * threads that allows to reduce lock congestion and improve performance. * Hundreds of threads on dozens of CPUs sharing the single pool lock do * not scale well otherwise. */ TAILQ_HEAD(svcxprt_list, __rpc_svcxprt); enum svcpool_state { SVCPOOL_INIT, /* svc_run not called yet */ SVCPOOL_ACTIVE, /* normal running state */ SVCPOOL_THREADWANTED, /* new service thread requested */ SVCPOOL_THREADSTARTING, /* new service thread started */ SVCPOOL_CLOSING /* svc_exit called */ }; typedef struct __rpc_svcgroup { struct mtx_padalign sg_lock; /* protect the thread/req lists */ struct __rpc_svcpool *sg_pool; enum svcpool_state sg_state; /* current pool state */ struct svcxprt_list sg_xlist; /* all transports in the group */ struct svcxprt_list sg_active; /* transports needing service */ struct svcthread_list sg_idlethreads; /* idle service threads */ int sg_minthreads; /* minimum service thread count */ int sg_maxthreads; /* maximum service thread count */ int sg_threadcount; /* current service thread count */ time_t sg_lastcreatetime; /* when we last started a thread */ time_t sg_lastidlecheck; /* when we last checked idle transports */ } SVCGROUP; /* * In the kernel, we can't use global variables to store lists of * transports etc. since otherwise we could not have two unrelated RPC * services running, each on its own thread. We solve this by * importing a tiny part of a Solaris kernel concept, SVCPOOL. * * A service pool contains a set of transports and service callbacks * for a set of related RPC services. The pool handle should be passed * when creating new transports etc. Future work may include extending * this to support something similar to the Solaris multi-threaded RPC * server. */ typedef SVCTHREAD *pool_assign_fn(SVCTHREAD *, struct svc_req *); typedef void pool_done_fn(SVCTHREAD *, struct svc_req *); #define SVC_MAXGROUPS 16 typedef struct __rpc_svcpool { struct mtx_padalign sp_lock; /* protect the transport lists */ const char *sp_name; /* pool name (e.g. "nfsd", "NLM" */ enum svcpool_state sp_state; /* current pool state */ struct proc *sp_proc; /* process which is in svc_run */ struct svc_callout_list sp_callouts; /* (prog,vers)->dispatch list */ struct svc_loss_callout_list sp_lcallouts; /* loss->dispatch list */ int sp_minthreads; /* minimum service thread count */ int sp_maxthreads; /* maximum service thread count */ /* * Hooks to allow an application to control request to thread * placement. */ pool_assign_fn *sp_assign; pool_done_fn *sp_done; /* * These variables are used to put an upper bound on the * amount of memory used by RPC requests which are queued * waiting for execution. */ unsigned long sp_space_low; unsigned long sp_space_high; unsigned long sp_space_used; unsigned long sp_space_used_highest; bool_t sp_space_throttled; int sp_space_throttle_count; struct replay_cache *sp_rcache; /* optional replay cache */ struct sysctl_ctx_list sp_sysctl; int sp_groupcount; /* Number of groups in the pool. */ int sp_nextgroup; /* Next group to assign port. */ SVCGROUP sp_groups[SVC_MAXGROUPS]; /* Thread/port groups. */ } SVCPOOL; /* * Operations defined on an SVCXPRT handle * * SVCXPRT *xprt; * struct rpc_msg *msg; * xdrproc_t xargs; * void * argsp; */ #define SVC_ACQUIRE(xprt) \ refcount_acquire(&(xprt)->xp_refs) #define SVC_RELEASE(xprt) \ if (refcount_release(&(xprt)->xp_refs)) \ SVC_DESTROY(xprt) #define SVC_RECV(xprt, msg, addr, args) \ (*(xprt)->xp_ops->xp_recv)((xprt), (msg), (addr), (args)) #define SVC_STAT(xprt) \ (*(xprt)->xp_ops->xp_stat)(xprt) #define SVC_ACK(xprt, ack) \ ((xprt)->xp_ops->xp_ack == NULL ? FALSE : \ ((ack) == NULL ? TRUE : (*(xprt)->xp_ops->xp_ack)((xprt), (ack)))) #define SVC_REPLY(xprt, msg, addr, m, seq) \ (*(xprt)->xp_ops->xp_reply) ((xprt), (msg), (addr), (m), (seq)) #define SVC_DESTROY(xprt) \ (*(xprt)->xp_ops->xp_destroy)(xprt) #define SVC_CONTROL(xprt, rq, in) \ (*(xprt)->xp_ops->xp_control)((xprt), (rq), (in)) #define SVC_EXT(xprt) \ ((SVCXPRT_EXT *) xprt->xp_p3) #define SVC_AUTH(xprt) \ (SVC_EXT(xprt)->xp_auth) /* * Operations defined on an SVCAUTH handle */ #define SVCAUTH_WRAP(auth, mp) \ ((auth)->svc_ah_ops->svc_ah_wrap(auth, mp)) #define SVCAUTH_UNWRAP(auth, mp) \ ((auth)->svc_ah_ops->svc_ah_unwrap(auth, mp)) #define SVCAUTH_RELEASE(auth) \ ((auth)->svc_ah_ops->svc_ah_release(auth)) /* * Service registration * * svc_reg(xprt, prog, vers, dispatch, nconf) * const SVCXPRT *xprt; * const rpcprog_t prog; * const rpcvers_t vers; * const void (*dispatch)(); * const struct netconfig *nconf; */ __BEGIN_DECLS extern bool_t svc_reg(SVCXPRT *, const rpcprog_t, const rpcvers_t, void (*)(struct svc_req *, SVCXPRT *), const struct netconfig *); __END_DECLS /* * Service un-registration * * svc_unreg(prog, vers) * const rpcprog_t prog; * const rpcvers_t vers; */ __BEGIN_DECLS extern void svc_unreg(SVCPOOL *, const rpcprog_t, const rpcvers_t); __END_DECLS /* * Service connection loss registration * * svc_loss_reg(xprt, dispatch) * const SVCXPRT *xprt; * const void (*dispatch)(); */ __BEGIN_DECLS extern bool_t svc_loss_reg(SVCXPRT *, void (*)(SVCXPRT *)); __END_DECLS /* * Service connection loss un-registration * * svc_loss_unreg(xprt, dispatch) * const SVCXPRT *xprt; * const void (*dispatch)(); */ __BEGIN_DECLS extern void svc_loss_unreg(SVCPOOL *, void (*)(SVCXPRT *)); __END_DECLS /* * Transport registration. * * xprt_register(xprt) * SVCXPRT *xprt; */ __BEGIN_DECLS extern void xprt_register(SVCXPRT *); __END_DECLS /* * Transport un-register * * xprt_unregister(xprt) * SVCXPRT *xprt; */ __BEGIN_DECLS extern void xprt_unregister(SVCXPRT *); extern void __xprt_unregister_unlocked(SVCXPRT *); __END_DECLS /* * Called when a transport has pending requests. */ __BEGIN_DECLS extern void xprt_active(SVCXPRT *); extern void xprt_inactive(SVCXPRT *); extern void xprt_inactive_locked(SVCXPRT *); extern void xprt_inactive_self(SVCXPRT *); __END_DECLS /* * When the service routine is called, it must first check to see if it * knows about the procedure; if not, it should call svcerr_noproc * and return. If so, it should deserialize its arguments via * SVC_GETARGS (defined above). If the deserialization does not work, * svcerr_decode should be called followed by a return. Successful * decoding of the arguments should be followed the execution of the * procedure's code and a call to svc_sendreply. * * Also, if the service refuses to execute the procedure due to too- * weak authentication parameters, svcerr_weakauth should be called. * Note: do not confuse access-control failure with weak authentication! * * NB: In pure implementations of rpc, the caller always waits for a reply * msg. This message is sent when svc_sendreply is called. * Therefore pure service implementations should always call * svc_sendreply even if the function logically returns void; use * xdr.h - xdr_void for the xdr routine. HOWEVER, tcp based rpc allows * for the abuse of pure rpc via batched calling or pipelining. In the * case of a batched call, svc_sendreply should NOT be called since * this would send a return message, which is what batching tries to avoid. * It is the service/protocol writer's responsibility to know which calls are * batched and which are not. Warning: responding to batch calls may * deadlock the caller and server processes! */ __BEGIN_DECLS extern bool_t svc_sendreply(struct svc_req *, xdrproc_t, void *); extern bool_t svc_sendreply_mbuf(struct svc_req *, struct mbuf *); extern void svcerr_decode(struct svc_req *); extern void svcerr_weakauth(struct svc_req *); extern void svcerr_noproc(struct svc_req *); extern void svcerr_progvers(struct svc_req *, rpcvers_t, rpcvers_t); extern void svcerr_auth(struct svc_req *, enum auth_stat); extern void svcerr_noprog(struct svc_req *); extern void svcerr_systemerr(struct svc_req *); extern int rpc_reg(rpcprog_t, rpcvers_t, rpcproc_t, char *(*)(char *), xdrproc_t, xdrproc_t, char *); __END_DECLS /* * Lowest level dispatching -OR- who owns this process anyway. * Somebody has to wait for incoming requests and then call the correct * service routine. The routine svc_run does infinite waiting; i.e., * svc_run never returns. * Since another (co-existent) package may wish to selectively wait for * incoming calls or other events outside of the rpc architecture, the * routine svc_getreq is provided. It must be passed readfds, the * "in-place" results of a select system call (see select, section 2). */ /* * a small program implemented by the svc_rpc implementation itself; * also see clnt.h for protocol numbers. */ __BEGIN_DECLS extern void rpctest_service(void); __END_DECLS __BEGIN_DECLS extern SVCXPRT *svc_xprt_alloc(void); extern void svc_xprt_free(SVCXPRT *); extern void svc_run(SVCPOOL *); extern void svc_exit(SVCPOOL *); extern bool_t svc_getargs(struct svc_req *, xdrproc_t, void *); extern bool_t svc_freeargs(struct svc_req *, xdrproc_t, void *); extern void svc_freereq(struct svc_req *); __END_DECLS /* * Socket to use on svcxxx_create call to get default socket */ #define RPC_ANYSOCK -1 #define RPC_ANYFD RPC_ANYSOCK /* * These are the existing service side transport implementations */ __BEGIN_DECLS /* * Create a new service pool. */ extern SVCPOOL* svcpool_create(const char *name, struct sysctl_oid_list *sysctl_base); /* * Destroy a service pool, including all registered transports. */ extern void svcpool_destroy(SVCPOOL *pool); /* * Close a service pool. Similar to svcpool_destroy(), but it does not * free the data structures. As such, the pool can be used again. */ extern void svcpool_close(SVCPOOL *pool); -/* - * Transport independent svc_create routine. - */ -extern int svc_create(SVCPOOL *, void (*)(struct svc_req *, SVCXPRT *), - const rpcprog_t, const rpcvers_t, const char *); -/* - * void (*dispatch)(); -- dispatch routine - * const rpcprog_t prognum; -- program number - * const rpcvers_t versnum; -- version number - * const char *nettype; -- network type - */ - - /* * Generic server creation routine. It takes a netconfig structure * instead of a nettype. */ extern SVCXPRT *svc_tp_create(SVCPOOL *, void (*)(struct svc_req *, SVCXPRT *), const rpcprog_t, const rpcvers_t, const char *uaddr, const struct netconfig *); /* * void (*dispatch)(); -- dispatch routine * const rpcprog_t prognum; -- program number * const rpcvers_t versnum; -- version number * const char *uaddr; -- universal address of service * const struct netconfig *nconf; -- netconfig structure */ extern SVCXPRT *svc_dg_create(SVCPOOL *, struct socket *, const size_t, const size_t); /* * struct socket *; -- open connection * const size_t sendsize; -- max send size * const size_t recvsize; -- max recv size */ extern SVCXPRT *svc_vc_create(SVCPOOL *, struct socket *, const size_t, const size_t); /* * struct socket *; -- open connection * const size_t sendsize; -- max send size * const size_t recvsize; -- max recv size */ extern SVCXPRT *svc_vc_create_backchannel(SVCPOOL *); extern void *clnt_bck_create(struct socket *, const rpcprog_t, const rpcvers_t); /* * struct socket *; -- server transport socket * const rpcprog_t prog; -- RPC program number * const rpcvers_t vers; -- RPC program version */ /* * Generic TLI create routine */ extern SVCXPRT *svc_tli_create(SVCPOOL *, const struct netconfig *, const struct t_bind *, const size_t, const size_t); /* * const struct netconfig *nconf; -- netconfig structure for network * const struct t_bind *bindaddr; -- local bind address * const size_t sendsz; -- max sendsize * const size_t recvsz; -- max recvsize */ __END_DECLS #endif /* !_RPC_SVC_H */ diff --git a/sys/rpc/svc_generic.c b/sys/rpc/svc_generic.c index 6fb43dc5c940..12c96eca27c8 100644 --- a/sys/rpc/svc_generic.c +++ b/sys/rpc/svc_generic.c @@ -1,299 +1,229 @@ /* $NetBSD: svc_generic.c,v 1.3 2000/07/06 03:10:35 christos Exp $ */ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 2009, Sun Microsystems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of Sun Microsystems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1986-1991 by Sun Microsystems Inc. */ /* * svc_generic.c, Server side for RPC. * */ #include "opt_inet6.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern int __svc_vc_setflag(SVCXPRT *, int); -/* - * The highest level interface for server creation. - * It tries for all the nettokens in that particular class of token - * and returns the number of handles it can create and/or find. - * - * It creates a link list of all the handles it could create. - * If svc_create() is called multiple times, it uses the handle - * created earlier instead of creating a new handle every time. - */ -int -svc_create( - SVCPOOL *pool, - void (*dispatch)(struct svc_req *, SVCXPRT *), - rpcprog_t prognum, /* Program number */ - rpcvers_t versnum, /* Version number */ - const char *nettype) /* Networktype token */ -{ - int g, num = 0; - SVCGROUP *grp; - SVCXPRT *xprt; - struct netconfig *nconf; - void *handle; - - if ((handle = __rpc_setconf(nettype)) == NULL) { - printf("svc_create: unknown protocol"); - return (0); - } - while ((nconf = __rpc_getconf(handle)) != NULL) { - for (g = 0; g < SVC_MAXGROUPS; g++) { - grp = &pool->sp_groups[g]; - mtx_lock(&grp->sg_lock); - TAILQ_FOREACH(xprt, &grp->sg_xlist, xp_link) { - if (strcmp(xprt->xp_netid, nconf->nc_netid)) - continue; - /* Found an old one, use it */ - mtx_unlock(&grp->sg_lock); - (void) rpcb_unset(prognum, versnum, nconf); - if (svc_reg(xprt, prognum, versnum, - dispatch, nconf) == FALSE) { - printf( - "svc_create: could not register prog %u vers %u on %s\n", - (unsigned)prognum, (unsigned)versnum, - nconf->nc_netid); - mtx_lock(&grp->sg_lock); - } else { - num++; - mtx_lock(&grp->sg_lock); - break; - } - } - mtx_unlock(&grp->sg_lock); - } - if (xprt == NULL) { - /* It was not found. Now create a new one */ - xprt = svc_tp_create(pool, dispatch, prognum, versnum, - NULL, nconf); - if (xprt) { - num++; - SVC_RELEASE(xprt); - } - } - } - __rpc_endconf(handle); - /* - * In case of num == 0; the error messages are generated by the - * underlying layers; and hence not needed here. - */ - return (num); -} - /* * The high level interface to svc_tli_create(). * It tries to create a server for "nconf" and registers the service * with the rpcbind. It calls svc_tli_create(); */ SVCXPRT * svc_tp_create( SVCPOOL *pool, void (*dispatch)(struct svc_req *, SVCXPRT *), rpcprog_t prognum, /* Program number */ rpcvers_t versnum, /* Version number */ const char *uaddr, /* Address (or null for default) */ const struct netconfig *nconf) /* Netconfig structure for the network */ { struct netconfig nconfcopy; struct netbuf *taddr; struct t_bind bind; SVCXPRT *xprt; if (nconf == NULL) { printf( "svc_tp_create: invalid netconfig structure for prog %u vers %u\n", (unsigned)prognum, (unsigned)versnum); return (NULL); } if (uaddr) { taddr = uaddr2taddr(nconf, uaddr); bind.addr = *taddr; free(taddr, M_RPC); bind.qlen = -1; xprt = svc_tli_create(pool, nconf, &bind, 0, 0); free(bind.addr.buf, M_RPC); } else { xprt = svc_tli_create(pool, nconf, NULL, 0, 0); } if (xprt == NULL) { return (NULL); } /*LINTED const castaway*/ nconfcopy = *nconf; (void) rpcb_unset(prognum, versnum, &nconfcopy); if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) { printf( "svc_tp_create: Could not register prog %u vers %u on %s\n", (unsigned)prognum, (unsigned)versnum, nconf->nc_netid); xprt_unregister(xprt); SVC_RELEASE(xprt); return (NULL); } return (xprt); } /* * If so is NULL, then it opens a socket for the given transport * provider (nconf cannot be NULL then). If the t_state is T_UNBND and * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For * NULL bindadr and Connection oriented transports, the value of qlen * is set to 8. * * If sendsz or recvsz are zero, their default values are chosen. */ SVCXPRT * svc_tli_create( SVCPOOL *pool, const struct netconfig *nconf, /* Netconfig struct for nettoken */ const struct t_bind *bindaddr, /* Local bind address */ size_t sendsz, /* Max sendsize */ size_t recvsz) /* Max recvsize */ { struct socket *so; SVCXPRT *xprt = NULL; /* service handle */ struct __rpc_sockinfo si; struct sockaddr_storage ss; if (nconf == NULL) { printf("svc_tli_create: invalid netconfig\n"); return (NULL); } so = __rpc_nconf2socket(nconf); if (!so) { printf( "svc_tli_create: could not open connection for %s\n", nconf->nc_netid); return (NULL); } __rpc_nconf2sockinfo(nconf, &si); if (bindaddr == NULL) { if (bindresvport(so, NULL)) { memset(&ss, 0, sizeof ss); ss.ss_family = si.si_af; ss.ss_len = si.si_alen; if (sobind(so, (struct sockaddr *)&ss, curthread)) { printf( "svc_tli_create: could not bind to anonymous port\n"); goto freedata; } } solisten(so, -1, curthread); } else { if (bindresvport(so, (struct sockaddr *)bindaddr->addr.buf)) { printf( "svc_tli_create: could not bind to requested address\n"); goto freedata; } solisten(so, (int)bindaddr->qlen, curthread); } /* * call transport specific function. */ switch (si.si_socktype) { case SOCK_STREAM: #if 0 slen = sizeof ss; if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) == 0) { /* accepted socket */ xprt = svc_fd_create(fd, sendsz, recvsz); } else #endif xprt = svc_vc_create(pool, so, sendsz, recvsz); if (!nconf || !xprt) break; #if 0 /* XXX fvdl */ if (strcmp(nconf->nc_protofmly, "inet") == 0 || strcmp(nconf->nc_protofmly, "inet6") == 0) (void) __svc_vc_setflag(xprt, TRUE); #endif break; case SOCK_DGRAM: xprt = svc_dg_create(pool, so, sendsz, recvsz); break; default: printf("svc_tli_create: bad service type"); goto freedata; } if (xprt == NULL) /* * The error messages here are spitted out by the lower layers: * svc_vc_create(), svc_fd_create() and svc_dg_create(). */ goto freedata; /* Fill in type of service */ xprt->xp_type = __rpc_socktype2seman(si.si_socktype); if (nconf) { xprt->xp_netid = strdup(nconf->nc_netid, M_RPC); } return (xprt); freedata: (void)soclose(so); if (xprt) xprt_unregister(xprt); return (NULL); }