Quantcast
Channel: WE MOVED to github.com/microsoft/cpprestsdk. This site is not monitored!
Viewing all articles
Browse latest Browse all 4845

Commented Issue: Two http_listeners on one port (problem with solution) [375]

$
0
0
Hi,

I found a problem when I wanted to have http server application which finds its free port.
We can think about BlackJackServer from samples. When we run the second instance of BlackJackServer it should find a free port.
If we try to open http_listener on occupied port, exception is thrown. So for our example we can easily modify on_initialize function from BlackJack_Server.cpp file:
```
52 void on_initialize()
53 {
54 utility::string_t addr;
55 unsigned int port = 12345;
56 bool isDealerStarted = false;
57 while(!isDealerStarted)
58 {
59 try
60 {
61 utility::string_t address = U("http://localhost:");
62 address.append(U(std::to_string(port)));
63 uri_builder uri(address);
64 uri.append_path(U("blackjack/dealer"));
65 addr = uri.to_uri().to_string();
66
67 g_httpDealer = std::unique_ptr<BlackJackDealer>(new BlackJackDealer(addr));
68 g_httpDealer->open().wait();
69 isDealerStarted = true;
70 }
71 catch(...)
72 {
73 ucout << "Can't start Dealer on port: " << port << std::endl;
74 port++;
75 }
76 }
77
78 ucout << utility::string_t(U("Listening for requests at: ")) << addr << std::endl;
79
80 return;
81 }
```
__If we run two instances of BlackJackServer with that modification, the second one will be trying to open http_listener on various ports from now to infinity.__
The problem is that casablanca stores all http_listeners in map. When we try to open http_listener on used port, exception is throwed, but __http_listener isn't erase from map__. And finally when we try to open new http_listener on different (probably free) port, casablanca tries to open all http_listeners from map and we get one more exception.
To easily solve this problem we can add try/catch sections in register_listener method from http_server_asio.cpp file:
```
847 pplx::task<void> http_linux_server::register_listener(details::http_listener_impl* listener)
848 {
849 auto parts = canonical_parts(listener->uri());
850 auto hostport = parts.first;
851 auto path = parts.second;
852
853 {
854 pplx::extensibility::scoped_rw_lock_t lock(m_listeners_lock);
855 if (m_registered_listeners.find(listener) != m_registered_listeners.end())
856 throw std::invalid_argument("listener already registered");
857
858 try
859 {
860 m_registered_listeners[listener] = utility::details::make_unique<pplx::extensibility::reader_writer_lock_t>();
861
862 auto found_hostport_listener = m_listeners.find(hostport);
863 if (found_hostport_listener == m_listeners.end())
864 {
865 found_hostport_listener = m_listeners.insert(
866 std::make_pair(hostport, utility::details::make_unique<details::hostport_listener>(this, hostport))).first;
867
868 if (m_started)
869 found_hostport_listener->second->start();
870 }
871
872 found_hostport_listener->second->add_listener(path, listener);
873 }
874 catch(...) //naive solution
875 {
876 m_registered_listeners.erase(listener);
877 m_listeners.erase(hostport);
878 throw;
879 }
880 }
881
882 return pplx::task_from_result();
883 }
```
This fixes the problem and now the second instance of BlackJackServer is working fine :-)
Tested on Ubuntu 14.04

Best regards
Andrzej Doros
Comments: Hi Andrzej, We accept contributions, it sounds like you already have this working so consider submitting a pull request for the changes in http_server_asio.cpp on the 'development' branch. Instead of rethrowing the exception in the catch block it would be better to return a A further improvement would be to make the hostport_listener::start method actually operate fully asynchronous returning a task and call async_resolve instead of the synchronous version. Steve

Viewing all articles
Browse latest Browse all 4845

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>