dae@psuvax1.UUCP (Daemon) (01/01/85)
Description: A connect() call that fails due to a missing recipient invalidates later uses of the socket: s = socket(stuff, stuff, stuff); connect (s, stuff, stuff); /* let's say it fails because recipient socket isn't there */ connect (s, stuff, stuff); or listen(s, anything) /* fails, errno = EINVAL */ In other words, if a connect() fails, the socket must be closed and totally regenerated. It could be argued that this is not a bug, since at least the listen on a connected socket should fail, BUT connect(s, stuff, stuff) /* let's say it succeeds */ listen(s, anything) /* succeeds !!! */ Repeat-by: The following code is really sad, but it serves to illustrate the point: a.out hostname servername try servers that don't exist, and one server that does exist (in /etc/services) but is not currently active. Instructive, no? #include <sys/types.h> #include <netdb.h> #include <sys/socket.h> #include <netinet/in.h> extern int errno; main(argc, argv) int argc; char **argv; { struct hostent *hp, *gethostbyname(); struct servent *sp, *getservbyname(); struct protoent *pp, *getprotobyname(); struct sockaddr_in sin; int s; if (argc != 3) exit(-5); bzero(&sin, sizeof(sin)); if ( (sp = getservbyname(argv[2], (char *) 0)) == (struct servent *) 0) die("serv"); sin.sin_port = sp->s_port; sin.sin_family = AF_INET; if ( (hp = gethostbyname(argv[1])) == (struct hostent *) 0) die ("host"); bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); if ( (pp = getprotobyname(sp->s_proto)) == (struct protoent *) 0) die("proto"); if ( (s = socket(hp->h_addrtype, SOCK_STREAM, pp->p_proto)) == -1) die("socket"); if ( connect(s, &sin, sizeof(sin)) == -1 ) { perror("connect (first time)"); if ( connect(s, &sin, sizeof(sin)) == -1 ) perror("connect (second time)"); else printf("no connect error (second time)\n"); } else printf("no connect error (first time)\n"); if (listen(s, 1) == -1) perror("listen"); else printf("no listen error\n"); if (close(s) == -1) perror("close"); else printf("no close error\n"); exit(0); } int die(m) char *m; { printf("Death = %s\nErrno = %d\n", m, errno); perror("die"); exit(-45); } Also-in: /usr/src/usr.bin/lpr/common.c, function getport() re-makes the socket every time the connect fails. Fix: I have absolutely no idea. Sorry, folks, but I'm not really a wizard. Just thought I'd warn you that it's not your code that's failing, but the kernel. Complaint: Anybody ever noticed how hard it is to have two *peer* processes get a socket 'tween them? Berkeley (or tcp) is really into this client-server (masochist-sadist) philosophy--one person has to grovel, and the other may deign to accept conversation. The lpr code (which I wish I had seen *before* I wrote mine) should be very instructive. Questions: Is the ambiguity of ECONNREFUSED (can mean (1) nobody there or (2) his queue is zero-length) inherent to tcp? Is anybody writing any other protocols out there? please? -- \ / \/ \ / From the furnace of Daemon ( ...{psuvax1,gondor,shire}!dae ) \/ (814) 237-1901 "I will have no covenants but proximities" [Emerson] When the going gets tough, the weird turn pro.