Using select(2) to wait for connect(2)

Andrew Gollan adjg at otc.OZ
Tue Nov 25 17:27:38 AEST 1986


I need to have a server that forms a junction between two client
processes.  Further if one of the clients is not present the other must
still be serviced.  I read the manual on accept(2) and found that one
could use select(2) to wait for incoming connections. I wrote two
programs of which the following are the pertinent exerpts. Assume that
the 'name' variables are all legal pathnames.

------------------------------------------------------------------------
/*	SERVER	*/
static int	mkdlink(name)
char	*name;
{
    register int	s;
    sockaddr_un		sun;	

    unlink(name);

    sun.sun_family = AF_UNIX;
    strcpy(sun.sun_path, name);

    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
	return -1;

    if (bind(s, (sockaddr *)&sun, strlen(sun.sun_path) + sizeof (short)) < 0)
	return -1;

    return s;
}

main()
{
    register int	s0;
    register int	s1;
    register int	accepted	= 0;


    s0 = mkdlink((char *)name1);
    s1 = mkdlink((char *)name2);

    (void)listen(s0, 1);
    (void)listen(s1, 1);

    for (;;)
    {
	int 		mask	= (1 << s0) | (1 << s1);
	register int 	i;

	if (select(2, &mask, (int *)0, (int *)0, 0) < 0)
	    exit(1);

	for (i = 0; i < NOFILE; ++i)
	{
	    if ((mask & (1 << i)) == 0)
		continue;

	    if (accepted & (1 << i))
	    {
		register int	other;
		register int	cnt;
		char		buf[1024];
		
		if (i == s0)
		    other = s1;
		else
		    other = s0;
		
		if
		(
		    (cnt = read(i, buf, sizeof (buf))) > 0
		    &&
		    (accepted & (1 << other))
		)
		    (void)write(other, buf, cnt);
	    }
	    else
	    {
		register int ns;
		sockaddr from;
		int fromlen = sizeof from;

		if ((ns = accept(i, &from, &fromlen)) < 0)
		    exit(1);

		close(i);

		if (i == s0)
		    s0 = ns;
		else
		    s1 = ns;
		accepted |= (1 << ns);
	    }
	}
    }
}

-------------------------------------------------------------------------
/*	CLIENT		*/
static int	mkdlink(name)
char	*name;
{
    register int	s;
    sockaddr_un		sun;	

    sun.sun_family = AF_UNIX;
    strcpy(sun.sun_path, name);

    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
	return -1;

    if (connect(s, (sockaddr *)&sun, strlen(sun.sun_path) + sizeof (short)) < 0)
	return -1;
    return s;
}

main()
{
    register int	s0;
    register int	cnt;
    int			haveread	= 0;
    char		buf[1024];

    s0 = mkdlink((char *)name1);

    for (;;)
    {
	int mask = (1 << 0) | (1 << s0);

	if (select(2, &mask, 0, 0, 0) < 0)
	    exit(1);

	for (register int i = 0; i < 32; ++i)
	{
	    if ((mask & (1 << i)) == 0)
		continue;

	    if ((cnt = read(i, buf, sizeof (buf))) < 0)
	    {
		exit(1);
	    }

	    if (cnt == 0)
	    {
		if (haveread)
		    exit(0);
		continue;
	    }

	    haveread = 1;

	    if (i == 0)
		(void)write(s0, buf, cnt);
	    else
		(void)write(1, buf, cnt);
	}
    }
}

------------------------------------------------------------------------
The problem:
	The select in the server never returns. The connects in the the
	client return immediately. It does not do very much useful. I
	was told that there were lots of bugs in the AF_UNIX domain, so
	I rewrote the code for the AF_INET domain. Same problem. I put
	a real live accept in the server for s0 before the select and
	it worked.

The questions:
	Am I doing something horribly wrong or is it that select(2)
	does not perform as documented? Have I missed something in the
	documentation?

			      Andrew Gollan
UUCP:	{seismo,mcvax}!otc.oz!adjg		ACSnet:	adjg at otc.oz
		    Overseas Telecommunications Commission



More information about the Comp.unix.wizards mailing list