Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 26 Mar 2001 21:35:11 -0800 (PST)
From:      wpaul@FreeBSD.ORG (Bill Paul)
To:        bright@wintelcom.net (Alfred Perlstein)
Cc:        current@freebsd.org
Subject:   Re: Fixing ypbind with TI-RPC
Message-ID:  <20010327053511.CE44B37B719@hub.freebsd.org>
In-Reply-To: <20010326200943.N9431@fw.wintelcom.net> from Alfred Perlstein at "Mar 26, 2001 08:09:43 pm"

next in thread | previous in thread | raw e-mail | index | archive | help
> > 
> > Why can't you just enable sigio on the reply socket, send all the
> > requests with a 0 timeout and then wait for a signal to either
> > interrupt the sending or to notify you when you complete sending?
> > 
> > Your solution seems awfully complex for what seems to be a simple
> > problem; doing a directed broadcast and taking the first answer you
> > get back.
> > 
> > Is the whole reason you need to do this because you're using the
> > xid to differentiate between the servers?

Once upon a time, a young coder needed to be able to send multiple
RPC requests and then wait for a single reply, instead of adhering to
the strict request/reply mechanism in the existing code. So he studied
the problem over many long nights. He fretted. He fussed. He tried not
to reinvent the wheel or cure cancer while he was at it. Eventually,
he made a couple of minor changes to a piece of existing code that did
exactly what he wanted.

The end.

> If that's true then you have a couple of options...
> 
> We could add a hack to our version of the rpc library to
> allow manipulation/query of the xid.  Or if the reply's source
> doesn't match any of the destinations you can remember it and
> send out another ping to that address.

You're already allowed to get/set the transaction ID using CLGET_XID
and CLSET_XID, and I intend to use this too. All I want to do is invoke
YPPROC_DOMAIN_NONACK on a bunch of servers and see which one replies
first, and I need to do it using unicasts because broadcasts won't get
forwarded across routers or point-to-point dialup links. I originally
created this monstrosity for NIS+, and decided it would be useful to
silence the people who insisted on putting their NIS clients on separate
networks from their NIS servers, and didn't want to set up NIS slaves
on the remote subnets like they were supposed to.

I'm including a patch to clnt_dg.c and clnt.h that adds the functionality
I need. It's quite small, and it's the path of least resistance in this
case, which is why I prefer it in this case in spite of the brokenness
it seeks to supress. Oh, there's also a fix for a bug in here. At least,
I think it's a bug. The clnt_dg_call() routine increments the transaction
ID before transmitting a request. It assumes that the XID is a 32-bit
value at a certain position in the block to be sent, and simply does a
cast to a u_int32_t and an in-place increment. The problem is, this value
is actually in network byte order, so to increment it properly, you need
to ntohl() it first, increment, then htonl() it back. Of course, if you
believe Sun, all the world's a SPARC, so for them it doesn't matter. This
really only becomes a problem if you actually use the CLGET_XID and
CLSET_XID control codes on a UDP client handle: the code in clnt_dg_control()
does the proper byte swapping, but clnt_dg_call() doesn't.

I'm not positive I'm doing the right thing here, but without this fix,
my newly hacked __yp_ping() routine produces some weird results.

-Bill


*** clnt_dg.c.orig	Mon Mar 26 21:17:00 2001
--- clnt_dg.c	Mon Mar 26 21:21:08 2001
***************
*** 126,131 ****
--- 126,132 ----
  	char			*cu_outbuf;
  	u_int			cu_recvsz;	/* recv size */
  	struct pollfd		pfdp;
+ 	int			cu_async;
  	char			cu_inbuf[1];
  };
  
***************
*** 238,243 ****
--- 239,245 ----
  	cu->cu_total.tv_usec = -1;
  	cu->cu_sendsz = sendsz;
  	cu->cu_recvsz = recvsz;
+ 	cu->cu_async = FALSE;
  	(void) gettimeofday(&now, NULL);
  	call_msg.rm_xid = __RPC_GETXID(&now);
  	call_msg.rm_call.cb_prog = program;
