WARNING about 4.2BSD connect()
Daemon
dae at psuvax1.UUCP
Wed Jan 2 06:36:57 AEST 1985
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.
More information about the Comp.unix.wizards
mailing list