No exception when the server port is already in use on Windows
Hello,
It's strange but I can start the server on a port which is already used and no exception is thrown.
I'm using boost 1.59
Regards
Ok, it's seems that it's the normal behaviour.. it's lazy.. powerful but a bit problematic in my case
I get terminating with uncaught exception of type boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::system::system_error> >: bind: Address already in use, but what OS are you running the server on?
I'm working on Windows 8.1 and toolset v120_xp (Visual Studio 2013), boost 1.59
I start a node server on the same port that SimpleWebServer. Sometimes it's the node server which catch the packets, and sometimes it's the SimpleWebServer. Maybe it's something like port sharing?! I'm not an expert for the sockets TCP.
I know there are some problems with exceptions on Windows, had the problems related to another project I'm working on (https://github.com/cppit/jucipp), but I have not had time to dive into it yet. Would appreciate any helpful links or pull requests towards fixing any Windows exception issues.
~~I must do that on Windows in order to have the exception:~~
diff --git a/server_http.hpp b/server_http.hpp
index 569a618..6917773 100644
--- a/server_http.hpp
+++ b/server_http.hpp
@@ -333,6 +333,7 @@ namespace SimpleWeb {
//Create new socket for this connection
//Shared_ptr is used to pass temporary objects to the asynchronous functions
std::shared_ptr<HTTP> socket(new HTTP(io_service));
+ socket->set_option(boost::asio::socket_base::reuse_address(false));
acceptor.async_accept(*socket, [this, socket](const boost::system::error_code& ec){
//Immediately start accepting a new connection
Sorry it's wrong :-( it fails every time...
resources:
- http://stackoverflow.com/questions/5002761/boostasio-server-detect-failure-to-listen-to-server-port
- http://itamarst.org/writings/win32sockets.html
Try add the following inside the ServerBase constructor (https://github.com/eidheim/Simple-Web-Server/blob/master/server_http.hpp#L156):
boost::asio::ip::tcp::acceptor::reuse_address option(false);
acceptor.set_option(option);
I've tried and it changes nothing. :-(
See if you can make sense of http://stackoverflow.com/questions/14388706/socket-options-so-reuseaddr-and-so-reuseport-how-do-they-differ-do-they-mean-t/14388707#14388707. If your node server and the Simple-Web-Server uses exactly the same ip:port combination you should get an exception no matter if reuse_address is true or false.
You can use boost::asio::ip::address::from_string("10.0.0.2") for instance to set a specific address instead of using boost::asio::ip::tcp::v4() at https://github.com/eidheim/Simple-Web-Server/blob/master/server_http.hpp#L155.
Try set the same address on both the node server and Simple-Web-Server.
I will, by the way, add another constructor most likely, that has the address as first parameter. So that this becomes simpler, and one can run this server on multiple networking cards.
I'll commit a solution for the things discussed above Tomorrow, using a Server::options class that one can set before running Server::start. One of the options will be reuse_address that will be set correctly.
Hello,
Thanks for all
Then yes, when I set the same address on node and on server_http then an exception is thrown. If node is binding on 0.0.0.0 then the exception is never thrown even is reuse_addr is set explicitly to false.
I even tested with something like (without success)
typedef boost::asio::detail::socket_option::boolean<BOOST_ASIO_OS_DEF(SOL_SOCKET), SO_EXCLUSIVEADDRUSE> excluse_address;
acceptor.set_option(excluse_address(true));
But I'm not able to have a case where it fails everytime.
Did you try the latest commit? Boost::Asio is very picky on where you set the options.
Ok I've a case where it works as expected..
If server_http binds on 0.0.0.0, reuse_address is false and excluse_address is true, the exception is always thrown (tested with node on 0.0.0.0 and 127.0.0.1).
I can live with that but for me it's a security problem because I want to bind server_http only on 127.0.0.1 with the same behaviour.
Yes I've tried with the latest version
The working case:
this->server->config.address = "0.0.0.0";
this->server->config.reuse_address = false;
(only valid with Windows)
diff --git a/server_http.hpp b/server_http.hpp
index afb36c0..8d3cc48 100644
--- a/server_http.hpp
+++ b/server_http.hpp
@@ -141,6 +141,10 @@ namespace SimpleWeb {
endpoint=std::unique_ptr<boost::asio::ip::tcp::endpoint>(new boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), config.port));
acceptor.open(endpoint->protocol());
acceptor.set_option(boost::asio::socket_base::reuse_address(config.reuse_address));
+
+ typedef boost::asio::detail::socket_option::boolean<BOOST_ASIO_OS_DEF(SOL_SOCKET), SO_EXCLUSIVEADDRUSE> excluse_address;
+ acceptor.set_option(excluse_address(true));
+
acceptor.bind(*endpoint);
acceptor.listen();
I will have to read up on this some more, but as I understand it now: On Windows, if Server::config.reuse_address == false, also set the SO_EXCLUSIVEADDRUSE socket option?
The exception is always thrown (with my tests) if:
- Server::config.reuse_address == false
- SO_EXCLUSIVEADDRUSE == true
- Server::config.address = "0.0.0.0"
- The other server (node for example) binds on 0.0.0.0 or 127.0.0.1
The SO_EXCLUSIVEADDRUSE flag smells just like a hack
#define SO_EXCLUSIVEADDRUSE ((int)(~SO_REUSEADDR)) /* disallow local address reuse */
Then I've tried with:
int optval = 1;
auto native_socket = acceptor.native_handle();
if (::setsockopt(native_socket,
SOL_SOCKET,
SO_EXCLUSIVEADDRUSE,
reinterpret_cast<const char *>(&optval), sizeof(optval)) != 0)
{ /* error management */
}
But the bind() is still possible when my node server is already listening on the same port.
I don't understand and I've no idea how to fix it.
From what I can understand from http://stackoverflow.com/questions/14388706/socket-options-so-reuseaddr-and-so-reuseport-how-do-they-differ-do-they-mean-t/14388707#14388707: "Microsoft realized that this might be a problem and thus added another socket option SO_EXCLUSIVEADDRUSE", you need to set SO_EXCLUSIVEADDRUSE on the node server. Is that possible?
I've tested with only two node servers, the first one uses the wildcard and the second one the loopback IP (both the same port).
Both server can be started (without exception) and it's not always the same server that catch the paquets. Then the problem is global... I'm not sure that I can do something around this problem.
I was maybe a bit unclear in my previous post, from http://stackoverflow.com/questions/14388706/socket-options-so-reuseaddr-and-so-reuseport-how-do-they-differ-do-they-mean-t/14388707#14388707 (scroll down to Windows): "Setting SO_EXCLUSIVEADDRUSE on a socket makes sure that if the binding succeeds, the combination of source address and port is owned exclusively by this socket and no other socket can bind to them, not even if it has SO_REUSEADDR set.". So if you set SO_EXCLUSIVEADDRUSE on an application (the main application which is running node), then no other application can bind to the same address(any combination):port.
For instance if you set SO_EXCLUSIVEADDRUSE on Simple-Web-Server, then no other application, Simple-Web-Server or any node application, can bind to this address:port. The challenge, though, is to set SO_EXCLUSIVEADDRUSE on the node application.
This is at least my understanding of the problem. If possible though, I would use Debian stable as server OS, but that is a personal preference, and maybe not possible in your case.
I think that as a security measure, and to make sure any networking server performs as in a posix environment, SO_EXCLUSIVEADDRUSE should always be turned on in Windows. I will most likely add this, but again, I have to read more on this. Reopening this issue.
I've tried with SO_EXCLUSIVEADDRUSE on Simple-Web-Server, bind on 127.0.0.1:3333
The node server can bind on 0.0.0.0:3333 without error and it's the problem. It's not working like the documentation. If the node server is started before Simple-Web-Server with the same settings, Simple-Web-Server binds without error too; but it should be exclusive. The error happens only if the node server uses 127.0.0.1 like Simple-Web-Server.
I can provide a complete archive with all files in order to reproduce the problem.
For what I can understand, this is a rather huge security issue for Windows, but what if the different serverapplications are running on different user logins? I'm afraid I do not have any other ideas if SO_EXCLUSIVEADDRUSE is not working. Maybe other than setting the SO_EXCLUSIVEADDRUSE option correctly, if it is not set correctly already for some reason. Like I said, boost is rather picky on how you set these options.