views:

58

answers:

3

In ASIO, s it possible to create another socket that has the same source port as another socket?

My UDP server application is calling receive_from using port 3000. It passes the packet off to a worker thread which will send the response (currently using a dynamic source port).

The socket in the other thread is created like this:

udp::socket sock2(io_service, udp::endpoint(udp::v4(), 0));

And responds to the original request using the sender_endpoint saved with the original packet.

What I'd like to be able to do is respond to the client using the same source port as the server is listening on. But I can't see how that can be done. I get an exception if I try that saying address in use. Is it possible to do what I'm asking? The reason I want that is if I use dynamic ports, it means the clients need to add special firewall rules in windows to allow the reply packets to be read. I've found that if the source port is the same in the reply, windows firewall will allow it to pass back in.

+2  A: 

The exception tells you as it is: you can't create two live sockets with the same source port. I don't know ASIO, but you should be able to create the socket before spinning off the thread, keeping reference to the socket and the thread for later use, and once the data sending thread is idle, joining back to it and sending any other stuff.

EDIT: with a little bit of effort, you can also make a socket for which you don't have to wait until the entire data from one thread has been sent: have a worker thread owning the socket listen on a queue for chunks of data (ideally exactly the size of the payload you intend to send) and send arbitrary chunks of payload to this queue, from multiple threads.

knitti
I think this is a big limitation of BSD sockets. It's a pity that you can't do this. I makes sense to me to be able create two sockets with the same source port, but have only one of them in the listen state. That would allow the send_to to work for UDP. Looks like I'll have to live with this limitation.
Matt H
You can do this, as long as the socket is reused within the same process. You just don't have to recreate the *same* device over and over again. And the limitation to the same process is a good thing, IMHO
knitti
That raises an interesting question. Are sockets thread safe? i.e. if I call send_to in one thread and then from another thread using the same socket calling send_to, would that cause issues?
Matt H
@knitti, if that were true then I wouldn't be getting the exception!
Matt H
no, you don't reuse it. You recreate it.
knitti
I'm wanting multiple sockets with identical source ports. There will be around 7 of them and they will only send + one other socket on the same port which will only ever receive. It seems that this is just not possible.
Matt H
Yes, they are thread safe. Sending data to the socket should block until it is out.
knitti
You should think about your software architecture, it should be possible to achieve what you want.
knitti
It's possible to even have them in multiple processes, if the second process inherited the bound socket through `fork()`, or was passed it using a `SCM_RIGHTS` message over a UNIX domain socket.
caf
A: 

send reply to the same socket (that you received client's request on) instead of creating new one but make sure you don't send to the same socket from both threads simultaneously

Andrew Tylychko
Thanks. Seems like this is the only way it can be done. But because of the nature of my app and the load that will be on it, I'll keep the independent sockets with the different port numbers.
Matt H
A: 

You should be able to use the SO_REUSEADDR socket option to bind multiple sockets to the same address. But having said that, you don't want to do this because it's not specified which socket will receive incoming data on that port (you would have to check all sockets for incoming data)

The better option is just to use the same socket to send replies - this can safely be done from multiple threads without any additional synchronisation (as you are using UDP).

cmeerw
No, thats not what that option is for. See: http://www.unixguide.net/network/socketfaq/4.5.shtml
Matt H
So have you tried it (on Linux with UDP sockets)? You might be in for a surprise...
cmeerw
Actually, you're right. I was doing this incorrectly because I was initialising boost incorrectly. It does work, but as you've pointed out, it will cause problems and did.
Matt H