From: gsa@easyaspi.udev.cdc.com (gary s anderson)
Newsgroups: comp.protocols.tcp-ip
Subject: Re: rpc process chewing up resources
Date: 6 Nov 92 22:08:11 GMT
Reply-To: gsa@easyaspi.udev.cdc.com (gary s anderson)

In article <DERAADT.92Nov5044404@newt.newt.cuc.ab.ca>, deraadt@newt.cuc.ab.ca (Theo de Raadt) writes:
|> I'm currently implimenting YP client functionality for 386bsd. So far,
|> it's been an enjoyable and frustrating time....
|> 
|> In article <49256@shamash.cdc.com> gsa@easyaspi.udev.cdc.com (gary s anderson) writes:
|> >  |> > |> > sits within the "yp" library code (you need to ask SUN why "pinging"
|> >  |> > |> > the portmapper from within "yp" is useful).  This has the wonderful
|> >  |> > |> Hmmmph!
|> >  |> > |> What would you do if you wanted to discover if ypbind is running?
|> 
|> Well, on some systems (including my code at the moment) that's exactly
|> why TCP is used. It's faster than UDP.

Please explain how TCP is "faster" than UDP.  You are sending one request
and getting one reply.  This is an unfragmented request/reply sequence,
in the case discussed in this thread.  TCP adds an end-to-end
connect sequence besides sending the request and receiving the response.
I'd like to know which systems you use which can create a connection
and send a message faster than you can just send the message.

There are many reasons to use TCP but your comment on "faster"
is obviously missing some relevant context information.

|> 
|> My first code used UDP to find out if ypbind was running. Well, if you
|> don't get an answer, even in talking to 127.0.0.1, well, the kernel's
|> buffers could just be swamped at the moment. So you have to try a few
|> times. Not pretty.

If there are no kernel buffers you can't create a TCP connection
either.  The case where UDP suffers is when concurrent request
information overflows the receive socket.  In the case we are
talking about this isn't a major concern (i.e. small packets and
short think time in server.  Additionally, vendors selling useful
multi-user systems provide reasonable buffer sizes).  Consequently,
overflowing the TCP connect limit would be roughly 
equivalent to the UDP receive buffer limit.

NOTE - In case you missed, the TCP connection in question is directed 
to the portmapper not to ypbind.

