Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Posting-Version: version B 2.10.2 9/5/84; site psuvax1.UUCP
Path: utzoo!watmath!clyde!cbosgd!cbdkc1!desoto!packard!hoxna!houxm!whuxlm!akgua!psuvax1!dae
From: dae@psuvax1.UUCP (Daemon)
Newsgroups: net.bugs.4bsd,net.unix-wizards
Subject: WARNING about 4.2BSD connect()
Message-ID: <1592@psuvax1.UUCP>
Date: Tue, 1-Jan-85 15:36:57 EST
Article-I.D.: psuvax1.1592
Posted: Tue Jan  1 15:36:57 1985
Date-Received: Thu, 3-Jan-85 04:00:05 EST
Distribution: net
Organization: The Furnace
Lines: 135
Xref: watmath net.bugs.4bsd:1307 net.unix-wizards:11307


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 
#include 
#include 
#include 

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.