RPC调用追踪

代码来自于gun elibc2.13

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)




你可能感兴趣的:(网络编程,C语言)