|> 
|> So, I started using TCP. Immediate response yes/no whether YP is
|> running. I had no real concerns with whether the portmapper is
|> running.
|> 
|> I'm have a Sun too. A few minutes ago, I went and looked to see why
|> the file /etc/ypbind.lock exist... a bit of snooping and following a
|> hunch...
|> 
|>   4835 -rw-------  1 root            0 Nov  2 21:46 /etc/ypbind.lock
|>   ^^^^
|>  inode
|> 
|> pstat -i | grep 4835
|>  f23f9a8    R     7,  0  4835 100600   1    0         0   E     2   0   1 VREG
|> 							  ^^^
|> That little 'E' is an exclusive lock.
|> 
|> Could someone explain exactly what is going on here? What I suspect
|> follows: ypbind maintains the exclusive lock on /etc/ypbind.lock
|> Processes that are interested can find out if ypbind is running by
|> doing a lockf(fd, F_TEST).  Sun's ypbind also puts an exclusive lock
|> on /var/yp/binding/domainname.2 and /var/yp/binding/domainname.1.  I
|> suspect the 2 is YPBINDVERS.
|> 
|> Just trying to get a flock() on that file seems to work. This is so much
|> easier than what it appears the entire argument here is about.
|> 
|> Here's what happens if I trace a program that needs to check YP.
|> 
|>     open ("/var/yp/binding/cuc.ab.ca.2", 0, 036736173730) = 4
|>     flock (4, 06) = -1 EWOULDBLOCK (Operation would block)
|>     mmap (0x8ab8, 14, 0x1, 0x80000001, 4, 0) = 0xf7710000
|>     close (4) = 0
|> 
|> Aha. The fact that the flock() failed tells us that ypbind is running.
|> Sun places into the binding file the actual (struct sockaddr_in) at
|> which the current ypserver can be found (It could be ypbind's address,
|> but it makes more sense to be ypserv's address). So they mmap() the
|> (struct sockaddr_in) and continue.
|> 
|> >  |> > 
|> >  |> > I would send a UDP RPC request to the portmapper to find out
|> >  |> > if ypbind was registered.  The problem is that there is code
|> >  |> > which creates a "dummy" TCP connection just to see if the
|> >  |> > portmapper is running (i.e. doesn't trust UDP time-outs as 
|> >  |> > sufficient evidence that the portmapper is not running).
|> 
|> I would not trust a UDP timeout on "localhost" as meaning that the
|> portmapper is dead. It might take 5 seconds for a busy portmapper to
|> answer. Someone in Timbuktu, at the end of a very slow link, may have
|> been spraying the portmapper. Packets may have convoyed, and the
|> portmapper may be swamped! How long are you going to wait around?

Why do you assume that this same phantom you fear cannot spray the
portmapper with bogus TCP connections?  You will find that the same
quantity of bogus TCP connections are generally worse than bogus UDP 
packets.  People with this level of paranoia typically deploy firewalls.

Also, you seem to be disillusioned about what happens when a TCP
packet gets dumped on the ground.  You will note that it has a
regressive back-off timer with the lowest retry level at
approximately one second.  What TCP gives you is a well-respected
retry algorithm which may not always be present in various UDP
applications.

The advantage that was hypothesized for TCP (in this particular
thread) is that the UDP/ICMP "port not available" (i.e. no server currently
bound to the specified port) may not be as well supported as the
equivalent TCP RST functionality.  If your application has some
semantical benefit gain from this feature then TCP might be
a better choice. 

|> 
|> >  |> > If the connection succeeds, it is immediately closed and then
|> >  |> > the UDP RPC request is made to the portmapper to get the 
|> >  |> > information about ypbind.
|> >  |> 
|> >  |> Perhaps my point was not clear.
|> >  |> 
|> >  |> By using TCP you avoid having to wait for a UDP time-out to expire when
|> >  |> things are not present.  Which would make you more unhappy?  Having an
|> >  |> anonymous TCP port number tied up for a little while or having to wait
|> >  |> a large part of a second (or more if you allow remote access over slow
|> >  |> links) to discover that the portmapper is not running?
|> 
|> With TCP, your connection will succeed immediately, well, as long as
|> the listen queue has room for you....
|> 
|> 
|> Really, I prefer Sun's method of checking for yellow. A flock() on a
|> locked file means you are talking to an inode that is already in the
|> buffer cache. That's got to be faster and more reliable than talking
|> to portmap & ypbind.

As long as everything is local you can reliably use files for
interlocking, however, I would not be overly enthused to see rpc.lockd
as the cornerstone for provision of these services (e.g. you ever needed
to solve a remote concurrency issue).

|> 
|> Anyways, I'm going to impliment my routines much like Sun's did!
|> 
|> Only one thing bothers me with the RPC programming I am doing. Sun's
|> ypbind is not multithreaded; rather, it forks when it gets a request
|> for a currently unbound domain. I decided to make my ypbind much more
|> multithreaded. What I have come to discover to my disgust is that if
|> you wish to write a properly multithreaded RPC application you have to
|> give up all the juicy RPC and SVC routines and dig right into the XDR
|> level. What a pain. And, boy, I could scream because I have found no
|> way to access msg->msg_xid from the SVC/RPC level! For a proper
|> multi-threaded application, you are going to need to save a copy of
|> that for the later reply!
|>  <tdr.
|> --

  
One technique is to use request-only primitives (e.g. use timeout==0) to satisfy
multi-threading needs.  However, since you probably want to interoperate
with existing ypbind entities this probably won't help much.


|> 
|> This space not left unintentionally unblank.		deraadt@newt.cuc.ab.ca