***************
*** 312,317 ****
--- 314,320 ----
  	socklen_t fromlen, inlen;
  	ssize_t recvlen = 0;
  	int rpc_lock_value;
+ 	u_int32_t xid;
  
  	sigfillset(&newmask);
  	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
***************
*** 336,347 ****
  
  call_again:
  	xdrs = &(cu->cu_outxdrs);
  	xdrs->x_op = XDR_ENCODE;
  	XDR_SETPOS(xdrs, cu->cu_xdrpos);
  	/*
  	 * the transaction is the first thing in the out buffer
  	 */
! 	(*(u_int32_t *)(void *)(cu->cu_outbuf))++;
  	if ((! XDR_PUTINT32(xdrs, &proc)) ||
  	    (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
  	    (! (*xargs)(xdrs, argsp))) {
--- 339,357 ----
  
  call_again:
  	xdrs = &(cu->cu_outxdrs);
+ 	if (cu->cu_async == TRUE && xargs == NULL)
+ 		goto get_reply;
  	xdrs->x_op = XDR_ENCODE;
  	XDR_SETPOS(xdrs, cu->cu_xdrpos);
  	/*
  	 * the transaction is the first thing in the out buffer
+ 	 * XXX Yes, and it's in network byte order, so we should to
+ 	 * be careful when we increment it, shouldn't we.
  	 */
! 	xid = ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf));
! 	xid++;
! 	*(u_int32_t *)(void *)(cu->cu_outbuf) = htonl(xid);
! 
  	if ((! XDR_PUTINT32(xdrs, &proc)) ||
  	    (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
  	    (! (*xargs)(xdrs, argsp))) {
***************
*** 366,371 ****
--- 376,384 ----
  		release_fd_lock(cu->cu_fd, mask);
  		return (cu->cu_error.re_status = RPC_TIMEDOUT);
  	}
+ 
+ get_reply:
+ 
  	/*
  	 * sub-optimal code appears here because we have
  	 * some clock time to spare while the packets are in flight.
***************
*** 495,501 ****
  		if (recvlen < sizeof (u_int32_t))
  			continue;
  		/* see if reply transaction id matches sent id */
! 		if (*((u_int32_t *)(void *)(cu->cu_inbuf)) !=
  		    *((u_int32_t *)(void *)(cu->cu_outbuf)))
  			continue;
  		/* we now assume we have the proper reply */
--- 508,515 ----
  		if (recvlen < sizeof (u_int32_t))
  			continue;
  		/* see if reply transaction id matches sent id */
! 		if (cu->cu_async == FALSE &&
! 		    *((u_int32_t *)(void *)(cu->cu_inbuf)) !=
  		    *((u_int32_t *)(void *)(cu->cu_outbuf)))
  			continue;
  		/* we now assume we have the proper reply */
***************
*** 722,728 ****
  		*(u_int32_t *)(void *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT)
  			= htonl(*(u_int32_t *)(void *)info);
  		break;
! 
  	default:
  		release_fd_lock(cu->cu_fd, mask);
  		return (FALSE);
--- 736,744 ----
  		*(u_int32_t *)(void *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT)
  			= htonl(*(u_int32_t *)(void *)info);
  		break;
! 	case CLSET_ASYNC:
! 		cu->cu_async = *(int *)(void *)info;
! 		break;
  	default:
  		release_fd_lock(cu->cu_fd, mask);
  		return (FALSE);
*** clnt.h.orig	Mon Mar 26 21:17:02 2001
--- clnt.h	Mon Mar 26 16:21:33 2001
***************
*** 228,233 ****
--- 228,234 ----
   */
  #define CLSET_RETRY_TIMEOUT 4   /* set retry timeout (timeval) */
  #define CLGET_RETRY_TIMEOUT 5   /* get retry timeout (timeval) */
+ #define CLSET_ASYNC		19
  
  /*
   * void

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010327053511.CE44B37B719>