*BSD News Article 27979


Return to BSD News archive

Xref: sserve comp.unix.programmer:15430 comp.unix.bsd:13512
Path: sserve!newshost.anu.edu.au!munnari.oz.au!news.uwa.edu.au!DIALix!not-for-mail
From: peter@melbourne.DIALix.oz.au (Peter Wemm)
Newsgroups: comp.unix.programmer,comp.unix.bsd
Subject: Re: Detecting dead client in BSD socket
Date: 7 Mar 1994 16:43:49 +0800
Organization: DIALix Services, Melbourne, Australia.
Lines: 147
Sender: peter@melbourne.DIALix.oz.au
Message-ID: <2lepg5$fi4$1@melbourne.DIALix.oz.au>
References: <1994Mar3.154852.24090@il.us.swissbank.com> <2l92ia$hrd@u.cc.utah.edu> <1994Mar5.142417.28947@noao.edu>
NNTP-Posting-Host: melbourne.dialix.oz.au
Keywords: socket bsd death
X-Newsreader: NN version 6.5.0 #55 (NOV)

rstevens@noao.edu (W. Richard Stevens) writes:
>> > Is there a way to determine, from the server side, whether a client has
>> > closed its end of the connection in a BSD socket?
>>
>> Set SO_KEEPALIVE as an option and notification will be more immediate; be
>> sure and use select on the socket and check for exceptional conditions.

>Check for "readability" not an "exception" condition.  If the other end
>dies, or dies and reboots, your socket will become readable after the
>keepalive probe(s) are sent; issue a read, and the error will probably
>be ETIMEDOUT or ECONNRESET.  Check Chapter 23 of my recent book "TCP/IP
>Illustrated" for lots of information on keepalives.  (This chapter is
>also reprinted in the Feb. 94 issue of Interop's ConneXions.)  If you're
>going to use keepalives, you need to understand how they're implemented
>by TCP, regardless whether you use sockets or TLI.
> 
>> On the other hand, if it's a socket library on top of TLI and your UNIX
>> obeys the notification protocol,

>Socket libraries on systems such as SVR4 are *not* built on top of TLI.
>This is a fundamental misconception that is continually repeated.  Sockets
>are built on top of TPI, the "Transport Provider Interface", a spec you
>can ftp from ftp.ui.org in pub/osi/tpi.ps.  The socket library talks to
>TPI just like TLI does.  Both require a special kernel streams module
>to help: sockmod and timod.  (Rago correctly talks about this in Section
>12.3 of his book "UNIX System V Network Programming".)  TLI may be "closer"
>to TPI than sockets (since they're both made to look OSI-ish) but to say
>that sockets in SVR4 are built on top is TLI is plain wrong.

>> rewriting directly to TLI will let you
>> not only run on other protocol stacks (XNS, IPX, OSI, etc.), it will
>> provide disconnect notification.

>Ah, but protocol independence does have its price, doesn't it :-)  Using
>sockets I can get or set the SO_KEEPALIVE option with 3 lines of code
>(assignment, function call, error handling).  Please show the equivalent
>TLI code.  I am especially interested in your implementation of getsockopt()
>using TLI (not XTI).

>	Rich Stevens  (rstevens@noao.edu)

SVR4 has two socket implementations.. There's the Lachman derived
protocol stack with the Sun/AT&T/whoever 'sockmod' and the user
library, and then there's the Wollongong (sp?) Win/TCP that's used on
the AT&T / NCR machines.

The sockmod approach, as you say, is built over TPI.  It is a
_reasonably_ faithful implementation of the traditional socket
semantics, but there are still some "gotchas" there to keep the
programmer on their toes.  There are a couple of real dangers with the
user-level library that keeps a malloc()ed "state" per open socket
descriptor.  Try dup()in them and other things like that and watch
your memory leak away. :-(

However, Win/TCP as I understand it, is built over the top of TLI.  It
has the classic TLI problems there, like accept() blowing up if there
are more than one queued connection and so on.  The 'StarServer'
family (I'm on one of the starserver mailing lists, but I've never
used one..) have problems with this every so often.  

Here's some food for thought. This code was once extracted from the
X11 source.  I believe it's basically a cleaned up SVR4 version of
some existing X code.

Oh, and this is setsockopt, not getsockopt as you requested.. :-)
---------------------------
#include    <stdio.h>
#include    <sys/types.h>
#include    <sys/sockio.h>
#include    <sys/tiuser.h>
#include    <sys/stropts.h>
#include    <sys/socket.h>
#include    <netinet/in.h>
#include    <net/if.h>
#include    <sys/ioctl.h>

/*
 * Streams-TLI emulation of setsockopt(2)
 */
static void Terror();

setsockopt(fd,level,opt,way,waysize)
int	fd;
int 	*way;
{
	struct optdesc {
		int     level;		/* Protocol Level Affected */
		int     optname;	/* option name to modify */
		int     len;		/* sizeof value */
		int     value;		/* value set or retrieved */
	};
	struct t_optmgmt	req, ret;
	struct optdesc		optreq, optret;
	extern int		t_errno;

	memset((char *)&req, 0, sizeof(req));
	req.opt.buf 	= (char *)&optreq;
	req.opt.len 	= sizeof(optreq);
	req.opt.maxlen 	= sizeof(optreq);
	req.flags 	= T_NEGOTIATE;

	memset((char *)&ret, 0, sizeof(ret));
	ret.opt.buf 	= (char *)&optret;
	ret.opt.len 	= sizeof(optret);
	ret.opt.maxlen 	= sizeof(optret);
	ret.flags 	= 0;
	memset((char *)&optret, 0, sizeof(optret));

	memset((char *)&optreq, 0, sizeof(optreq));
	optreq.optname 	= opt;
	optreq.level 	= level;
	optreq.value    = *way;
	optreq.len      = waysize;
	if(t_optmgmt(fd, &req, &ret) < 0) {
		Terror("t_optmgmt");
		return(-1);
	}

	if(ret.flags != T_SUCCESS && ret.flags != T_NEGOTIATE) {
		fprintf(stderr, "t_optmgmt %d: ret.flags=0x%x\n", opt,
			ret.flags);
		return(-1);
	}
	return(0);
}


static void
Terror(s)
char *s;
{
	extern int t_errno;

	if(t_errno == TSYSERR)
		perror(s);
	else
		t_error(s);
}
---------------------------

Lovely, isn't it... :-)

-Peter
-- 
Peter Wemm <peter@DIALix.oz.au> - NIC Handle: PW65 - The keeper of "NN"
      "My computer is better than your computer" - Anonymous
  (Overheard, shortly after the creation of the second computer....)