Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

WSAEADDRINUSE on an ephemeral port #

4 views
Skip to first unread message

Jeffery Griffith

unread,
Apr 22, 2002, 12:42:39 PM4/22/02
to
hi,

just curious if anyone has experienced this problem before. i haven't
found any references to it on MSDN though a cygwin developer at
http://www.cygwin.com/ml/cygwin-developers/2001-11/msg00080.html wrote
a nice description and application to reproduce it. anyone have any
background on this? essentially a connect() fails with address-in-use
as the reason even though bind was never called for a specific port#
on the client side. sure enough, netstat shows that ephemeral port #
in a TIME_WAIT state from a previous connection indicating that
perhaps winsock attempts to assign an ephemeral port that is
technically still in use. any pointers to where/whether this is a
documented bug would be greatly appreciated.

thanks,
Jeff

Phil Frisbie, Jr.

unread,
Apr 22, 2002, 2:55:14 PM4/22/02
to
That original 'bug' turned out to be the programmer's error in not closing the
sockets properly.

Post a small code sample that shows your problem so we can duplicate it.


Phil Frisbie, Jr.
Hawk Software
http://www.hawksoft.com

Jeffery Griffith

unread,
Apr 22, 2002, 6:56:26 PM4/22/02
to
as i read the follow up post, the socket closing only explained the
ENOBUFS error. his rewritten version (included inline below) seems to
reproduce the problem nicely without those distractions. if you can
spot a problem with this code, then hopefully it'll be the same
problem that i have!

thanks again,
--jg

/*

This program illustrates a bug in the Windows winsock layer. This
bug manifests itself both on Windows NT 4.0 and Windows 2000. The
bug is that the winsock layer is apparently willing to assign a
local port number to a socket which is actually already in use, such
that when the program later to connect() the socket to a remote
port, the connection fails with WSAEADDRINUSE.

When you run the program, it will keep creating and closing socket
connections over and over again. It will report errors when a
connection fails because of an EADDRINUSE error.

*/

/*

With Visual Studio, compile this program as "cl doecho.c
ws2_32.lib".

With Cygwin, compile this program with "gcc -mno-cygwin -mwindows
doecho.c -lws2_32" if you want a native Windows version or "gcc
doecho.c -lws32_32" for a Cygwin version. Both the native Windows
and Cygwin versions illustrate the bug.

With Linux, compile the program with "gcc doecho.c". You can then
run it essentially forever and it will never print any errors, thus
illustrating that there is a bug in winsock that isn't in Linux.

*/

/*

Run the program with two arguments -- an IP address in dotted quad
notation, and a port number.

Separately from this program, you need to run a listener on the
specified address and port. All the listener should do is accept
and close connections. Something like the following Perl script
should do. Note that the listener can *not* be running on Windows
-- that seems to interfere with the manifestation of the bug. The
listener should be running on a Unix machine of some sort (I used
Linux).

use Socket;

($port = shift) || die;

socket(ACCEPTOR, AF_INET, SOCK_STREAM, 0) || die;

$iaddr = INADDR_ANY;
$sockaddr = sockaddr_in($port, $iaddr);

setsockopt(ACCEPTOR, SOL_SOCKET, SO_REUSEADDR, pack("l", 1));

bind(ACCEPTOR, $sockaddr) || die;
listen(ACCEPTOR, SOMAXCONN) || die;

while (accept(CLIENT, ACCEPTOR)) {
close(CLIENT);
}

*/

#ifndef WIN32
#ifdef _MSC_VER
#define WIN32
#endif
#endif

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#ifdef WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#endif

#ifndef WIN32
#define wsaperror perror
#else
void wsaperror(char *);
#endif

main(int argc, char *argv[])
{
#ifdef WIN32
WSADATA wsaData;
#endif
int succeeded = 0;
struct sockaddr_in addr = {0};
int ret;
char *endptr = NULL;

if (argc != 3) {
fprintf(stderr, "Must specify IP address and port arguments\n");
exit(1);
}

addr.sin_family = AF_INET;

if ((addr.sin_addr.s_addr = inet_addr(argv[1])) == INADDR_NONE) {
fprintf(stderr, "First argument must be IP address\n");
exit(1);
}

addr.sin_port = strtol(argv[2], &endptr, 10);
if (! (*argv[2] && endptr && ! *endptr)) {
fprintf(stderr, "Second argument must be port number\n");
exit(1);
}
addr.sin_port = htons(addr.sin_port);

#ifdef WIN32
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
wsaperror("WSAStartup");
exit(1);
}
#endif

