📄 clnt_kudp.c
字号:
#ifndef lintstatic char *sccsid = "@(#)clnt_kudp.c 4.3 (ULTRIX) 2/28/91";#endif lint/************************************************************************ * * * Copyright (c) 1986 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//* * Portions of this software have been licensed to * Digital Equipment Company, Maynard, MA. * Copyright (c) 1986 Sun Microsystems, Inc. ALL RIGHTS RESERVED. *//* * clnt_kudp.c * Implements a kernel UDP/IP based, client side RPC. *//* * * Modification history: * * 29 Jan 91 -- chet * Make kernel RPC calls interruptible. * * 10 Dec 89 -- chet * Add arphasmbuf() call in clntkudp_callit() after timeouts * to free an mbuf on the arpresolve trash heap (avoids long sleeps). * * 30 May 88 -- U. Sinkewicz * Added SO_LOCK to replace smp_lock(&so->lk_socket, LK_RETRY) * as part of an smp bug fix. Fix guarantees that socket doesn't * change while unlocked during sleeps or for the lock heirarchy. * * 1 Sep 88 -- chet * Remove transaction ID - it's now in the client handle * passed down from the application * * 06-Jun-88 condylis * Added SMP locking for clntkudpxid and mbuf data contained in * outbuf member of cku_private structure. New routine to * initialize rpc smp locks (rpcinit). Added interaction with * socket locks. Added SMP locking of RPC client statistics. * * 12-11-87 Robin L. and Larry C. and Ricky P. * Added new kmalloc memory allocation to system. * * 02-Mar-87 -- logcher * Merged in diskless changes, added checks for null pointers * in clntkudp_create */#include "../h/param.h"#include "../h/systm.h"#include "../h/user.h"#include "../h/kernel.h"#include "../h/proc.h"#include "../h/socket.h"#include "../h/socketvar.h"#include "../h/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 "../h/smp_lock.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 *//* SMP lock for protecting mbuf data of cku_private * This lock is used with CKU_BUFBUSY and CKU_BUFWANTED flags */ struct lock_t cku_lk_outbuf;};/* SMP lock for xids contained in client handles */struct lock_t lk_rpcxid;struct { int rccalls; int rcbadcalls; int rcretrans; int rcbadxids; int rctimeouts; int rcwaits; int rcnewcreds; int rcbadverfs;} 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 CKU_ONCE_ONLY 0x020/* Times to retry */#define RECVTRIES 2#define SNDTRIES 4/* Need the externs for rpcinit routine */extern struct lock_t lk_rpccallout;extern struct lock_t lk_rpcdupreq;extern struct lock_t lk_rpcrqcred;extern struct lock_t lk_nfsstat;clntkudp_once(cl, flag) CLIENT *cl;{ struct cku_private *p = (struct cku_private *)cl->cl_private; if (flag != 0) { p->cku_flags |= CKU_ONCE_ONLY; } else { p->cku_flags &= ~CKU_ONCE_ONLY; }}staticnoop(){}staticbuffree(p) struct cku_private *p;{ int s; s = splimp(); smp_lock(&p->cku_lk_outbuf, LK_RETRY); p->cku_flags &= ~CKU_BUFBUSY; if (p->cku_flags & CKU_BUFWANTED) { p->cku_flags &= ~CKU_BUFWANTED; wakeup((caddr_t)&p->cku_outbuf); } smp_unlock(&p->cku_lk_outbuf); splx(s);}/* * 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 kmem_alloc(p, struct cku_private *, (u_int)sizeof *p, KM_RPC); if(p == NULL) panic("clntkudp_create: kmem_alloc returns 0"); h = ptoh(p); /* 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); kmem_alloc(p->cku_outbuf, char *, (u_int)UDPMSGSIZE, KM_RPC); if(p->cku_outbuf == NULL) panic("clntkudp_create: kmem_alloc returns 0 for p->cku_outbuf"); /* Initialize SMP lock for mbuf data buffer */ lockinit(&p->cku_lk_outbuf, &lock_cku_d); 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. * * We must clear u.u_error after calling socreate() because * socreate calls suser() which may set u.u_error as a side * effect. This is really a bug in socreate() which should * be fixed someday, but for now we just patch things up here. */ error = socreate(AF_INET, &p->cku_sock, SOCK_DGRAM, IPPROTO_UDP); u.u_error = 0; /* XXX */ 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, KM_RPC); kmem_free((caddr_t)(caddr_t)p, KM_RPC);#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_flags &= (CKU_BUFBUSY | CKU_BUFWANTED);}/* * 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. */enum clnt_stat clntkudp_callit(h, procnum, xdr_args, argsp, xdr_results, resultsp, wait) register CLIENT *h; u_long procnum; xdrproc_t xdr_args; caddr_t argsp; xdrproc_t xdr_results; caddr_t resultsp; struct timeval wait;{ register struct cku_private *p = htop(h); register XDR *xdrs; register struct socket *so = p->cku_sock; int rtries; int stries = p->cku_retrys; struct sockaddr_in from; int s; struct ucred *tmpcred; struct mbuf *m = NULL; int timohz; u_long xid; u_int rempos = 0; int refreshes = 2; /* number of times to refresh credential */ int interrupted; /* return from sleep() */ int smask; /* saved signal mask */ struct proc *pp = u.u_procp;#ifdef RPCDEBUG rpc_debug(4, "cku_callit\n");#endif smp_lock(&lk_nfsstat, LK_RETRY); rcstat.rccalls++; smp_unlock(&lk_nfsstat); while (p->cku_flags & CKU_BUSY) { smp_lock(&lk_nfsstat, LK_RETRY); rcstat.rcwaits++; smp_unlock(&lk_nfsstat); p->cku_flags |= CKU_WANTED; (void) sleep((caddr_t)h, PZERO-2); } p->cku_flags |= CKU_BUSY; if ((p->cku_flags & CKU_ONCE_ONLY) != 0) stries = 1; /* * Set credentials into the u structure */ tmpcred = u.u_cred; u.u_cred = p->cku_cred; /* * 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. */ /* * SMP lock this sleep wakeup mechanism which is described * above. */ s = splimp();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -