clnt_kudp.c

来自「操作系统SunOS 4.1.3版本的源码」· C语言 代码 · 共 740 行 · 第 1/2 页

C
740
字号
#ifndef lintstatic char sccsid[] = "@(#)clnt_kudp.c 1.1 92/07/30 Copyr 1989 Sun Micro";#endif/* * clnt_kudp.c * Implements a kernel UPD/IP based, client side RPC. * * Copyright (C) 1984, Sun Microsystems, Inc. */#include <sys/param.h>#include "boot/systm.h"#include <sys/user.h>#include <sys/kernel.h>#include <sys/proc.h>#include <sys/socket.h>#include <sys/socketvar.h>#include <sys/mbuf.h>#include <net/if.h>#include <net/route.h>#include <netinet/in.h>#include <netinet/in_pcb.h>#include <rpc/types.h>#include <rpc/xdr.h>#include <rpc/auth.h>#include <rpc/clnt.h>#include <rpc/rpc_msg.h>#include <mon/sunromvec.h>extern	int	verbosemode;#ifdef	NFS_BOOT#undef	uextern struct user u;#endif	/* NFS_BOOT */#ifdef OPENPROMS#define	millitime()	prom_gettime()#else#define	millitime()	(*romp->v_nmiclock)#endif !OPENPROMSstruct mbuf	*ku_recvfrom();int		ckuwakeup();enum clnt_stat	clntkudp_callit();void		clntkudp_abort();void		clntkudp_error();bool_t		clntkudp_freeres();void		clntkudp_destroy();void		xdrmbuf_init();/* * Operations vector for UDP/IP based RPC */static struct clnt_ops udp_ops = {	clntkudp_callit,	/* do rpc call */	clntkudp_abort,		/* abort call */	clntkudp_error,		/* return error status */	clntkudp_freeres,	/* free results */	clntkudp_destroy	/* destroy rpc handle */};/* * Private data per rpc handle.  This structure is allocated by * clntkudp_create, and freed by cku_destroy. */struct cku_private {	u_int			 cku_flags;	/* see below */	CLIENT			 cku_client;	/* client handle */	int			 cku_retrys;	/* request retrys */	struct socket		*cku_sock;	/* open udp socket */	struct sockaddr_in	 cku_addr;	/* remote address */	struct rpc_err		 cku_err;	/* error status */	XDR			 cku_outxdr;	/* xdr routine for output */	XDR			 cku_inxdr;	/* xdr routine for input */	u_int			 cku_outpos;	/* position of in output mbuf */	char			*cku_outbuf;	/* output buffer */	char			*cku_inbuf;	/* input buffer */	struct mbuf		*cku_inmbuf;	/* input mbuf */	struct ucred		*cku_cred;	/* credentials */};struct {	int	rccalls;	int	rcbadcalls;	int	rcretrans;	int	rcbadxids;	int	rctimeouts;	int	rcwaits;	int	rcnewcreds;} rcstat;#define	ptoh(p)		(&((p)->cku_client))#define	htop(h)		((struct cku_private *)((h)->cl_private))/* cku_flags */#define	CKU_TIMEDOUT	0x001#define	CKU_BUSY	0x002#define	CKU_WANTED	0x004#define	CKU_BUFBUSY	0x008#define	CKU_BUFWANTED	0x010#define	RECVTRIES	18	/* # retransmission attempts */#define	MAXRTO		16000	/* max retransmission timer in ms. */#define	ONESECOND	1000	/* 1 second == 1000 ms */int	clntkudpxid = 0;/* * V. Jacobson Mean+Varience retransmission timer algorithm. * Best guess starting values. */static	int	sa = 800;	/* scaled average round trip time */static	int	sd = 20;	/* scaled mean deviation */static	int	rto = 1000;	/* retransmit timer */staticnoop(){}staticbuffree(p)	struct cku_private *p;{#ifdef	RPCDEBUG	rpc_debug(6, "buffree(p 0x%x)\n", p);#endif	/* RPCDEBUG */	p->cku_flags &= ~CKU_BUFBUSY;	if (p->cku_flags & CKU_BUFWANTED) {		p->cku_flags &= ~CKU_BUFWANTED;		wakeup((caddr_t)&p->cku_outbuf);	}}/* * Create an rpc handle for a udp rpc connection. * Allocates space for the handle structure and the private data, and * opens a socket.  Note sockets and handles are one to one. */CLIENT *clntkudp_create(addr, pgm, vers, retrys, cred)	struct sockaddr_in *addr;	u_long pgm;	u_long vers;	int retrys;	struct ucred *cred;{	register CLIENT *h;	register struct cku_private *p;	int error = 0;	struct rpc_msg call_msg;	struct mbuf *m, *mclgetx();	extern int nfs_portmon;#ifdef RPCDEBUG	rpc_debug(6, "clntkudp_create(addr 0x%x pgm %d vers %d retrys %d\n",	    addr->sin_addr.s_addr, pgm, vers, retrys);#endif	p = (struct cku_private *)kmem_alloc((u_int)sizeof *p);	bzero((caddr_t)p, sizeof (*p));	h = ptoh(p);	if (!clntkudpxid) {		clntkudpxid = 0x1f7391f3 + millitime();	}	/* handle */	h->cl_ops = &udp_ops;	h->cl_private = (caddr_t) p;	h->cl_auth = authkern_create();	/* call message, just used to pre-serialize below */	call_msg.rm_xid = 0;	call_msg.rm_direction = CALL;	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;	call_msg.rm_call.cb_prog = pgm;	call_msg.rm_call.cb_vers = vers;	/* private */	clntkudp_init(h, addr, retrys, cred);	p->cku_outbuf = (char *)kmem_alloc((u_int)UDPMSGSIZE);	m = mclgetx(noop, 0, p->cku_outbuf, UDPMSGSIZE, M_DONTWAIT);	if (m == NULL)		goto bad;	xdrmbuf_init(&p->cku_outxdr, m, XDR_ENCODE);	/* pre-serialize call message header */	if (! xdr_callhdr(&(p->cku_outxdr), &call_msg)) {		printf("clntkudp_create - Fatal header serialization error.");		(void) m_freem(m);		goto bad;	}	p->cku_outpos = XDR_GETPOS(&(p->cku_outxdr));	(void) m_free(m);	/* open udp socket */	error = socreate(AF_INET, &p->cku_sock, SOCK_DGRAM, IPPROTO_UDP);	if (error) {		printf("clntkudp_create: socket creation problem: ");		errno_print(error);		printf("\n");		goto bad;	}	if (error = bindresvport(p->cku_sock)) {		printf("clntkudp_create: socket bind problem: ");		errno_print(error);		printf("\n");		goto bad;	}	return (h);bad:	kmem_free((caddr_t)p->cku_outbuf, (u_int)UDPMSGSIZE);	kmem_free((caddr_t)p, (u_int)sizeof (struct cku_private));#ifdef RPCDEBUG	rpc_debug(10, "clntkudp_create: create failed\n");#endif	return ((CLIENT *)NULL);}clntkudp_init(h, addr, retrys, cred)	CLIENT *h;	struct sockaddr_in *addr;	int retrys;	struct ucred *cred;{	struct cku_private *p = htop(h);#ifdef RPCDEBUG	rpc_debug(6, "clntkudp_init(h 0x%x addr 0x%x retrys 0x%x)\n",		h, addr, retrys);#endif	p->cku_retrys = retrys;	p->cku_addr = *addr;	p->cku_cred = cred;	p->cku_flags = 0;}/* * Time out back off function. tim is in hz */#define	MAXTIMO	(60 * hz)#define	backoff(tim)	((((tim) << 1) > MAXTIMO) ? MAXTIMO : ((tim) << 1))/* * Call remote procedure. * Most of the work of rpc is done here.  We serialize what is left * of the header (some was pre-serialized in the handle), serialize * the arguments, and send it off.  We wait for a reply or a time out. * Timeout causes an immediate return, other packet problems may cause * a retry on the receive.  When a good packet is received we deserialize * it, and check verification.  A bad reply code will cause one retry * with full (longhand) credentials. * If "ignorebad" is TRUE, bad (!RPC_SUCCESS) replies are ignored. */enum clnt_statclntkudp_callit_addr(h, procnum, xdr_args, argsp, xdr_results, resultsp, wait,	    sin, ignorebad)	register CLIENT	*h;	u_long		procnum;	xdrproc_t	xdr_args;	caddr_t		argsp;	xdrproc_t	xdr_results;	caddr_t		resultsp;	struct timeval	wait;	struct sockaddr_in *sin;	int		ignorebad;{	register struct cku_private *p = htop(h);	register XDR		   *xdrs;	register struct socket	   *so = p->cku_sock;	int			   rtries = 0;	struct sockaddr_in	   from;	struct rpc_msg		   reply_msg;	int			   s;	struct ucred		   *tmpcred;	struct mbuf		   *m;	u_long xid;	int	t1, t2, tout;	int	maxtout;#ifdef RPCDEBUG	rpc_debug(6,	    "clntkudp_callit_addr(h 0x%x procnum 0x%x xdr_args 0x%x argsp 0x%x\n",	    h, procnum, xdr_args, argsp);	rpc_debug(6,		"xdr_results 0x%x resultsp 0x%x wait 0x%x sin 0x%x)\n",		xdr_results, resultsp, wait, sin);#endif	rcstat.rccalls++;	/*	 * compute absolute return time = <now> + <wait argument> in ms	 */	maxtout = millitime() + (wait.tv_sec * 1000) + (wait.tv_usec / 1000);	while (p->cku_flags & CKU_BUSY) {		rcstat.rcwaits++;		p->cku_flags |= CKU_WANTED;		(void) sleep((caddr_t)h, PZERO-2);	}	p->cku_flags |= CKU_BUSY;	/*	 * Set credentials into the u structure	 */	tmpcred = u.u_cred;	u.u_cred = p->cku_cred;	xid = clntkudpxid++;call_again:	/*	 * Wait til buffer gets freed then make a type 2 mbuf point at it	 * The buffree routine clears CKU_BUFBUSY and does a wakeup when	 * the mbuf gets freed.	 */	s = splimp();	while (p->cku_flags & CKU_BUFBUSY) {		p->cku_flags |= CKU_BUFWANTED;		/*		 * This is a kludge to avoid deadlock in the case of a		 * loop-back call.  The client can block waiting for		 * the server to free the mbuf while the server is blocked		 * waiting for the client to free the reply mbuf.  Avoid this		 * by flushing the input queue every once in a while while		 * we are waiting.		 */		timeout(wakeup, (caddr_t)&p->cku_outbuf, hz);	}	p->cku_flags |= CKU_BUFBUSY;	(void) splx(s);	m = mclgetx(buffree, (int)p, p->cku_outbuf, UDPMSGSIZE, M_WAIT);	if (m == NULL) {		p->cku_err.re_status = RPC_SYSTEMERROR;		p->cku_err.re_errno = ENOBUFS;		buffree(p);		goto done;	}	/*	 * The transaction id is the first thing in the	 * preserialized output buffer.	 */	(*(u_long *)(p->cku_outbuf)) = xid;	xdrmbuf_init(&p->cku_outxdr, m, XDR_ENCODE);	xdrs = &p->cku_outxdr;	XDR_SETPOS(xdrs, p->cku_outpos);	/*	 * Serialize dynamic stuff into the output buffer.	 */	if ((! XDR_PUTLONG(xdrs, (long *)&procnum)) ||	    (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||	    (! (*xdr_args)(xdrs, argsp))) {		p->cku_err.re_status = RPC_CANTENCODEARGS;		(void) m_freem(m);		goto done;	}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?