while (1) {
int s;
struct sockaddr_in local_addr = {0};
#ifdef WIN32
int name_len = sizeof(local_addr);
#else
socklen_t name_len = sizeof(local_addr);
#endif

if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
wsaperror("socket");
break;
}

ret = connect(s, (struct sockaddr *) &addr, sizeof(addr));

if (getsockname(s, (struct sockaddr *) &local_addr, &name_len) <
0)
wsaperror("getsockname");
else if (ret < 0)
fprintf(stderr, "Local port failed: %d\n",
ntohs(local_addr.sin_port));

if (ret < 0) {
wsaperror("connect");
#ifdef WIN32
closesocket(s);
#else
close(s);
#endif
continue;
}

if (send(s, "foo\n", 4, 0) < 0) {
wsaperror("send");
break;
}

#ifdef WIN32
closesocket(s);
#else
close(s);
#endif

fprintf(stderr, "%d\n", ntohs(local_addr.sin_port));
fflush(stdout);
}

#ifdef WIN32
WSACleanup();
#endif
exit(1);
}

#ifdef WIN32
void wsaperror(char *str)
{
int err = WSAGetLastError();
char *errstr;

switch (err) {
case WSAEADDRINUSE:
errstr = "WSAEADDRINUSE";
break;
case WSAENOBUFS:
errstr = "WSAENOBUFS";
break;
default:
errstr = "Unknown error";
break;
}

fprintf(stderr, "%s: Error %d (%s)\n", str, err, errstr);
}
#endif

"Phil Frisbie, Jr." <ph...@hawksoft.com> wrote in message news:<3CC45C02...@hawksoft.com>...

Phil Frisbie, Jr.

unread,
Apr 23, 2002, 12:33:13 PM4/23/02
to
Jeffery Griffith wrote:
>
> as i read the follow up post, the socket closing only explained the
> ENOBUFS error. his rewritten version (included inline below) seems to
> reproduce the problem nicely without those distractions. if you can
> spot a problem with this code, then hopefully it'll be the same
> problem that i have!

Ok, I now fully understand the problem. This is the old "Windows only assigns
local ports 1024 through 5000" problem. On a normal server, even one that
supports hundreds on connections a second, it will not show up because the
clients are connecting from different addresses and/or ports. And a client would
NEVER do what you are doing unless it was trying to load test a single server.

I also ran into this problem in my network library, HawkNL, when I wrote a
sample application to see how many UDP sockets could be opened at once. On
Windows NT my app would choke and Windows would come to a crawl as soon as you
tried to open more than about 3976 sockets. I ended up writing my own bind()
function wrapper to choose free port numbers.

> thanks again,
> --jg

Jeffery Griffith

unread,
Apr 25, 2002, 7:03:47 PM4/25/02
to
"Phil Frisbie, Jr." <ph...@hawksoft.com> wrote in message news:<3CC58C39...@hawksoft.com>...

>
> Ok, I now fully understand the problem. This is the old "Windows only assigns
> local ports 1024 through 5000" problem. On a normal server, even one that
> supports hundreds on connections a second, it will not show up because the
> clients are connecting from different addresses and/or ports. And a client
> would NEVER do what you are doing unless it was trying to load test a
> single server.

yep, that't the problem exactly, though i still don't really
understand why it would choose to assign an ephemeral port # that is
in a TIME_WAIT state regardless of how many it has to choose from.
i've seen reports of this several years back so i'm surprised it
hasn't been addressed IF it's truly a winsock bug. regarding a real
client NEVER doing this, that may be true at the end of the chain but
consider your server/listener as a client itself in a distributed
system and it can easily happen, e.g. in my case i listen for RTSP
connections on port 554 and in turn connect via TCP to other elements
of the system and my server becomes a client with a problem.

>
> I also ran into this problem in my network library, HawkNL, when I wrote a
> sample application to see how many UDP sockets could be opened at once. On
> Windows NT my app would choke and Windows would come to a crawl as soon as you
> tried to open more than about 3976 sockets. I ended up writing my own bind()
> function wrapper to choose free port numbers.
>

thanks for the ideas!

--jg

0 new messages