Subject: Re: any way to let host act as TCP server OR client on same IP/port?

From: Chris Friesen <[email-masked]>
Date: Wed, 13 Jul 2011 13:16:09 -0600

On 07/13/2011 12:05 PM, Rick Jones wrote:
> On 07/13/2011 10:52 AM, Eric Dumazet wrote:
>> Le mercredi 13 juillet 2011 à 10:30 -0600, Chris Friesen a écrit :
>>> I've been asked an interesting question about TCP. We have some people
>>> that want to set up a TCP socket that can listen for connections on a
>>> given IP/port, but also initiate connections from that same IP/port.
>>> (Only one at a time, of course.)
>>>
>>> The TCP state machine seems to allow this (moving from LISTEN to
>>> SYN_SENT) but it's not a normal transition.
>>>
>>> Is there any way to do this using the socket API?
>>>
>>> I thought up a hack whereby we could use NFQUEUE to detect an incoming
>>> SYN and delay it while we call listen() on the socket. Is there any
>>> better way to do this?
>>
>> Could you try SO_REUSEADDR, on both listener and connect attempt ?
> 
> I was thinking the same thing, but it appears to not work under:

<snip>

> if (bind(listener,
> (struct sockaddr *)&me,
> sizeof(me)) < 0) {
> perror("bind listener");
> exit(-1);
> }
> 
> if (listen(listener,128) < 0) {
> perror("listen listener");
> exit(-1);
> }
> 
> /* connect something to it */
> if (connect(client,(struct sockaddr *)&me,sizeof(me)) < 0) {
> perror("connect client");
> exit(-1);

In our case we don't need to actually be connected, just be listening
and ready to either accept() a connection or connect() to someone else.

However, even after removing the connect() call I get:
"bind active: Address already in use"

The TCP state machine shows a single connection going from LISTEN to
SYN_SENT via a "send" operation in the application.  Presumably this
would logically map to a sendto/sendmsg but according to the man page
those don't support specifying addresses for connection-oriented
sockets.  I tried it anyways and got no errors but the following trace
shows that it's dying with SIGPIPE:

bind(3, {sa_family=AF_INET, sin_port=htons(23456), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
listen(3, 128)                          = 0
sendto(3, "\1", 1, 0, {sa_family=AF_INET, sin_port=htons(9), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EPIPE (Broken pipe)
--- {si_signo=SIGPIPE, si_code=SI_USER, si_pid=20609, si_uid=8382, si_value={int=2722689790, ptr=0x3ca248f2fe}} (Broken pipe) ---
+++ killed by SIGPIPE +++

Chris

-- 
Chris Friesen
Software Developer
GENBAND
[email-masked]
www.genband.com