libsocket icon indicating copy to clipboard operation
libsocket copied to clipboard

Calling setsockopts on unconnected socket

Open thirtythreeforty opened this issue 11 years ago • 7 comments

As far as I can tell, it isn't possible to set options on a socket without first getting it into the connected state. It would be useful to do this, for example, to set the socket option SO_REUSEADDR before connecting. The problem is that the socket isn't actually created until connection time.

Using setsockopt with inet_stream::getfd works fine after connecting, because the socket file descriptor is then valid.

Am I missing something, or is this not possible?

thirtythreeforty avatar Apr 23 '14 00:04 thirtythreeforty

It's hardly possible for both the C and the C++ part because TCP client sockets are created and immediately connected after that in create_inet_stream_socket in C/inet/libinetsocket.c (actual socket()/connect() in lines 185+). From the viewpoint of libsocket++, it's an atomic operation.

The only possibility I see at the moment is introducing some more parameters in create_inet_stream_socket which are passed to a setsockopt call. Or, if you want to especially set the SO_REUSEADDR flag, a boolean (in C: int) flag.

dermesser avatar Apr 23 '14 13:04 dermesser

I follow. Shouldn't the socket be created when the object is created (RAII) and then only connected when you call connect()? (The constructor could of course call connect() too if appropriate.)

I think the more-parameter option is a decent one, but how would you set multiple options in a scalable way? The only possibility I see is accepting a std::vector of parameter:value pairs but that doesn't seem very clean in C.

thirtythreeforty avatar Apr 23 '14 14:04 thirtythreeforty

It may at first seem as a better alternative to do it the RAII way you mentioned.

But there comes a load of problems with it, the (in my opinion) most important one being the choice of the address family. Usually I would use LIBSOCKET_BOTH to let getaddrinfo() choose what address family to use. In that case, I have to create the socket after calling getaddrinfo(), which is done in create_inet_stream_socket(). But if I want to create the socket first and then connect it, I already have to know the address family. I may do that, libinetsocket has a function for it, but it's still not desirable (I believe).

Using an additional parameter int sockopts may work best in that situation. It would be passed to create_inet_stream_socket and inet_stream::inet_stream() (and connect() and so on) and take the values defined in <sys/socket.h>.

dermesser avatar Apr 23 '14 15:04 dermesser

Gotcha. That makes sense.

If you are going to pass sockopts, how would you pass multiple options? For example, if I want to set the two options SO_REUSEADDR and SO_REUSEPORT, I can't just bitwise-or them together for a single call... They're defined as 2 and 15.

thirtythreeforty avatar Apr 23 '14 15:04 thirtythreeforty

Hm... Didn't think of that...

What about implementing LIBSOCKET_... wrappers that may get bitwise ORed, for example: LIBSOCKET_REUSEADDR == 1, LIBSOCKET_REUSEPORT == 2, LIBSOCKET_DONTROUTE == 4 etc. And then converting them back to the SO_... constants.

dermesser avatar Apr 23 '14 19:04 dermesser

That would work. There would be a lot of if statements, but welcome to C :laughing:. Adding an argument is going to break the interface for existing programs, as C doesn't overload. C++ should be fine though.

Also, oops, I didn't mean to close this.

thirtythreeforty avatar Apr 23 '14 19:04 thirtythreeforty

cf. https://github.com/dermesser/libsocket/blob/master/C/inet/libinetsocket.c#L572 Maybe a little more compact, and we're fine :+1:

dermesser avatar Apr 23 '14 20:04 dermesser