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 + -
显示快捷键?