Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 16 Feb 2003 00:32:52 +0200
From:      Giorgos Keramidas <keramida@ceid.upatras.gr>
To:        freebsd-current@freebsd.org
Subject:   UDP connect() behavior in 5.0-CURRENT
Message-ID:  <20030215223252.GA17712@gothmog.gr>

next in thread | raw e-mail | index | archive | help
The second volume of ``TCP/IP Illustrated'' by Stevens says that
already connected UDP sockets return EISCONN on any following
connect() attempts.  Exercise 23.8 of the same book mentions that an
interesting exception are connect() calls to address 0.0.0.0, which
still return an EISCONN error, but also have the side-effect of
leaving the socket disassociated from a UDP pcb, allowing subsequent
connect() attempts to work.

Trying to reproduce the EISCONN error by running the attached program,
I couldn't.  It seems that connect() returns ECONNREFUSED when it is
run on already connected sockets.  If you run the program as it is
shown below, it works fine, connecting to localhost:53 and then
exiting.  If you undef the #if 0 ... #endif part, it should fail with
EISCONN, but it fails with ECONNREFUSED instead :-(

===== conn.c =====
#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <netdb.h>

#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <strings.h>
#include <unistd.h>

#define MY_PROTO	"udp"

int
main(void)
{
	struct sockaddr_in addr;
	struct protoent *pe;
	struct servent *se;
	int sd;

	/*
	 * Create a UDP socket.
	 */
	pe = getprotobyname(MY_PROTO);
	if (pe == NULL)
		errx(1, "getprotobyname(%s): unknown protocol", MY_PROTO);
	if ((sd = socket(PF_INET, SOCK_DGRAM, pe->p_proto)) == -1)
		err(1, "socket");

	/*
	 * When the ifdef'ed part below is uncommented, the error of the
	 * second connect() attempt is not EISCONN, but ECONNREFUSED, which
	 * is wrong.
	 */
#if 0
	/*
	 * First, connect to the UDP discard service of localhost and send at
	 * least one packet to it.
	 */
	printf("-!- Connecting to localhost:discard/%s\n", MY_PROTO);
	fflush(stdout);
	se = getservbyname("discard", MY_PROTO);
	if (se == NULL)
		errx(1, "getservbyname[discard/%s]: unknown service", MY_PROTO);

	bzero((char *)&addr, sizeof(struct sockaddr_in));
	addr.sin_family = PF_INET;
	addr.sin_addr.s_addr = htonl(0x7f000001); /* localhost */
	addr.sin_port = htons(se->s_port);

	if (connect(sd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
		err(1, "connect[%s/%s]", se->s_name, pe->p_name);

	printf("-!- Sending some stuff to localhost:%s/%s\n", se->s_name,
	    pe->p_name);
	fflush(stdout);
	if (write(sd, (char *)&addr, sizeof(addr)) == -1)
		err(1, "write/%s", se->s_name);
#endif

	/*
	 * Now attempt to connect to localhost:domain (DNS).
	 * This should fail on connect().
	 */
	printf("-!- Connecting to localhost:domain/%s\n", pe->p_name);
	fflush(stdout);
	se = getservbyname("domain", MY_PROTO);
	if (se == NULL)
		errx(1, "getservbyname[domain/%s]: unknown service",
		    pe->p_name);

	bzero((char *)&addr, sizeof(struct sockaddr_in));
	addr.sin_family = PF_INET;
	addr.sin_addr.s_addr = htonl(0x7f000001); /* localhost */
	addr.sin_port = htons(se->s_port);

	if (connect(sd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
		err(1, "connect[%s/%s]: error %d:", se->s_name, pe->p_name,
		    errno);

	close(sd);
	return (0);
}
===== end of conn.c =====

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




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