Description
I've encountered another issue in our server project: We need to set SO_REUSEPORT.
We already use endpoint:set_reuse_addr(true) with our TCP server (SOCK_STREAM), which partially helps. To solve the last issues we need to set SO_REUSEPORT.
The project uses the latest websocketpp 0.7.0 on Mac OS X.
As suggested I already uses the socket_init_handler ([http://stackoverflow.com/questions/23023317/proper-set-socket-init-handler-syntax-or-modify-source-to-turn-on-tcp-nodelay-wi/23031124#23031124] and [https://groups.google.com/forum/#!msg/websocketpp/rvBcIJ940Bc/zxpZf9AOb0IJ]).
I've also set the tcp_pre_init_handler.
The modified websocketpp-provided example "echo_server.cpp" shows the issue quite nicely; I've added the following lines:
`
void on_socket_init(websocketpp::connection_hdl hdl, boost::asio::ip::tcp::socket & s)
{
std::cerr << "on_socket_init...\n";
int reuse = 1;
int ihdl = s.lowest_layer().native_handle();
if (setsockopt(ihdl, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0)
perror(“setsockopt(SO_REUSEADDR) failed");
}
...
echo_server.set_socket_init_handler(bind(&on_socket_init, ::_1, ::_2));
//echo_server.set_tcp_pre_init_handler(bind(&on_tcp_init, ::_1));
...
std::cerr << "pre listen...\n";
echo_server.listen(9002);
std::cerr << "post listen...\n";
...
`
Starting a second instance of the server, it fails with
[info] asio listen error: system:48 (Address already in use) Underlying Transport Error
Unfortunately the handlers are called when the first client connects and therefore after endpoint.listen(), which actually creates the socket, sets SO_REUSEADDR and bind()s the socket.
Trying to set SO_REUSEPORT in the handler has no effect.
The output before a client has connected:
pre listen... post listen...
As soon as a client connects:
on_socket_init...
When adding tcp_pre_init_handler as well, I can observe it being called even after on_socket_init.
By modifying (as a test) the boost::asio code to also set SO_REUSEPORT for TCP/non-datagram oriented sockets, I can see that starting two (or more) instances of the server then is possible.
(How) is it possible to set SO_REUSEPORT before the bind() takes place?
If this is currently not possible, can you please add a callback / another handler (preferably already providing the socket like the init_socket_handler), which gets called in endpoint.listen() after
m_acceptor->open(ep.protocol(),bec);
and before
m_acceptor->bind(ep,bec);
Many thanks in advance!