⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clnt_kudp.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
#ifdef	KERNEL/* * Copyright (c) 1987 by Sun Microsystems, Inc. * * @(#)clnt_kudp.c 1.1 92/07/30 * * Implements a kernel UPD/IP based, client side RPC. * * Copyright (C) 1988, Sun Microsystems, Inc. */#include <sys/param.h>#include <sys/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>struct mbuf	*ku_recvfrom();int		ckuwakeup();enum clnt_stat	clntkudp_callit();void		clntkudp_abort();void		clntkudp_error();bool_t		clntkudp_freeres();bool_t		clntkudp_control();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 */	clntkudp_control	/* the ioctl() of rpc */};/* * 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 rpc_timers	*cku_timers;	/* for estimating RTT */	struct rpc_timers	*cku_timeall;	/* for estimating RTT */	void			(*cku_feedback)();	caddr_t			cku_feedarg;	/* argument for feedback func */	u_long			cku_xid;	/* current XID */};struct {	int	rccalls;	int	rcbadcalls;	int	rcretrans;	int	rcbadxids;	int	rctimeouts;	int	rcwaits;	int	rcnewcreds;	int	rcbadverfs;	int	rctimers;} 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/* Times to retry */#define	RECVTRIES	2#define	SNDTRIES	4u_long	clntxid;	/* transaction id used by all clients */staticnoop(){}staticbuffree(p)	struct cku_private *p;{	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(4, "clntkudp_create(%X, %d, %d, %d\n",	    addr->sin_addr.s_addr, pgm, vers, retrys);#endif	p = (struct cku_private *)kmem_zalloc(sizeof *p);	h = ptoh(p);	if (!clntxid) {		clntxid = (time.tv_usec ^ time.tv_sec);	}	/* 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_WAIT);	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, %d", error);		goto bad;	}	if (error = bindresvport(p->cku_sock)) {		printf("clntkudp_create: socket bind problem, %d", error);		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(4, "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);	p->cku_retrys = retrys;	p->cku_addr = *addr;	p->cku_cred = cred;	p->cku_xid = 0;	p->cku_flags &= (CKU_BUFBUSY | CKU_BUFWANTED);}/* * set the timers.  Return current retransmission timeout. */clntkudp_settimers(h, t, all, minimum, feedback, arg, xid)	CLIENT *h;	struct rpc_timers *t, *all;	unsigned int minimum;	void (*feedback)();	caddr_t arg;	u_long xid;{	struct cku_private *p = htop(h);	int value;	p->cku_feedback = feedback;	p->cku_feedarg = arg;	p->cku_timers = t;	p->cku_timeall = all;	if (xid)		p->cku_xid = xid;	else		p->cku_xid = alloc_xid();	value = all->rt_rtxcur;	value += t->rt_rtxcur;	if (value < minimum)		return (minimum);	rcstat.rctimers++;	return (value);}/* * Time out back off function. tim is in hz */#define	MAXTIMO	(20 * hz)#define	backoff(tim)	((((tim) << 1) > MAXTIMO) ? MAXTIMO : ((tim) << 1))#if defined(ASYNCHIO) && defined(LWP)extern int runthreads;#endif /* ASYNCHIO && LWP *//* * 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, rpc replies with remote errors 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;	int			   stries = p->cku_retrys;	int			   s;	struct ucred		   *tmpcred;	struct mbuf		   *m;	int timohz;	u_long xid;	u_int rempos = 0;	int refreshes = 2;	/* number of times to refresh credential */	int round_trip;		/* time the RPC */	int interrupted;	/* return from sleep() */	int smask;		/* saved signal mask*/	struct proc *pp = u.u_procp;# define time_in_hz (time.tv_sec*hz + time.tv_usec/(1000000/hz))#ifdef RPCDEBUG	rpc_debug(4, "cku_callit\n");#endif	rcstat.rccalls++;	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;	if (p->cku_xid == 0)		xid = alloc_xid();	else		xid = p->cku_xid;	/*	 * This is dumb but easy: keep the time out in units of hz	 * so it is easy to call timeout and modify the value.	 */	timohz = wait.tv_sec * hz + (wait.tv_usec * hz) / 1000000;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 wainting 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);		(void) sleep((caddr_t)&p->cku_outbuf, PZERO-3);		if (!(p->cku_flags & CKU_BUFBUSY)) {			/* probably woke up from buffree	*/			untimeout(wakeup, (caddr_t)&p->cku_outbuf);		}		sbflush(&so->so_rcv);	}	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;	}	xdrs = &p->cku_outxdr;	/*	 * The transaction id is the first thing in the	 * preserialized output buffer.	 */	(*(u_long *)(p->cku_outbuf)) = xid;	xdrmbuf_init(xdrs, m, XDR_ENCODE);	if (rempos != 0) {		XDR_SETPOS(xdrs, rempos);	} else {		/*		 * Serialize dynamic stuff into the output buffer.		 */		XDR_SETPOS(xdrs, p->cku_outpos);		if ((! XDR_PUTLONG(xdrs, (long *)&procnum)) ||		    (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||		    (! (*xdr_args)(xdrs, argsp))) {			p->cku_err.re_status = RPC_CANTENCODEARGS;			p->cku_err.re_errno = EIO;			(void) m_freem(m);			goto done;		}		rempos = XDR_GETPOS(xdrs);	}	m->m_len = rempos;	round_trip = time_in_hz;	if ((p->cku_err.re_errno = ku_sendto_mbuf(so, m, &p->cku_addr)) != 0) {		p->cku_err.re_status = RPC_CANTSEND;		p->cku_err.re_errno = EIO;		goto done;	}recv_again:	for (rtries = RECVTRIES; rtries; rtries--) {		s = splnet();		while (so->so_rcv.sb_cc == 0) {

⌨️ 快捷键说明

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