* SO_REUSEADDR behavior different from BSD
@ 2004-08-04 14:25 Michael T Kerrisk
2004-08-05 14:14 ` bert hubert
0 siblings, 1 reply; 8+ messages in thread
From: Michael T Kerrisk @ 2004-08-04 14:25 UTC (permalink / raw)
To: netdev
Gidday,
In the classical BSD sockets implementation, the
SO_REUSEADDR socket option serves two purposes:
(a) to permit a socket to be bound to a port that currently
has a bound endpoint in the TIME_WAIT state, and
(b) to allow a terminated server to be restarted (and once
again be bound to it's well-known port), even if there
is a child of the previous server still serving a
connection.
On Linux SO_REUSEADDR does serve this purpose. However,
other second scenario is mot permitted by SO_REUSEADDR.
To make it clear what I mean, Ill detail the scenario.
Suppose we have the following:
Server (host Y)
Create listening socket -- fd 4
bind() to INADDR_ANY:9999
listen()
accept()
Client (host X)
Create socket
connect() to Y:9999 <accept unblocks, fd 5 returned>
server forks --------+
\ <child>
server terminates closes fd 4
<keeps running, with
fd 5 holding the
connection to client>
At this point, netstat on host Y shows the tuple
[local=Y-IP-addr:9999, remote=X-IP-addr:ephem-port] ESTABLISHED
New Server started
Create listening socket -- fd 4
set SO_REUSEADDR to 1 for fd 4
bind() fd 4 to port INADDR_ANY:9999
WHAT HAPPENS?
On FreeBSD, the bind() succeeds, and then using "netstat an"
on host Y shows:
[local=Y-IP-addr:9999, remote=X-IP-addr:ephem-port] ESTABLISHED
and
[local=*:9999, remote=*.*] CLOSED
But on Linux (2.6), the bind() fails with EADDRINUSE.
Why does Linux behave differently in this scenario?
Cheers,
Michael
--
Michael Kerrisk
mtk-lists@gmx.net
NEU: WLAN-Router für 0,- EUR* - auch für DSL-Wechsler!
GMX DSL = supergünstig & kabellos http://www.gmx.net/de/go/dsl
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: SO_REUSEADDR behavior different from BSD
2004-08-04 14:25 SO_REUSEADDR behavior different from BSD Michael T Kerrisk
@ 2004-08-05 14:14 ` bert hubert
2004-08-05 16:36 ` Michael T Kerrisk
0 siblings, 1 reply; 8+ messages in thread
From: bert hubert @ 2004-08-05 14:14 UTC (permalink / raw)
To: Michael T Kerrisk; +Cc: netdev
On Wed, Aug 04, 2004 at 04:25:27PM +0200, Michael T Kerrisk wrote:
> But on Linux (2.6), the bind() fails with EADDRINUSE.
This scenario has previously worked for me. Can you show the exact source
which exhibits this problem?
--
http://www.PowerDNS.com Open source, database driven DNS Software
http://lartc.org Linux Advanced Routing & Traffic Control HOWTO
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: SO_REUSEADDR behavior different from BSD
2004-08-05 14:14 ` bert hubert
@ 2004-08-05 16:36 ` Michael T Kerrisk
2004-08-05 18:20 ` David Stevens
2004-08-05 18:34 ` YOSHIFUJI Hideaki / 吉藤英明
0 siblings, 2 replies; 8+ messages in thread
From: Michael T Kerrisk @ 2004-08-05 16:36 UTC (permalink / raw)
To: bert hubert; +Cc: netdev
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="us-ascii", Size: 7086 bytes --]
> On Wed, Aug 04, 2004 at 04:25:27PM +0200, Michael T Kerrisk wrote:
>
> > But on Linux (2.6), the bind() fails with EADDRINUSE.
>
> This scenario has previously worked for me. Can you show the exact source
> which exhibits this problem?
Okay, sorry for the delay. I had to hack together a simpler
program to demonstrate this. I've attached the program below
(it is both server and client, depending on command line options).
Do note that in my original description, on the first time through,
the server did NOT use SO_REUSEADDR.
In other words, using my program, we do the following:
SERVER HOST CLIENT HOST
./reuseaddr_test -s -n
(The above does NOT use
SO_REUSEADDR)
./reuseaddr_test -c <server-host>
(At this point the server parent exists, but the server
client and child are connected)
./reuseaddr_test -s
(The above DOES use
SO_REUSEADDR)
Now, on Linux, at this point, the second instance of the
server fails with EADDRINUSE, even though it did use
SO_REUSEADDR. On FreeBSD 5.1, the second server instance
does successfully bind.
On Linux, if the *first* instance also used SO_REUSEADDR,
then the second instance can bind. FreeBSD does not require
this.
I realise that the scenario that delivers EADDRINUSE
above is slightly unusual, because normally a server always
specifies SO_REUSEADDR, but my question is why the scenario
I'm describing does differ from FreeBSD, which I'm assuming
conforms to the canonical BSD behaviour.
Cheers,
Michael
==
/* reuseaddr_test.c
Michael Kerrisk, Aug 2004
IPv4 for simplicity...
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#define DEF_PORT "55555"
#define DEF_SLEEP_TIME 60
#define errMsg(msg) { perror(msg); }
#define errExit(msg) { perror(msg); exit(EXIT_FAILURE); }
#define fatalErr(msg) { fprintf(stderr, "%s\n", msg); \
exit(EXIT_FAILURE); }
static void
usageError(char *progName, char *msg)
{
if (msg != NULL)
printf("%s", msg);
fprintf(stderr, "Usage: %s [options] -s \n"
" or: %s [options] -c host\n",
progName, progName);
fprintf(stderr, "Options are:\n");
fprintf(stderr, "\t-c host Run as client, connecting to 'host'\n");
fprintf(stderr, "\t-s Run as server\n");
fprintf(stderr, "\t-p port Use given 'port' number (def=%s)\n",
DEF_PORT);
fprintf(stderr, "\t-n *Don't* use SO_REUSEADDR in server\n");
fprintf(stderr, "\t-w nsecs Child sleep interval (def=%d)\n",
DEF_SLEEP_TIME);
exit(EXIT_FAILURE);
} /* usageError */
/* Return Internet address as string: "(host, port#)" */
static char *
inet4AddressString(const struct sockaddr_in *addr)
{
static char buf[1024];
struct hostent *hent;
char *host;
hent = gethostbyaddr((char *) &addr->sin_addr,
sizeof(addr->sin_addr), addr->sin_family);
/* Return host name, or dotted address if not found */
host = (hent != NULL) ? hent->h_name : inet_ntoa(addr->sin_addr);
snprintf(buf, sizeof(buf), "(%s, %u)", host, ntohs(addr->sin_port));
return buf;
} /* inet4AddressString */
int
main(int argc, char *argv[])
{
int opt, sfd, cfd;
int client, server, reuse;
char *pstr = DEF_PORT;
char *host;
struct sockaddr_in svaddr, claddr;
struct hostent *h;
struct in_addr **addrpp;
char buf[1];
socklen_t s;
int optval;
int stime;
#define CMD_SIZE 1024
char cmd[CMD_SIZE];
server = 0;
client = 0;
reuse = 1;
stime = DEF_SLEEP_TIME;
while ((opt = getopt(argc, argv, "c:sp:nw:")) != -1) {
switch (opt) {
case 'c':
client = 1;
host = optarg;
break;
case 's':
server = 1;
break;
case 'p':
pstr = optarg;
break;
case 'w':
stime = atoi(optarg);
break;
case 'n':
reuse = 0;
break;
default:
usageError(argv[0], NULL);
break;
} /* switch */
} /* while */
if ((server && client) || (!server && !client))
usageError(argv[0], NULL);
sfd = socket(AF_INET, SOCK_STREAM, 0);
if (sfd == -1) errExit("socket");
memset(&svaddr, 0, sizeof(struct sockaddr_in));
svaddr.sin_family = AF_INET;
svaddr.sin_port = htons(atoi(pstr));
if (server) {
svaddr.sin_addr.s_addr = htonl(INADDR_ANY);
} else { /* client */
h = gethostbyname(host);
if (h == NULL)
fatalErr("host lookup failed (gethostbyname())");
addrpp = (struct in_addr **) h->h_addr_list;
svaddr.sin_addr.s_addr = (*addrpp)->s_addr;
}
if (server) {
if (reuse) {
optval = 1;
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof(optval)) == -1) errExit("setsockopt");
}
if (bind(sfd, (struct sockaddr *) &svaddr,
sizeof(struct sockaddr_in)) == -1) errExit("bind");
if (listen(sfd, 5) == -1) errExit("listen");
printf("Server listen() completed; about to accept()\n");
s = sizeof(struct sockaddr_in);
cfd = accept(sfd, (struct sockaddr *) &claddr, &s);
if (cfd == -1) errExit("accept");
printf("Server received connection from: %s\n",
inet4AddressString(&claddr));
snprintf(cmd, CMD_SIZE, "netstat -an | grep %s", pstr);
printf("cmd: %s\n", cmd);
//system(cmd);
switch(fork()) {
case -1:
errExit("fork");
case 0:
close(sfd); /* Close listening socket */
sleep(2); /* Give parent a moment to exit */
printf("Server child started\n");
system(cmd);
printf("Server child about to sleep %d seconds\n", stime);
sleep(stime);
printf("Server child exiting\n");
exit(EXIT_FAILURE);
default:
printf("Server parent exiting\n");
exit(EXIT_FAILURE);
}
} else { /* client */
if (connect(sfd, (struct sockaddr *) &svaddr,
sizeof(struct sockaddr_in)) == -1)
errExit("connect");
printf("Client connected, now about to read\n");
read(sfd, buf, 1);
printf("Client exiting\n");
}
exit(EXIT_SUCCESS);
} /* main */
--
Michael Kerrisk
mtk-lists@gmx.net
NEU: WLAN-Router für 0,- EUR* - auch für DSL-Wechsler!
GMX DSL = supergünstig & kabellos http://www.gmx.net/de/go/dsl
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: SO_REUSEADDR behavior different from BSD
2004-08-05 16:36 ` Michael T Kerrisk
@ 2004-08-05 18:20 ` David Stevens
2004-08-05 18:34 ` YOSHIFUJI Hideaki / 吉藤英明
1 sibling, 0 replies; 8+ messages in thread
From: David Stevens @ 2004-08-05 18:20 UTC (permalink / raw)
To: Michael T Kerrisk; +Cc: bert hubert, netdev
Michael,
Linux does not have SO_REUSEPORT, which post-Net/3
BSD systems do. I believe SO_REUSEADDR on Linux behaves
the same as 4.3BSD, but will differ with 4.4BSD and later because
of the addition of SO_REUSEPORT (unless there's a bug :-)).
+-DLS
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: SO_REUSEADDR behavior different from BSD
2004-08-05 16:36 ` Michael T Kerrisk
2004-08-05 18:20 ` David Stevens
@ 2004-08-05 18:34 ` YOSHIFUJI Hideaki / 吉藤英明
2004-08-08 2:25 ` Fernando Gont
1 sibling, 1 reply; 8+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2004-08-05 18:34 UTC (permalink / raw)
To: mtk-lists; +Cc: ahu, netdev
In article <19686.1091723777@www48.gmx.net> (at Thu, 5 Aug 2004 18:36:17 +0200 (MEST)), "Michael T Kerrisk" <mtk-lists@gmx.net> says:
> Now, on Linux, at this point, the second instance of the
> server fails with EADDRINUSE, even though it did use
> SO_REUSEADDR. On FreeBSD 5.1, the second server instance
> does successfully bind.
This behavior is intended.
First socket is REQUIRED to set SO_REUSEADDR
I hate BSD's behavior because it is asynmetry.
(Both sockets are required to agree on "REUSEADDR.")
--
Hideaki YOSHIFUJI @ USAGI Project <yoshfuji@linux-ipv6.org>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: SO_REUSEADDR behavior different from BSD
@ 2004-08-05 22:25 Michael T Kerrisk
0 siblings, 0 replies; 8+ messages in thread
From: Michael T Kerrisk @ 2004-08-05 22:25 UTC (permalink / raw)
To: YOSHIFUJI.Hideaki/; +Cc: ahu, netdev, David Stevens
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="us-ascii", Size: 911 bytes --]
> In article <19686.1091723777@www48.gmx.net> (at Thu, 5 Aug 2004 18:36:17
> +0200 (MEST)), "Michael T Kerrisk" <mtk-lists@gmx.net> says:
>
> > Now, on Linux, at this point, the second instance of the
> > server fails with EADDRINUSE, even though it did use
> > SO_REUSEADDR. On FreeBSD 5.1, the second server instance
> > does successfully bind.
>
> This behavior is intended.
> First socket is REQUIRED to set SO_REUSEADDR
> I hate BSD's behavior because it is asynmetry.
> (Both sockets are required to agree on "REUSEADDR.")
Hideaki, David,
Thank you for the information / confirmation that this is intended
behavior. I'll try to see that something on this point makes it
into the man pages.
Cheers,
Michael
--
Michael Kerrisk
mtk-lists@gmx.net
NEU: WLAN-Router für 0,- EUR* - auch für DSL-Wechsler!
GMX DSL = supergünstig & kabellos http://www.gmx.net/de/go/dsl
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: SO_REUSEADDR behavior different from BSD
2004-08-05 18:34 ` YOSHIFUJI Hideaki / 吉藤英明
@ 2004-08-08 2:25 ` Fernando Gont
2004-08-09 13:29 ` Michael T Kerrisk
0 siblings, 1 reply; 8+ messages in thread
From: Fernando Gont @ 2004-08-08 2:25 UTC (permalink / raw)
To: YOSHIFUJI Hideaki / 吉藤英明, mtk-lists
Cc: ahu, netdev
At 11:34 05/08/2004 -0700, YOSHIFUJI Hideaki wrote:
> > Now, on Linux, at this point, the second instance of the
> > server fails with EADDRINUSE, even though it did use
> > SO_REUSEADDR. On FreeBSD 5.1, the second server instance
> > does successfully bind.
>
>This behavior is intended.
>First socket is REQUIRED to set SO_REUSEADDR
>I hate BSD's behavior because it is asynmetry.
>(Both sockets are required to agree on "REUSEADDR.")
Not sure what you mean by "asymetry".
--
Fernando Gont
e-mail: fernando@gont.com.ar || fgont@acm.org
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: SO_REUSEADDR behavior different from BSD
2004-08-08 2:25 ` Fernando Gont
@ 2004-08-09 13:29 ` Michael T Kerrisk
0 siblings, 0 replies; 8+ messages in thread
From: Michael T Kerrisk @ 2004-08-09 13:29 UTC (permalink / raw)
To: Fernando Gont; +Cc: netdev
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="us-ascii", Size: 999 bytes --]
> At 11:34 05/08/2004 -0700, YOSHIFUJI Hideaki wrote:
>
> > > Now, on Linux, at this point, the second instance of the
> > > server fails with EADDRINUSE, even though it did use
> > > SO_REUSEADDR. On FreeBSD 5.1, the second server instance
> > > does successfully bind.
> >
> >This behavior is intended.
> >First socket is REQUIRED to set SO_REUSEADDR
> >I hate BSD's behavior because it is asynmetry.
> >(Both sockets are required to agree on "REUSEADDR.")
>
> Not sure what you mean by "asymetry".
Ferando,
By asymmetry, I understand Hideaki to mean that BSD requires
SO_REUSEADDR in the second server bind(), but not the first.
the Linux philosophy then appears to be symmetry: both server
instances must agree that the socket port is reusable (i.e.,
both must set SO_REUSEADDR).
Cheers,
Michael
--
Michael Kerrisk
mtk-lists@gmx.net
NEU: WLAN-Router für 0,- EUR* - auch für DSL-Wechsler!
GMX DSL = supergünstig & kabellos http://www.gmx.net/de/go/dsl
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2004-08-09 13:29 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-08-04 14:25 SO_REUSEADDR behavior different from BSD Michael T Kerrisk
2004-08-05 14:14 ` bert hubert
2004-08-05 16:36 ` Michael T Kerrisk
2004-08-05 18:20 ` David Stevens
2004-08-05 18:34 ` YOSHIFUJI Hideaki / 吉藤英明
2004-08-08 2:25 ` Fernando Gont
2004-08-09 13:29 ` Michael T Kerrisk
-- strict thread matches above, loose matches on Subject: below --
2004-08-05 22:25 Michael T Kerrisk
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).