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