Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!munnari!otc!adjg From: adjg@otc.OZ (Andrew Gollan) Newsgroups: comp.unix.wizards Subject: Using select(2) to wait for connect(2) Message-ID: <46@otc.OZ> Date: Tue, 25-Nov-86 02:27:38 EST Article-I.D.: otc.46 Posted: Tue Nov 25 02:27:38 1986 Date-Received: Tue, 25-Nov-86 09:55:44 EST Organization: O.T.C. Systems Development, Australia Lines: 174 Keywords: select sockets AF_UNIX 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@otc.oz Overseas Telecommunications Commission