read函数调用路径
tcp&&ip.addr==172.18.83.223&&(portmap||data)
/*注意这个数据结构,专门用于server读取和回复数据的*/
#define LAST_FRAG (1UL << 31)
typedef struct rec_strm
{
caddr_t tcp_handle;
caddr_t the_buffer;
/*
* out-going bits
*/
int (*writeit) (char *, char *, int);
caddr_t out_base; /* output buffer (points to frag header) */
caddr_t out_finger; /* next output position */
caddr_t out_boundry; /* data cannot up to this address */
u_int32_t *frag_header; /* beginning of curren fragment */
bool_t frag_sent; /* true if buffer sent in middle of record */
/*
* in-coming bits
*/
int (*readit) (char *, char *, int);
u_long in_size; /* fixed size of the input buffer */
caddr_t in_base;
caddr_t in_finger; /* location of next byte to be had */
caddr_t in_boundry; /* can read up to this location */
long fbtbc; /* fragment bytes to be consumed */
bool_t last_frag;
u_int sendsize;
u_int recvsize;
}
RECSTREAM;
/*
* 感悟:凡是使用函数指针调用的地方,一般都有一个堆对应的函数群,在函数群中一个专门负责初始化这些函数指针的create函数
* 从最上层函数到,最底层的read write函数都有个共同的特点,就是每个函数都会用返回值通知上层函数自己是否调用成功,
* 每一次read,write的情况都会被上层知道,最后还可以通过内部变量strm_stat返回错误代码,返回值只用来作为错误处理。
*/
#0 readtcp (xprtptr=0x8051708 "\t", buf=0x80529e0 "", len=) at svc_tcp.c:325
#1 0x00232be6 in fill_input_buf (rstrm=0x80519f8) at xdr_rec.c:586
#2 0x00232f02 in get_input_bytes (rstrm=0x80519f8, addr=0xbfffdfbc "i/#", len=4) at xdr_rec.c:606
#3 0x00232fac in set_input_fragment (rstrm=0x80519f8) at xdr_rec.c:626
#4 0x0023300c in xdrrec_getbytes (xdrs=0x8051848, addr=0xbfffdfe8 "\t", len=4) at xdr_rec.c:264
#5 0x00233348 in xdrrec_getlong (lp=0xbfffe010, xdrs=0x8051848) at xdr_rec.c:220
#6 xdrrec_getlong (xdrs=0x8051848, lp=0xbfffe010) at xdr_rec.c:204
#7 0x00231c5c in xdr_long (xdrs=0x8051848, lp=0xbfffe010) at xdr.c:171
#8 0x00231fb3 in xdr_char (xdrs=0x8051848, cp=0xbfffe488 "") at xdr.c:360
#9 0x00232748 in xdr_vector (xdrs=0x8051848, basep=0xbfffe0d4 "", nelem=4000, elemsize=1, xdr_elem=0x8048c10 ) at xdr_array.c:156
#10 0x080494ea in xdr_MATH (xdrs=0x8051848, objp=0xbfffe0a8) at math_xdr.c:22
#11 0x002308dc in svctcp_getargs (xprt=0x8051708, xdr_args=0x8049424 , args_ptr=0xbfffe0a8 "") at svc_tcp.c:381
#12 0x08048faf in math_prog_2 (rqstp=0xbffff5c0, transp=0x8051708) at math_svc.c:47
#13 0x0022fd51 in svc_getreq_common (fd=9) at svc.c:485
#14 0x0022fae7 in svc_getreq_poll (pfdp=0x80539a8, pollretval=1) at svc.c:415
#15 0x002303ef in svc_run () at svc_run.c:95
#16 0x08049205 in main (argc=1, argv=0xbffff704) at math_svc.c:89
int
main (int argc, char **argv)
{
register SVCXPRT *transp;
pmap_unset (MATH_PROG, MATH_VER);
transp = svcudp_create(RPC_ANYSOCK);
if (transp == NULL) {
fprintf (stderr, "%s", "cannot create udp service.");
exit(1);
}
if (!svc_register(transp, MATH_PROG, MATH_VER, math_prog_2, IPPROTO_UDP)) {
fprintf (stderr, "%s", "unable to register (MATH_PROG, MATH_VER, udp).");
exit(1);
}
transp = svctcp_create(RPC_ANYSOCK, 0, 0);
if (transp == NULL) {
fprintf (stderr, "%s", "cannot create tcp service.");
exit(1);
}
if (!svc_register(transp, MATH_PROG, MATH_VER, math_prog_2, IPPROTO_TCP)) {
fprintf (stderr, "%s", "unable to register (MATH_PROG, MATH_VER, tcp).");
exit(1);
}
//进入下一层
svc_run ();
fprintf (stderr, "%s", "svc_run returned");
exit (1);
/* NOTREACHED */
}
void
svc_run (void)
{
int i;
struct pollfd *my_pollfd = NULL;
int last_max_pollfd = 0;
for (;;)
{
int max_pollfd = svc_max_pollfd;
if (max_pollfd == 0 && svc_pollfd == NULL)
break;
if (last_max_pollfd != max_pollfd)
{
struct pollfd *new_pollfd
= realloc (my_pollfd, sizeof (struct pollfd) * max_pollfd);
if (new_pollfd == NULL)
{
perror (_("svc_run: - out of memory"));
break;
}
my_pollfd = new_pollfd;
last_max_pollfd = max_pollfd;
}
for (i = 0; i < max_pollfd; ++i)
{
my_pollfd[i].fd = svc_pollfd[i].fd;
my_pollfd[i].events = svc_pollfd[i].events;
my_pollfd[i].revents = 0;
}
switch (i = __poll (my_pollfd, max_pollfd, -1))
{
case -1:
if (errno == EINTR)
continue;
perror (_("svc_run: - poll failed"));
break;
case 0:
continue;
default:
//进入下一层
INTUSE(svc_getreq_poll) (my_pollfd, i);
continue;
}
break;
}
free (my_pollfd);
}
void
svc_getreq_poll (struct pollfd *pfdp, int pollretval)
{
if (pollretval == 0)
return;
register int fds_found;
for (int i = fds_found = 0; i < svc_max_pollfd; ++i)
{
register struct pollfd *p = &pfdp[i];
if (p->fd != -1 && p->revents)
{
/* fd has input waiting */
if (p->revents & POLLNVAL)
xprt_unregister (xports[p->fd]);
else
//进入下一层
INTUSE(svc_getreq_common) (p->fd);
if (++fds_found >= pollretval)
break;
}
}
}
INTDEF (svc_getreq_poll)
void
svc_getreq_common (const int fd)
{
enum xprt_stat stat;
struct rpc_msg msg;
register SVCXPRT *xprt;
char cred_area[2 * MAX_AUTH_BYTES + RQCRED_SIZE];
msg.rm_call.cb_cred.oa_base = cred_area;
msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
xprt = xports[fd];
/* Do we control fd? */
if (xprt == NULL)
return;
/* now receive msgs from xprtprt (support batch calls) */
do
{
//注意这里实际上是调用了svctcp_recv,而在svctcp_recv中设置了xdrs->x_op = XDR_DECODE。
if (SVC_RECV (xprt, &msg))
{
/* now find the exported program and call it */
struct svc_callout *s;
struct svc_req r;
enum auth_stat why;
rpcvers_t low_vers;
rpcvers_t high_vers;
int prog_found;
r.rq_clntcred = &(cred_area[2 * MAX_AUTH_BYTES]);
r.rq_xprt = xprt;
r.rq_prog = msg.rm_call.cb_prog;
r.rq_vers = msg.rm_call.cb_vers;
r.rq_proc = msg.rm_call.cb_proc;
r.rq_cred = msg.rm_call.cb_cred;
/* first authenticate the message */
/* Check for null flavor and bypass these calls if possible */
if (msg.rm_call.cb_cred.oa_flavor == AUTH_NULL)
{
r.rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor;
r.rq_xprt->xp_verf.oa_length = 0;
}
else if ((why = INTUSE(_authenticate) (&r, &msg)) != AUTH_OK)
{
svcerr_auth (xprt, why);
goto call_done;
}
/* now match message with a registered service */
prog_found = FALSE;
low_vers = 0 - 1;
high_vers = 0;
for (s = svc_head; s != NULL_SVC; s = s->sc_next)
{
if (s->sc_prog == r.rq_prog)
{
if (s->sc_vers == r.rq_vers)
{
//进入下一层
(*s->sc_dispatch) (&r, xprt);
goto call_done;
}
/* found correct version */
prog_found = TRUE;
if (s->sc_vers < low_vers)
low_vers = s->sc_vers;
if (s->sc_vers > high_vers)
high_vers = s->sc_vers;
}
/* found correct program */
}
/* if we got here, the program or version
is not served ... */
if (prog_found)
svcerr_progvers (xprt, low_vers, high_vers);
else
svcerr_noprog (xprt);
/* Fall through to ... */
}
call_done:
if ((stat = SVC_STAT (xprt)) == XPRT_DIED)
{
SVC_DESTROY (xprt);
break;
}
}
while (stat == XPRT_MOREREQS);
}
INTDEF (svc_getreq_common)
static void
math_prog_2(struct svc_req *rqstp, register SVCXPRT *transp)
{
union {
struct MATH math_proc_2_arg;
} argument;
char *result;
xdrproc_t _xdr_argument, _xdr_result;
char *(*local)(char *, struct svc_req *);
switch (rqstp->rq_proc) {
case NULLPROC:
(void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL);
return;
case MATH_PROC:
_xdr_argument = (xdrproc_t) xdr_MATH;
_xdr_result = (xdrproc_t) xdr_MATH;
local = (char *(*)(char *, struct svc_req *)) math_proc_2_svc;
break;
default:
svcerr_noproc (transp);
return;
}
memset ((char *)&argument, 0, sizeof (argument));
//进入下一层
if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
svcerr_decode (transp);
return;
}
result = (*local)((char *)&argument, rqstp);
if (result != NULL && !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) {
svcerr_systemerr (transp);
}
if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
fprintf (stderr, "%s", "unable to free arguments");
exit (1);
}
return;
}
static bool_t
svctcp_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
{
//进入下一层
return ((*xdr_args) (&(((struct tcp_conn *)
(xprt->xp_p1))->xdrs), args_ptr));
}
bool_t
xdr_MATH (XDR *xdrs, MATH *objp)
{
register int32_t *buf;
int i;
if (!xdr_int (xdrs, &objp->op))
return FALSE;
if (!xdr_vector (xdrs, (char *)objp->arg1, 20,
sizeof (char), (xdrproc_t) xdr_char))
return FALSE;
if (!xdr_vector (xdrs, (char *)objp->arg2, 20,
sizeof (char), (xdrproc_t) xdr_char))
return FALSE;
//进入下一层
if (!xdr_vector (xdrs, (char *)objp->result, 4000,
sizeof (char), (xdrproc_t) xdr_char))
return FALSE;
return TRUE;
}
/*
* xdr_vector():
*
* XDR a fixed length array. Unlike variable-length arrays,
* the storage of fixed length arrays is static and unfreeable.
* > basep: base of the array
* > size: size of the array
* > elemsize: size of each element
* > xdr_elem: routine to XDR each element
*/
bool_t
xdr_vector (xdrs, basep, nelem, elemsize, xdr_elem)
XDR *xdrs;
char *basep;
u_int nelem;
u_int elemsize;
xdrproc_t xdr_elem;
{
u_int i;
char *elptr;
elptr = basep;
for (i = 0; i < nelem; i++)
{
//进入下一层
if (!(*xdr_elem) (xdrs, elptr, LASTUNSIGNED))
{
return FALSE;
}
elptr += elemsize;
}
return TRUE;
}
/*
* XDR a char
*/
bool_t
xdr_char (XDR *xdrs, char *cp)
{
int i;
i = (*cp);
//进入下一层
if (!INTUSE(xdr_int) (xdrs, &i))
{
return FALSE;
}
*cp = i;
return TRUE;
}
/*
* XDR long integers
* The definition of xdr_long() is kept for backward
* compatibility. Instead xdr_int() should be used.
*/
bool_t
xdr_long (XDR *xdrs, long *lp)
{
if (xdrs->x_op == XDR_ENCODE
&& (sizeof (int32_t) == sizeof (long)
|| (int32_t) *lp == *lp))
return XDR_PUTLONG (xdrs, lp);
if (xdrs->x_op == XDR_DECODE)
//进入下一层
return XDR_GETLONG (xdrs, lp);
if (xdrs->x_op == XDR_FREE)
return TRUE;
return FALSE;
}
INTDEF(xdr_long)
/*
* The routines defined below are the xdr ops which will go into the
* xdr handle filled in by xdrrec_create.
*/
static bool_t
xdrrec_getlong (XDR *xdrs, long *lp)
{
RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
int32_t *buflp = (int32_t *) rstrm->in_finger;
int32_t mylong;
/* first try the inline, fast case */
if (rstrm->fbtbc >= BYTES_PER_XDR_UNIT &&
rstrm->in_boundry - (char *) buflp >= BYTES_PER_XDR_UNIT)
{
*lp = (int32_t) ntohl (*buflp);
rstrm->fbtbc -= BYTES_PER_XDR_UNIT;
rstrm->in_finger += BYTES_PER_XDR_UNIT;
}
else
{
//进入下一层
if (!xdrrec_getbytes (xdrs, (caddr_t) & mylong,
BYTES_PER_XDR_UNIT))
return FALSE;
*lp = (int32_t) ntohl (mylong);
}
return TRUE;
}
static bool_t /* must manage buffers, fragments, and records */
xdrrec_getbytes (XDR *xdrs, caddr_t addr, u_int len)
{
RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
u_int current;
while (len > 0)
{
current = rstrm->fbtbc;
if (current == 0)
{
if (rstrm->last_frag)
return FALSE;
if (!set_input_fragment (rstrm))
return FALSE;
continue;
}
current = (len < current) ? len : current;
//进入下一层
if (!get_input_bytes (rstrm, addr, current))
return FALSE;
addr += current;
rstrm->fbtbc -= current;
len -= current;
}
return TRUE;
}
static bool_t /* knows nothing about records! Only about input buffers */
internal_function
get_input_bytes (RECSTREAM *rstrm, caddr_t addr, int len)
{
int current;
while (len > 0)
{
current = rstrm->in_boundry - rstrm->in_finger;
if (current == 0)
{
//进入下一层
if (!fill_input_buf (rstrm))
return FALSE;
continue;
}
current = (len < current) ? len : current;
memcpy (addr, rstrm->in_finger, current);
rstrm->in_finger += current;
addr += current;
len -= current;
}
return TRUE;
}
static bool_t /* knows nothing about records! Only about input buffers */
fill_input_buf (RECSTREAM *rstrm)
{
caddr_t where;
size_t i;
int len;
where = rstrm->in_base;
i = (size_t) rstrm->in_boundry % BYTES_PER_XDR_UNIT;
where += i;
len = rstrm->in_size - i;
//进入下一层
if ((len = (*(rstrm->readit)) (rstrm->tcp_handle, where, len)) == -1)
return FALSE;
rstrm->in_finger = where;
where += len;
rstrm->in_boundry = where;
return TRUE;
}
/*
* reads data from the tcp connection.
* any error is fatal and the connection is closed.
* (And a read of zero bytes is a half closed stream => error.)
*/
static int
readtcp (char *xprtptr, char *buf, int len)
{
SVCXPRT *xprt = (SVCXPRT *)xprtptr;
int sock = xprt->xp_sock;
int milliseconds = 35 * 1000;
struct pollfd pollfd;
do
{
pollfd.fd = sock;
pollfd.events = POLLIN;
switch (__poll (&pollfd, 1, milliseconds))
{
case -1:
if (errno == EINTR)
continue;
/*FALLTHROUGH*/
case 0:
goto fatal_err;
default:
if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
|| (pollfd.revents & POLLNVAL))
goto fatal_err;
break;
}
}
while ((pollfd.revents & POLLIN) == 0);
//开始读
if ((len = __read (sock, buf, len)) > 0)
return len;
fatal_err:
((struct tcp_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
return -1;
}
write函数调用路径
WRITE I型callstack
#0 writetcp (xprtptr=0x8051708 "\t", buf=0x8051a40 "", len=4000) at svc_tcp.c:337
#1 0x00232d62 in flush_out (rstrm=0x80519f8, eor=) at xdr_rec.c:562
#2 0x00232e83 in xdrrec_putlong (xdrs=0x8051848, lp=0xbfffdf6c) at xdr_rec.c:242
#3 0x00231c45 in xdr_long (xdrs=0x8051848, lp=0xbfffdf6c) at xdr.c:168
#4 0x00231fb3 in xdr_char (xdrs=0x8051848, cp=0x804d02b "") at xdr.c:360
#5 0x00232748 in xdr_vector (xdrs=0x8051848, basep=0x804c88c "12", nelem=4000, elemsize=1, xdr_elem=0x8048c10 ) at xdr_array.c:156
#6 0x080494ea in xdr_MATH (xdrs=0x8051848, objp=0x804c860) at math_xdr.c:22
#7 0x0022e99d in xdr_accepted_reply (xdrs=0x8051848, ar=0xbfffe050) at rpc_prot.c:88
#8 0x002323e5 in xdr_union (xdrs=0x8051848, dscmp=0xbfffe04c, unp=0xbfffe050 "", choices=, dfault=0) at xdr.c:630
#9 0x0022eb58 in xdr_replymsg (xdrs=0x8051848, rmsg=0xbfffe044) at rpc_prot.c:144
#10 0x00230b00 in svctcp_reply (xprt=0x8051708, msg=0xbfffe044) at svc_tcp.c:403
#11 0x0022f765 in svc_sendreply (xprt=0x8051708, xdr_results=0x8049424 , xdr_location=0x804c860 "") at svc.c:254
#12 0x08049015 in math_prog_2 (rqstp=0xbffff5c0, transp=0x8051708) at math_svc.c:52
#13 0x0022fd51 in svc_getreq_common (fd=9) at svc.c:485
#14 0x0022fae7 in svc_getreq_poll (pfdp=0x80539a8, pollretval=1) at svc.c:415
#15 0x002303ef in svc_run () at svc_run.c:95
#16 0x08049205 in main (argc=1, argv=0xbffff704) at math_svc.c:89
WRITE II型callstack
#0 writetcp (xprtptr=0x8051708 "\t", buf=0x8051a40 "\200", len=208) at svc_tcp.c:337
#1 0x00232d62 in flush_out (rstrm=0x80519f8, eor=) at xdr_rec.c:562
#2 0x00230b12 in svctcp_reply (xprt=0x8051708, msg=0xbfffe044) at svc_tcp.c:404
#3 0x0022f765 in svc_sendreply (xprt=0x8051708, xdr_results=0x8049424 , xdr_location=0x804c860 "") at svc.c:254
#4 0x08049015 in math_prog_2 (rqstp=0xbffff5c0, transp=0x8051708) at math_svc.c:52
#5 0x0022fd51 in svc_getreq_common (fd=9) at svc.c:485
#6 0x0022fae7 in svc_getreq_poll (pfdp=0x80539a8, pollretval=1) at svc.c:415
#7 0x002303ef in svc_run () at svc_run.c:95
#8 0x08049205 in main (argc=1, argv=0xbffff704) at math_svc.c:89
int
main (int argc, char **argv)
{
register SVCXPRT *transp;
pmap_unset (MATH_PROG, MATH_VER);
transp = svcudp_create(RPC_ANYSOCK);
if (transp == NULL) {
fprintf (stderr, "%s", "cannot create udp service.");
exit(1);
}
if (!svc_register(transp, MATH_PROG, MATH_VER, math_prog_2, IPPROTO_UDP)) {
fprintf (stderr, "%s", "unable to register (MATH_PROG, MATH_VER, udp).");
exit(1);
}
transp = svctcp_create(RPC_ANYSOCK, 0, 0);
if (transp == NULL) {
fprintf (stderr, "%s", "cannot create tcp service.");
exit(1);
}
if (!svc_register(transp, MATH_PROG, MATH_VER, math_prog_2, IPPROTO_TCP)) {
fprintf (stderr, "%s", "unable to register (MATH_PROG, MATH_VER, tcp).");
exit(1);
}
//进入下一层
svc_run ();
fprintf (stderr, "%s", "svc_run returned");
exit (1);
/* NOTREACHED */
}
void
svc_run (void)
{
int i;
struct pollfd *my_pollfd = NULL;
int last_max_pollfd = 0;
for (;;)
{
int max_pollfd = svc_max_pollfd;
if (max_pollfd == 0 && svc_pollfd == NULL)
break;
if (last_max_pollfd != max_pollfd)
{
struct pollfd *new_pollfd
= realloc (my_pollfd, sizeof (struct pollfd) * max_pollfd);
if (new_pollfd == NULL)
{
perror (_("svc_run: - out of memory"));
break;
}
my_pollfd = new_pollfd;
last_max_pollfd = max_pollfd;
}
for (i = 0; i < max_pollfd; ++i)
{
my_pollfd[i].fd = svc_pollfd[i].fd;
my_pollfd[i].events = svc_pollfd[i].events;
my_pollfd[i].revents = 0;
}
switch (i = __poll (my_pollfd, max_pollfd, -1))
{
case -1:
if (errno == EINTR)
continue;
perror (_("svc_run: - poll failed"));
break;
case 0:
continue;
default:
//进入下一层
INTUSE(svc_getreq_poll) (my_pollfd, i);
continue;
}
break;
}
free (my_pollfd);
}
void
svc_getreq_poll (struct pollfd *pfdp, int pollretval)
{
if (pollretval == 0)
return;
register int fds_found;
for (int i = fds_found = 0; i < svc_max_pollfd; ++i)
{
register struct pollfd *p = &pfdp[i];
if (p->fd != -1 && p->revents)
{
/* fd has input waiting */
if (p->revents & POLLNVAL)
xprt_unregister (xports[p->fd]);
else
//进入下一层
INTUSE(svc_getreq_common) (p->fd);
if (++fds_found >= pollretval)
break;
}
}
}
INTDEF (svc_getreq_poll)
void
svc_getreq_common (const int fd)
{
enum xprt_stat stat;
struct rpc_msg msg;
register SVCXPRT *xprt;
char cred_area[2 * MAX_AUTH_BYTES + RQCRED_SIZE];
msg.rm_call.cb_cred.oa_base = cred_area;
msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
xprt = xports[fd];
/* Do we control fd? */
if (xprt == NULL)
return;
/* now receive msgs from xprtprt (support batch calls) */
do
{
if (SVC_RECV (xprt, &msg))
{
/* now find the exported program and call it */
struct svc_callout *s;
struct svc_req r;
enum auth_stat why;
rpcvers_t low_vers;
rpcvers_t high_vers;
int prog_found;
r.rq_clntcred = &(cred_area[2 * MAX_AUTH_BYTES]);
r.rq_xprt = xprt;
r.rq_prog = msg.rm_call.cb_prog;
r.rq_vers = msg.rm_call.cb_vers;
r.rq_proc = msg.rm_call.cb_proc;
r.rq_cred = msg.rm_call.cb_cred;
/* first authenticate the message */
/* Check for null flavor and bypass these calls if possible */
if (msg.rm_call.cb_cred.oa_flavor == AUTH_NULL)
{
r.rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor;
r.rq_xprt->xp_verf.oa_length = 0;
}
else if ((why = INTUSE(_authenticate) (&r, &msg)) != AUTH_OK)
{
svcerr_auth (xprt, why);
goto call_done;
}
/* now match message with a registered service */
prog_found = FALSE;
low_vers = 0 - 1;
high_vers = 0;
for (s = svc_head; s != NULL_SVC; s = s->sc_next)
{
if (s->sc_prog == r.rq_prog)
{
if (s->sc_vers == r.rq_vers)
{
//进入下一层
(*s->sc_dispatch) (&r, xprt);
goto call_done;
}
/* found correct version */
prog_found = TRUE;
if (s->sc_vers < low_vers)
low_vers = s->sc_vers;
if (s->sc_vers > high_vers)
high_vers = s->sc_vers;
}
/* found correct program */
}
/* if we got here, the program or version
is not served ... */
if (prog_found)
svcerr_progvers (xprt, low_vers, high_vers);
else
svcerr_noprog (xprt);
/* Fall through to ... */
}
call_done:
if ((stat = SVC_STAT (xprt)) == XPRT_DIED)
{
SVC_DESTROY (xprt);
break;
}
}
while (stat == XPRT_MOREREQS);
}
INTDEF (svc_getreq_common)
static void
math_prog_2(struct svc_req *rqstp, register SVCXPRT *transp)
{
union {
struct MATH math_proc_2_arg;
} argument;
char *result;
xdrproc_t _xdr_argument, _xdr_result;
char *(*local)(char *, struct svc_req *);
printf("enter_count:%d\n",enter_count++);
switch (rqstp->rq_proc) {
case NULLPROC:
(void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL);
return;
case MATH_PROC:
_xdr_argument = (xdrproc_t) xdr_MATH;
_xdr_result = (xdrproc_t) xdr_MATH;
local = (char *(*)(char *, struct svc_req *)) math_proc_2_svc;
break;
default:
svcerr_noproc (transp);
return;
}
memset ((char *)&argument, 0, sizeof (argument));
if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
svcerr_decode (transp);
return;
}
result = (*local)((char *)&argument, rqstp);
//进入下一层
if (result != NULL && !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) {
svcerr_systemerr (transp);
}
if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
fprintf (stderr, "%s", "unable to free arguments");
exit (1);
}
return;
}
/* ******************* REPLY GENERATION ROUTINES ************ */
/* Send a reply to an rpc request */
bool_t
svc_sendreply (register SVCXPRT *xprt, xdrproc_t xdr_results,
caddr_t xdr_location)
{
struct rpc_msg rply;
rply.rm_direction = REPLY;
rply.rm_reply.rp_stat = MSG_ACCEPTED;
rply.acpted_rply.ar_verf = xprt->xp_verf;
rply.acpted_rply.ar_stat = SUCCESS;
rply.acpted_rply.ar_results.where = xdr_location;
rply.acpted_rply.ar_results.proc = xdr_results;
//进入下一层
return SVC_REPLY (xprt, &rply);
}
INTDEF (svc_sendreply)
/*
svc_tcp.c
函数功能把msg按照预订好的xdr格式,按照TCP方式发送出去。
param:
SVCXPRT *xprt
struct rpc_msg *msg
*/
static bool_t
svctcp_reply (SVCXPRT *xprt, struct rpc_msg *msg)
{
struct tcp_conn *cd = (struct tcp_conn *) (xprt->xp_p1);
XDR *xdrs = &(cd->xdrs);
bool_t stat;
//注意这里的x_op,决定了后面XDR系列函数的会调用发送函数。
xdrs->x_op = XDR_ENCODE;
msg->rm_xid = cd->x_id;
//进入write I型
stat = INTUSE(xdr_replymsg) (xdrs, msg);
//进入write II型
(void) INTUSE(xdrrec_endofrecord) (xdrs, TRUE);
return stat;
}
/*write I型*/
/*
* XDR a reply message
*/
bool_t
xdr_replymsg (xdrs, rmsg)
XDR *xdrs;
struct rpc_msg *rmsg;
{
if (INTUSE(xdr_u_long) (xdrs, &(rmsg->rm_xid)) &&
INTUSE(xdr_enum) (xdrs, (enum_t *) & (rmsg->rm_direction)) &&
(rmsg->rm_direction == REPLY))
{
//进入下一层
return INTUSE(xdr_union) (xdrs, (enum_t *) & (rmsg->rm_reply.rp_stat),
(caddr_t) & (rmsg->rm_reply.ru), reply_dscrm,
NULL_xdrproc_t);
}
return FALSE;
}
INTDEF(xdr_replymsg)
/*
* XDR a discriminated union
* Support routine for discriminated unions.
* You create an array of xdrdiscrim structures, terminated with
* an entry with a null procedure pointer. The routine gets
* the discriminant value and then searches the array of xdrdiscrims
* looking for that value. It calls the procedure given in the xdrdiscrim
* to handle the discriminant. If there is no specific routine a default
* routine may be called.
* If there is no specific or default routine an error is returned.
*/
bool_t
xdr_union (xdrs, dscmp, unp, choices, dfault)
XDR *xdrs;
enum_t *dscmp; /* enum to decide which arm to work on */
char *unp; /* the union itself */
const struct xdr_discrim *choices; /* [value, xdr proc] for each arm */
xdrproc_t dfault; /* default xdr routine */
{
enum_t dscm;
/*
* we deal with the discriminator; it's an enum
*/
if (!INTUSE(xdr_enum) (xdrs, dscmp))
{
return FALSE;
}
dscm = *dscmp;
/*
* search choices for a value that matches the discriminator.
* if we find one, execute the xdr routine for that value.
*/
for (; choices->proc != NULL_xdrproc_t; choices++)
{
if (choices->value == dscm)
//进入下一层
return (*(choices->proc)) (xdrs, unp, LASTUNSIGNED);
}
/*
* no match - execute the default xdr routine if there is one
*/
return ((dfault == NULL_xdrproc_t) ? FALSE :
(*dfault) (xdrs, unp, LASTUNSIGNED));
}
INTDEF(xdr_union)
/* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */
/*
* XDR the MSG_ACCEPTED part of a reply message union
*/
bool_t
xdr_accepted_reply (XDR *xdrs, struct accepted_reply *ar)
{
/* personalized union, rather than calling xdr_union */
if (!INTUSE(xdr_opaque_auth) (xdrs, &(ar->ar_verf)))
return FALSE;
if (!INTUSE(xdr_enum) (xdrs, (enum_t *) & (ar->ar_stat)))
return FALSE;
switch (ar->ar_stat)
{
case SUCCESS:
//进入下一层
return ((*(ar->ar_results.proc)) (xdrs, ar->ar_results.where));
case PROG_MISMATCH:
if (!INTUSE(xdr_u_long) (xdrs, &(ar->ar_vers.low)))
return FALSE;
return (INTUSE(xdr_u_long) (xdrs, &(ar->ar_vers.high)));
default:
return TRUE;
}
return TRUE; /* TRUE => open ended set of problems */
}
INTDEF(xdr_accepted_reply)
bool_t
xdr_MATH (XDR *xdrs, MATH *objp)
{
register int32_t *buf;
int i;
if (!xdr_int (xdrs, &objp->op))
return FALSE;
if (!xdr_vector (xdrs, (char *)objp->arg1, 20,
sizeof (char), (xdrproc_t) xdr_char))
return FALSE;
if (!xdr_vector (xdrs, (char *)objp->arg2, 20,
sizeof (char), (xdrproc_t) xdr_char))
return FALSE;
//进入下一层
if (!xdr_vector (xdrs, (char *)objp->result, 4000,
sizeof (char), (xdrproc_t) xdr_char))
return FALSE;
return TRUE;
}
/*
* xdr_vector():
*
* XDR a fixed length array. Unlike variable-length arrays,
* the storage of fixed length arrays is static and unfreeable.
* > basep: base of the array
* > size: size of the array
* > elemsize: size of each element
* > xdr_elem: routine to XDR each element
*/
bool_t
xdr_vector (xdrs, basep, nelem, elemsize, xdr_elem)
XDR *xdrs;
char *basep;
u_int nelem;
u_int elemsize;
xdrproc_t xdr_elem;
{
u_int i;
char *elptr;
elptr = basep;
for (i = 0; i < nelem; i++)
{
//进入下一层
if (!(*xdr_elem) (xdrs, elptr, LASTUNSIGNED))
{
return FALSE;
}
elptr += elemsize;
}
return TRUE;
}
/*
* XDR a char
*/
bool_t
xdr_char (XDR *xdrs, char *cp)
{
int i;
i = (*cp);
//进入下一层
if (!INTUSE(xdr_int) (xdrs, &i))
{
return FALSE;
}
*cp = i;
return TRUE;
}
/*
* XDR long integers
* The definition of xdr_long() is kept for backward
* compatibility. Instead xdr_int() should be used.
*/
bool_t
xdr_long (XDR *xdrs, long *lp)
{
if (xdrs->x_op == XDR_ENCODE
&& (sizeof (int32_t) == sizeof (long)
|| (int32_t) *lp == *lp)){
//进入下一层
return XDR_PUTLONG (xdrs, lp);
}
if (xdrs->x_op == XDR_DECODE)
return XDR_GETLONG (xdrs, lp);
if (xdrs->x_op == XDR_FREE)
return TRUE;
return FALSE;
}
INTDEF(xdr_long)
static bool_t
xdrrec_putlong (XDR *xdrs, const long *lp)
{
RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
int32_t *dest_lp = (int32_t *) rstrm->out_finger;
if ((rstrm->out_finger += BYTES_PER_XDR_UNIT) > rstrm->out_boundry)
{
/*
* this case should almost never happen so the code is
* inefficient
*/
rstrm->out_finger -= BYTES_PER_XDR_UNIT;
rstrm->frag_sent = TRUE;
//进入下一层
if (!flush_out (rstrm, FALSE))
return FALSE;
dest_lp = (int32_t *) rstrm->out_finger;
rstrm->out_finger += BYTES_PER_XDR_UNIT;
}
*dest_lp = htonl (*lp);
return TRUE;
}
/*
* Internal useful routines
*/
static bool_t
internal_function
flush_out (RECSTREAM *rstrm, bool_t eor)
{
u_long eormask = (eor == TRUE) ? LAST_FRAG : 0;
u_long len = (rstrm->out_finger - (char *) rstrm->frag_header
- BYTES_PER_XDR_UNIT);
*rstrm->frag_header = htonl (len | eormask);
len = rstrm->out_finger - rstrm->out_base;
//进入下一层
if ((*(rstrm->writeit)) (rstrm->tcp_handle, rstrm->out_base, (int) len)
!= (int) len)
return FALSE;
rstrm->frag_header = (u_int32_t *) rstrm->out_base;
rstrm->out_finger = (caddr_t) rstrm->out_base + BYTES_PER_XDR_UNIT;
return TRUE;
}
/*
* writes data to the tcp connection.
* Any error is fatal and the connection is closed.
*/
static int
writetcp (char *xprtptr, char * buf, int len)
{
SVCXPRT *xprt = (SVCXPRT *)xprtptr;
int i, cnt;
for (cnt = len; cnt > 0; cnt -= i, buf += i)
{
//开始写
if ((i = __write (xprt->xp_sock, buf, cnt)) < 0)
{
((struct tcp_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
return -1;
}
}
return len;
}
//进入write II型
/*
* The client must tell the package when an end-of-record has occurred.
* The second parameter tells whether the record should be flushed to the
* (output) tcp stream. (This lets the package support batched or
* pipelined procedure calls.) TRUE => immediate flush to tcp connection.
*/
bool_t
xdrrec_endofrecord (XDR *xdrs, bool_t sendnow)
{
RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
u_long len; /* fragment length */
if (sendnow || rstrm->frag_sent
|| rstrm->out_finger + BYTES_PER_XDR_UNIT >= rstrm->out_boundry)
{
rstrm->frag_sent = FALSE;
//进入下一层
return flush_out (rstrm, TRUE);
}
len = (rstrm->out_finger - (char *) rstrm->frag_header
- BYTES_PER_XDR_UNIT);
*rstrm->frag_header = htonl ((u_long) len | LAST_FRAG);
rstrm->frag_header = (u_int32_t *) rstrm->out_finger;
rstrm->out_finger += BYTES_PER_XDR_UNIT;
return TRUE;
}
INTDEF(xdrrec_endofrecord)