Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 14 Nov 1997 22:32:50 -0800 (PST)
From:      Matthew Dillon <dillon@backplane.com>
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   kern/5048: if shutdown(fd,1) called twice on socket, pending input data is lost
Message-ID:  <199711150632.WAA23109@apollo.backplane.com>
Resent-Message-ID: <199711150640.WAA03760@hub.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         5048
>Category:       kern
>Synopsis:       Calling shutdown(fd,1) multiple times will blow up input data
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Nov 14 22:40:00 PST 1997
>Last-Modified:
>Originator:     Matthew Dillon
>Organization:
Best Internet Communications
>Release:        FreeBSD 2.2-STABLE i386
>Environment:

	FreeBSD 2.2.5

>Description:

	If you call shutdown(socket, 1) twice, pending input data on the
	socket may be lost.

>How-To-Repeat:

	Open a TCP connection to some destination that sends you data
	(e.g. chargen), then call shutdown on the socket multiple times,
	the chargen will eventually stall.


/*
 * TESTSHUTDOWN localhost chargen
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/time.h>

#include <netinet/in.h>

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <setjmp.h>
#include <ctype.h>
#include <netdb.h>

void goforit(int fd);

int
main(int ac, char **av)
{
    int fd;
    int i;
    struct sockaddr_in sin;
    struct hostent *host;
    struct servent *serv;
    char *hostName = NULL;
    char *servName = NULL;

    for (i = 1; i < ac; ++i) {
	char *ptr = av[i];
	if (*ptr != '-') {
	    if (hostName == NULL)
		hostName = ptr;
	    else
		servName = ptr;
	    continue;
	}
	ptr += 2;
	switch(ptr[-1]) {
	case 'b':
	default:
	    printf("bad option: %s\n", ptr - 2);
	    exit(0);
	}
    }

    if (hostName == NULL) {
	puts("no hostname / ip address specified");
	exit(0);
    }
    if (servName == NULL) {
	puts("no portname / port number specified");
	exit(0);
    }

    bzero(&sin, sizeof(sin));
    sin.sin_family = AF_INET;

    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) > 0) {
        if ((host = gethostbyname(hostName)) != NULL) {
            sin.sin_family = host->h_addrtype;
            bcopy(host->h_addr, &sin.sin_addr, host->h_length);
	} else {
	    sin.sin_addr.s_addr = inet_addr(hostName);
	}
	if ((serv = getservbyname(servName, "tcp")) != NULL) {
	    sin.sin_port = serv->s_port;
	} else {
	    sin.sin_port = htons(strtol(servName, NULL, 0));
	}
	if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == 0) {
	    puts("connected");
	    goforit(fd);
	    close(fd);
	} else {
	    perror("connect");
	}
    }
    return(0);
}

void
goforit(int fd)
{
    int pid;
    int n;
    char buf[256];

    if ((pid = fork()) == 0) {
	int ttl = 0;

	while ((n = read(fd, buf, sizeof(buf))) > 0) {
	    write(1, buf, n);
	    ttl += n;
	    if (ttl > 1024) {
		printf("\n****** (CALLING SHUTDOWN) *******\n");
		shutdown(fd, 1);
		shutdown(fd, 1);
		ttl = 0;
	    }
	}
	exit(0);
    }
    while ((n = read(0, buf, sizeof(buf))) > 0) {
	int i = 0;
	int r;

	while (i < n && (r = write(fd, buf + i, n - i)) > 0) {
	    i += r;
	}
    }
    shutdown(fd, 1);
    while (wait(NULL) != pid)
	;
}

>Fix:



>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199711150632.WAA23109>