diff --git a/include/libtorrent/natpmp.hpp b/include/libtorrent/natpmp.hpp index 2ad31b5cd..698a67467 100644 --- a/include/libtorrent/natpmp.hpp +++ b/include/libtorrent/natpmp.hpp @@ -68,17 +68,19 @@ public: private: - void update_mapping(int i); - void send_map_request(int i); + typedef boost::mutex mutex_t; + + void update_mapping(int i, mutex_t::scoped_lock& l); + void send_map_request(int i, mutex_t::scoped_lock& l); void resend_request(int i, error_code const& e); void on_reply(error_code const& e , std::size_t bytes_transferred); - void try_next_mapping(int i); + void try_next_mapping(int i, mutex_t::scoped_lock& l); void update_expiration_timer(); void mapping_expired(error_code const& e, int i); - void log(char const* msg); - void disable(error_code const& ec); + void log(char const* msg, mutex_t::scoped_lock& l); + void disable(error_code const& ec, mutex_t::scoped_lock& l); struct mapping_t { @@ -153,8 +155,7 @@ private: bool m_abort; - typedef boost::mutex mutex_t; - mutex_t m_mutex; + mutable mutex_t m_mutex; }; } diff --git a/include/libtorrent/upnp.hpp b/include/libtorrent/upnp.hpp index fc869defc..2a973b371 100644 --- a/include/libtorrent/upnp.hpp +++ b/include/libtorrent/upnp.hpp @@ -123,7 +123,9 @@ public: private: - void discover_device_impl(); + typedef boost::mutex mutex_t; + + void discover_device_impl(mutex_t::scoped_lock& l); static address_v4 upnp_multicast_address; static udp::endpoint upnp_multicast_endpoint; @@ -134,8 +136,8 @@ private: , std::size_t bytes_transferred); struct rootdevice; - void next(rootdevice& d, int i); - void update_map(rootdevice& d, int i); + void next(rootdevice& d, int i, mutex_t::scoped_lock& l); + void update_map(rootdevice& d, int i, mutex_t::scoped_lock& l); void on_upnp_xml(error_code const& e @@ -149,14 +151,14 @@ private: , int mapping, http_connection& c); void on_expire(error_code const& e); - void disable(error_code const& ec); - void return_error(int mapping, int code); - void log(char const* msg); + void disable(error_code const& ec, mutex_t::scoped_lock& l); + void return_error(int mapping, int code, mutex_t::scoped_lock& l); + void log(char const* msg, mutex_t::scoped_lock& l); void delete_port_mapping(rootdevice& d, int i); void create_port_mapping(http_connection& c, rootdevice& d, int i); void post(upnp::rootdevice const& d, char const* soap - , char const* soap_action); + , char const* soap_action, mutex_t::scoped_lock& l); int num_mappings() const { return int(m_mappings.size()); } @@ -304,7 +306,6 @@ private: connection_queue& m_cc; - typedef boost::mutex mutex_t; mutex_t m_mutex; std::string m_model; diff --git a/src/natpmp.cpp b/src/natpmp.cpp index 6a57d49f1..2a99377a4 100644 --- a/src/natpmp.cpp +++ b/src/natpmp.cpp @@ -75,8 +75,8 @@ void natpmp::rebind(address const& listen_interface) { char msg[200]; snprintf(msg, sizeof(msg), "failed to find default route: %s", ec.message().c_str()); - log(msg); - disable(ec); + log(msg, l); + disable(ec, l); return; } @@ -89,18 +89,18 @@ void natpmp::rebind(address const& listen_interface) char msg[200]; snprintf(msg, sizeof(msg), "found router at: %s" , print_address(m_nat_endpoint.address()).c_str()); - log(msg); + log(msg, l); m_socket.open(udp::v4(), ec); if (ec) { - disable(ec); + disable(ec, l); return; } m_socket.bind(udp::endpoint(address_v4::any(), 0), ec); if (ec) { - disable(ec); + disable(ec, l); return; } @@ -114,12 +114,14 @@ void natpmp::rebind(address const& listen_interface) || i->action != mapping_t::action_none) continue; i->action = mapping_t::action_add; - update_mapping(i - m_mappings.begin()); + update_mapping(i - m_mappings.begin(), l); } } bool natpmp::get_mapping(int index, int& local_port, int& external_port, int& protocol) const { + mutex_t::scoped_lock l(m_mutex); + TORRENT_ASSERT(index < int(m_mappings.size()) && index >= 0); if (index >= int(m_mappings.size()) || index < 0) return false; mapping_t const& m = m_mappings[index]; @@ -130,12 +132,14 @@ bool natpmp::get_mapping(int index, int& local_port, int& external_port, int& pr return true; } -void natpmp::log(char const* msg) +void natpmp::log(char const* msg, mutex_t::scoped_lock& l) { + l.unlock(); m_log_callback(msg); + l.lock(); } -void natpmp::disable(error_code const& ec) +void natpmp::disable(error_code const& ec, mutex_t::scoped_lock& l) { m_disabled = true; @@ -144,13 +148,18 @@ void natpmp::disable(error_code const& ec) { if (i->protocol == none) continue; i->protocol = none; - m_callback(i - m_mappings.begin(), 0, ec); + int index = i - m_mappings.begin(); + l.unlock(); + m_callback(index, 0, ec); + l.lock(); } close(); } void natpmp::delete_mapping(int index) { + mutex_t::scoped_lock l(m_mutex); + TORRENT_ASSERT(index < int(m_mappings.size()) && index >= 0); if (index >= int(m_mappings.size()) || index < 0) return; mapping_t& m = m_mappings[index]; @@ -164,7 +173,7 @@ void natpmp::delete_mapping(int index) } m.action = mapping_t::action_delete; - update_mapping(index); + update_mapping(index, l); } int natpmp::add_mapping(protocol_type p, int external_port, int local_port) @@ -187,11 +196,11 @@ int natpmp::add_mapping(protocol_type p, int external_port, int local_port) int mapping_index = i - m_mappings.begin(); - update_mapping(mapping_index); + update_mapping(mapping_index, l); return mapping_index; } -void natpmp::try_next_mapping(int i) +void natpmp::try_next_mapping(int i, mutex_t::scoped_lock& l) { /* #if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) @@ -211,7 +220,7 @@ void natpmp::try_next_mapping(int i) */ if (i < int(m_mappings.size()) - 1) { - update_mapping(i + 1); + update_mapping(i + 1, l); return; } @@ -237,10 +246,10 @@ void natpmp::try_next_mapping(int i) // m_log << " updating " << (m - m_mappings.begin()) << std::endl; //#endif - update_mapping(m - m_mappings.begin()); + update_mapping(m - m_mappings.begin(), l); } -void natpmp::update_mapping(int i) +void natpmp::update_mapping(int i, mutex_t::scoped_lock& l) { if (i == m_mappings.size()) { @@ -260,7 +269,7 @@ void natpmp::update_mapping(int i) if (m.action == mapping_t::action_none || m.protocol == none) { - try_next_mapping(i); + try_next_mapping(i, l); return; } @@ -269,11 +278,11 @@ void natpmp::update_mapping(int i) // the socket is not currently in use // send out a mapping request m_retry_count = 0; - send_map_request(i); + send_map_request(i, l); } } -void natpmp::send_map_request(int i) +void natpmp::send_map_request(int i, mutex_t::scoped_lock& l) { using namespace libtorrent::detail; @@ -298,7 +307,7 @@ void natpmp::send_map_request(int i) , m.action == mapping_t::action_add ? "add" : "delete" , m.protocol == udp ? "udp" : "tcp" , m.local_port, m.external_port, ttl); - log(msg); + log(msg, l); error_code ec; m_socket.send_to(asio::buffer(buf, 12), m_nat_endpoint, 0, ec); @@ -310,7 +319,7 @@ void natpmp::send_map_request(int i) // immediately m_currently_mapping = -1; m.action = mapping_t::action_none; - try_next_mapping(i); + try_next_mapping(i, l); } else { @@ -335,21 +344,23 @@ void natpmp::resend_request(int i, error_code const& e) m_mappings[i].action = mapping_t::action_none; // try again in two hours m_mappings[i].expires = time_now() + hours(2); - try_next_mapping(i); + try_next_mapping(i, l); return; } - send_map_request(i); + send_map_request(i, l); } void natpmp::on_reply(error_code const& e , std::size_t bytes_transferred) { + mutex_t::scoped_lock l(m_mutex); + using namespace libtorrent::detail; if (e) { char msg[200]; snprintf(msg, sizeof(msg), "error on receiving reply: %s", e.message().c_str()); - log(msg); + log(msg, l); return; } @@ -360,7 +371,7 @@ void natpmp::on_reply(error_code const& e /* if ((rand() % 2) == 0) { - log(" simulating drop"); + log(" simulating drop", l); return; } */ @@ -369,12 +380,10 @@ void natpmp::on_reply(error_code const& e char msg[200]; snprintf(msg, sizeof(msg), "received packet from wrong IP: %s" , print_endpoint(m_remote).c_str()); - log(msg); + log(msg, l); return; } - mutex_t::scoped_lock l(m_mutex); - error_code ec; m_send_timer.cancel(ec); @@ -401,7 +410,7 @@ void natpmp::on_reply(error_code const& e { snprintf(msg + num_chars, sizeof(msg) - num_chars, "unexpected version: %u" , version); - log(msg); + log(msg, l); } mapping_t* m = 0; @@ -420,10 +429,10 @@ void natpmp::on_reply(error_code const& e if (m == 0) { snprintf(msg + num_chars, sizeof(msg) - num_chars, " not found in map table"); - log(msg); + log(msg, l); return; } - log(msg); + log(msg, l); if (public_port == 0 || lifetime == 0) { @@ -451,18 +460,22 @@ void natpmp::on_reply(error_code const& e if (result >= 1 && result <= 5) ev = errors[result - 1]; m->expires = time_now() + hours(2); + l.unlock(); m_callback(index, 0, error_code(ev, libtorrent_category)); + l.lock(); } else if (m->action == mapping_t::action_add) { + l.unlock(); m_callback(index, m->external_port, error_code(errors::no_error, libtorrent_category)); + l.lock(); } m_currently_mapping = -1; m->action = mapping_t::action_none; m_send_timer.cancel(ec); update_expiration_timer(); - try_next_mapping(index); + try_next_mapping(index, l); } void natpmp::update_expiration_timer() @@ -527,17 +540,17 @@ void natpmp::mapping_expired(error_code const& e, int i) mutex_t::scoped_lock l(m_mutex); char msg[200]; snprintf(msg, sizeof(msg), "mapping %u expired", i); - log(msg); + log(msg, l); m_mappings[i].action = mapping_t::action_add; if (m_next_refresh == i) m_next_refresh = -1; - update_mapping(i); + update_mapping(i, l); } void natpmp::close() { mutex_t::scoped_lock l(m_mutex); m_abort = true; - log("closing"); + log("closing", l); /* #if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) m_log << time_now_string() << " close" << std::endl; @@ -564,6 +577,6 @@ void natpmp::close() } error_code ec; m_refresh_timer.cancel(ec); - update_mapping(0); + update_mapping(0, l); } diff --git a/src/upnp.cpp b/src/upnp.cpp index a53002eac..81fac31fd 100644 --- a/src/upnp.cpp +++ b/src/upnp.cpp @@ -107,17 +107,19 @@ void upnp::discover_device() { mutex_t::scoped_lock l(m_mutex); if (m_socket.num_send_sockets() == 0) - log("No network interfaces to broadcast to"); + log("No network interfaces to broadcast to", l); - discover_device_impl(); + discover_device_impl(l); } -void upnp::log(char const* msg) +void upnp::log(char const* msg, mutex_t::scoped_lock& l) { + l.unlock(); m_log_callback(msg); + l.lock(); } -void upnp::discover_device_impl() +void upnp::discover_device_impl(mutex_t::scoped_lock& l) { const char msearch[] = "M-SEARCH * HTTP/1.1\r\n" @@ -138,8 +140,8 @@ void upnp::discover_device_impl() { char msg[200]; snprintf(msg, sizeof(msg), "broadcast failed: %s. Aborting.", ec.message().c_str()); - log(msg); - disable(ec); + log(msg, l); + disable(ec, l); return; } @@ -148,7 +150,7 @@ void upnp::discover_device_impl() m_broadcast_timer.async_wait(bind(&upnp::resend_request , self(), _1)); - log("broadcasting search for rootdevice"); + log("broadcasting search for rootdevice", l); } // returns a reference to a mapping or -1 on failure @@ -160,7 +162,7 @@ int upnp::add_mapping(upnp::protocol_type p, int external_port, int local_port) snprintf(msg, sizeof(msg), "adding port map: [ protocol: %s ext_port: %u " "local_port: %u ] %s", (p == tcp?"tcp":"udp"), external_port , local_port, m_disabled ? "DISABLED": ""); - log(msg); + log(msg, l); if (m_disabled) return -1; std::vector::iterator i = std::find_if( @@ -194,7 +196,7 @@ int upnp::add_mapping(upnp::protocol_type p, int external_port, int local_port) m.external_port = external_port; m.local_port = local_port; - if (d.service_namespace) update_map(d, mapping_index); + if (d.service_namespace) update_map(d, mapping_index, l); } return mapping_index; @@ -212,7 +214,7 @@ void upnp::delete_mapping(int mapping) snprintf(msg, sizeof(msg), "deleting port map: [ protocol: %s ext_port: %u " "local_port: %u ]", (m.protocol == tcp?"tcp":"udp"), m.external_port , m.local_port); - log(msg); + log(msg, l); if (m.protocol == none) return; @@ -225,7 +227,7 @@ void upnp::delete_mapping(int mapping) TORRENT_ASSERT(mapping < int(d.mapping.size())); d.mapping[mapping].action = mapping_t::action_delete; - if (d.service_namespace) update_map(d, mapping); + if (d.service_namespace) update_map(d, mapping, l); } } @@ -252,13 +254,13 @@ void upnp::resend_request(error_code const& e) if (m_retry_count < 12 && (m_devices.empty() || m_retry_count < 4)) { - discover_device_impl(); + discover_device_impl(l); return; } if (m_devices.empty()) { - disable(error_code(errors::no_router, libtorrent_category)); + disable(error_code(errors::no_router, libtorrent_category), l); return; } @@ -277,7 +279,7 @@ void upnp::resend_request(error_code const& e) #endif char msg[200]; snprintf(msg, sizeof(msg), "connecting to: %s", d.url.c_str()); - log(msg); + log(msg, l); if (d.upnp_connection) d.upnp_connection->close(); d.upnp_connection.reset(new http_connection(m_io_service , m_cc, bind(&upnp::on_upnp_xml, self(), _1, _2 @@ -290,7 +292,7 @@ void upnp::resend_request(error_code const& e) (void)e; char msg[200]; snprintf(msg, sizeof(msg), "connection failed to: %s %s", d.url.c_str(), e.what()); - log(msg); + log(msg, l); d.disabled = true; } #endif @@ -339,7 +341,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer char msg[200]; snprintf(msg, sizeof(msg), "when receiving response from: %s: %s" , print_endpoint(from).c_str(), ec.message().c_str()); - log(msg); + log(msg, l); } else { @@ -347,7 +349,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer int num_chars = snprintf(msg, sizeof(msg) , "ignoring response from: %s. IP is not on local network. " , print_endpoint(from).c_str()); - log(msg); + log(msg, l); std::vector net = enum_net_interfaces(m_io_service, ec); for (std::vector::const_iterator i = net.begin() @@ -356,7 +358,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer num_chars += snprintf(msg + num_chars, sizeof(msg) - num_chars, "(%s,%s) " , print_address(i->interface_address).c_str(), print_address(i->netmask).c_str()); } - log(msg); + log(msg, l); } return; } @@ -374,7 +376,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer char msg[200]; snprintf(msg, sizeof(msg), "when receiving response from: %s: %s" , print_endpoint(from).c_str(), ec.message().c_str()); - log(msg); + log(msg, l); } else { @@ -387,7 +389,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer num_chars += snprintf(msg + num_chars, sizeof(msg) - num_chars, "(%s,%s) " , print_address(i->gateway).c_str(), print_address(i->netmask).c_str()); } - log(msg); + log(msg, l); } return; } @@ -402,7 +404,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer char msg[200]; snprintf(msg, sizeof(msg), "received malformed HTTP from: %s" , print_endpoint(from).c_str()); - log(msg); + log(msg, l); return; } @@ -413,14 +415,14 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer char msg[200]; snprintf(msg, sizeof(msg), "HTTP status %u from %s" , p.status_code(), print_endpoint(from).c_str()); - log(msg); + log(msg, l); } else { char msg[200]; snprintf(msg, sizeof(msg), "HTTP method %s from %s" , p.method().c_str(), print_endpoint(from).c_str()); - log(msg); + log(msg, l); } return; } @@ -430,7 +432,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer char msg[200]; snprintf(msg, sizeof(msg), "incomplete HTTP packet from %s" , print_endpoint(from).c_str()); - log(msg); + log(msg, l); return; } @@ -440,7 +442,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer char msg[200]; snprintf(msg, sizeof(msg), "missing location header from %s" , print_endpoint(from).c_str()); - log(msg); + log(msg, l); return; } @@ -464,7 +466,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer char msg[200]; snprintf(msg, sizeof(msg), "invalid URL %s from %s: %s" , d.url.c_str(), print_endpoint(from).c_str(), ec.message().c_str()); - log(msg); + log(msg, l); return; } @@ -476,7 +478,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer char msg[200]; snprintf(msg, sizeof(msg), "unsupported protocol %s from %s" , protocol.c_str(), print_endpoint(from).c_str()); - log(msg); + log(msg, l); return; } @@ -485,21 +487,21 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer char msg[200]; snprintf(msg, sizeof(msg), "URL with port 0 from %s" , print_endpoint(from).c_str()); - log(msg); + log(msg, l); return; } char msg[200]; snprintf(msg, sizeof(msg), "found rootdevice: %s (%d)" , d.url.c_str(), int(m_devices.size())); - log(msg); + log(msg, l); if (m_devices.size() >= 50) { char msg[200]; snprintf(msg, sizeof(msg), "too many rootdevices: (%d). Ignoring %s" , int(m_devices.size()), d.url.c_str()); - log(msg); + log(msg, l); return; } @@ -536,7 +538,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer char msg[200]; snprintf(msg, sizeof(msg), "connecting to: %s" , d.url.c_str()); - log(msg); + log(msg, l); if (d.upnp_connection) d.upnp_connection->close(); d.upnp_connection.reset(new http_connection(m_io_service @@ -552,7 +554,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer char msg[200]; snprintf(msg, sizeof(msg), "connection failed to: %s %s" , d.url.c_str(), e.what()); - log(msg); + log(msg, l); d.disabled = true; } #endif @@ -562,7 +564,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer } void upnp::post(upnp::rootdevice const& d, char const* soap - , char const* soap_action) + , char const* soap_action, mutex_t::scoped_lock& l) { TORRENT_ASSERT(d.magic == 1337); TORRENT_ASSERT(d.upnp_connection); @@ -582,7 +584,7 @@ void upnp::post(upnp::rootdevice const& d, char const* soap char msg[400]; snprintf(msg, sizeof(msg), "sending: %s", header); - log(msg); + log(msg, l); } void upnp::create_port_mapping(http_connection& c, rootdevice& d, int i) @@ -596,7 +598,7 @@ void upnp::create_port_mapping(http_connection& c, rootdevice& d, int i) TORRENT_ASSERT(d.disabled); char msg[200]; snprintf(msg, sizeof(msg), "mapping %u aborted", i); - log(msg); + log(msg, l); return; } @@ -623,14 +625,14 @@ void upnp::create_port_mapping(http_connection& c, rootdevice& d, int i) , print_address(c.socket().local_endpoint(ec).address()).c_str() , m_user_agent.c_str(), d.lease_duration, soap_action); - post(d, soap, soap_action); + post(d, soap, soap_action, l); } -void upnp::next(rootdevice& d, int i) +void upnp::next(rootdevice& d, int i, mutex_t::scoped_lock& l) { if (i < num_mappings() - 1) { - update_map(d, i + 1); + update_map(d, i + 1, l); } else { @@ -639,11 +641,11 @@ void upnp::next(rootdevice& d, int i) , boost::bind(&mapping_t::action, _1) != int(mapping_t::action_none)); if (i == d.mapping.end()) return; - update_map(d, i - d.mapping.begin()); + update_map(d, i - d.mapping.begin(), l); } } -void upnp::update_map(rootdevice& d, int i) +void upnp::update_map(rootdevice& d, int i, mutex_t::scoped_lock& l) { TORRENT_ASSERT(d.magic == 1337); TORRENT_ASSERT(i < int(d.mapping.size())); @@ -658,9 +660,9 @@ void upnp::update_map(rootdevice& d, int i) { char msg[200]; snprintf(msg, sizeof(msg), "mapping %u does not need updating, skipping", i); - log(msg); + log(msg, l); m.action = mapping_t::action_none; - next(d, i); + next(d, i, l); return; } @@ -669,14 +671,14 @@ void upnp::update_map(rootdevice& d, int i) char msg[200]; snprintf(msg, sizeof(msg), "connecting to %s", d.hostname.c_str()); - log(msg); + log(msg, l); if (m.action == mapping_t::action_add) { if (m.failcount > 5) { m.action = mapping_t::action_none; // giving up - next(d, i); + next(d, i, l); return; } @@ -714,7 +716,7 @@ void upnp::delete_port_mapping(rootdevice& d, int i) TORRENT_ASSERT(d.disabled); char msg[200]; snprintf(msg, sizeof(msg), "unmapping %u aborted", i); - log(msg); + log(msg, l); return; } @@ -734,7 +736,7 @@ void upnp::delete_port_mapping(rootdevice& d, int i) , (d.mapping[i].protocol == udp ? "UDP" : "TCP") , soap_action); - post(d, soap, soap_action); + post(d, soap, soap_action, l); } namespace @@ -848,7 +850,7 @@ void upnp::on_upnp_xml(error_code const& e char msg[200]; snprintf(msg, sizeof(msg), "error while fetching control url from: %s: %s" , d.url.c_str(), e.message().c_str()); - log(msg); + log(msg, l); d.disabled = true; return; } @@ -858,7 +860,7 @@ void upnp::on_upnp_xml(error_code const& e char msg[200]; snprintf(msg, sizeof(msg), "error while fetching control url from: %s: incomplete HTTP message" , d.url.c_str()); - log(msg); + log(msg, l); d.disabled = true; return; } @@ -868,7 +870,7 @@ void upnp::on_upnp_xml(error_code const& e char msg[200]; snprintf(msg, sizeof(msg), "error while fetching control url from: %s: %s" , d.url.c_str(), p.message().c_str()); - log(msg); + log(msg, l); d.disabled = true; return; } @@ -899,7 +901,7 @@ void upnp::on_upnp_xml(error_code const& e char msg[200]; snprintf(msg, sizeof(msg), "could not find a port mapping interface in response from: %s" , d.url.c_str()); - log(msg); + log(msg, l); d.disabled = true; return; } @@ -932,7 +934,7 @@ void upnp::on_upnp_xml(error_code const& e "urlbase: %s in response from %s" , d.control_url.c_str(), d.service_namespace , s.url_base.c_str(), d.url.c_str()); - log(msg); + log(msg, l); boost::tie(protocol, auth, d.hostname, d.port, d.path) = parse_url_components(d.control_url, ec); @@ -942,15 +944,15 @@ void upnp::on_upnp_xml(error_code const& e char msg[200]; snprintf(msg, sizeof(msg), "failed to parse URL '%s': %s" , d.control_url.c_str(), ec.message().c_str()); - log(msg); + log(msg, l); d.disabled = true; return; } - if (num_mappings() > 0) update_map(d, 0); + if (num_mappings() > 0) update_map(d, 0, l); } -void upnp::disable(error_code const& ec) +void upnp::disable(error_code const& ec, mutex_t::scoped_lock& l) { m_disabled = true; @@ -960,7 +962,9 @@ void upnp::disable(error_code const& ec) { if (i->protocol == none) continue; i->protocol = none; + l.unlock(); m_callback(i - m_mappings.begin(), 0, ec); + l.lock(); } // we cannot clear the devices since there @@ -1077,7 +1081,7 @@ void upnp::on_upnp_map_response(error_code const& e char msg[200]; snprintf(msg, sizeof(msg), "error while adding port map: %s" , e.message().c_str()); - log(msg); + log(msg, l); d.disabled = true; return; } @@ -1103,8 +1107,8 @@ void upnp::on_upnp_map_response(error_code const& e if (!p.header_finished()) { - log("error while adding port map: incomplete http message"); - next(d, mapping); + log("error while adding port map: incomplete http message", l); + next(d, mapping, l); return; } @@ -1120,7 +1124,7 @@ void upnp::on_upnp_map_response(error_code const& e char msg[200]; snprintf(msg, sizeof(msg), "error while adding port map, code: %u" , s.error_code); - log(msg); + log(msg, l); } mapping_t& m = d.mapping[mapping]; @@ -1131,7 +1135,7 @@ void upnp::on_upnp_map_response(error_code const& e d.lease_duration = 0; m.action = mapping_t::action_add; ++m.failcount; - update_map(d, mapping); + update_map(d, mapping, l); return; } else if (s.error_code == 718 || s.error_code == 727) @@ -1143,10 +1147,10 @@ void upnp::on_upnp_map_response(error_code const& e m.external_port = 0; m.action = mapping_t::action_add; ++m.failcount; - update_map(d, mapping); + update_map(d, mapping, l); return; } - return_error(mapping, s.error_code); + return_error(mapping, s.error_code, l); } else if (s.error_code == 716) { @@ -1155,22 +1159,24 @@ void upnp::on_upnp_map_response(error_code const& e m.external_port = 40000 + (std::rand() % 10000); m.action = mapping_t::action_add; ++m.failcount; - update_map(d, mapping); + update_map(d, mapping, l); return; } else if (s.error_code != -1) { - return_error(mapping, s.error_code); + return_error(mapping, s.error_code, l); } char msg[200]; snprintf(msg, sizeof(msg), "map response: %s" , std::string(p.get_body().begin, p.get_body().end).c_str()); - log(msg); + log(msg, l); if (s.error_code == -1) { + l.unlock(); m_callback(mapping, m.external_port, error_code()); + l.lock(); if (d.lease_duration > 0) { m.expires = time_now() @@ -1191,10 +1197,10 @@ void upnp::on_upnp_map_response(error_code const& e m.failcount = 0; } - next(d, mapping); + next(d, mapping, l); } -void upnp::return_error(int mapping, int code) +void upnp::return_error(int mapping, int code, mutex_t::scoped_lock& l) { int num_errors = sizeof(error_codes) / sizeof(error_codes[0]); error_code_t* end = error_codes + num_errors; @@ -1208,7 +1214,9 @@ void upnp::return_error(int mapping, int code) error_string += ": "; error_string += e->msg; } + l.unlock(); m_callback(mapping, 0, error_code(code, upnp_category)); + l.lock(); } void upnp::on_upnp_unmap_response(error_code const& e @@ -1228,29 +1236,29 @@ void upnp::on_upnp_unmap_response(error_code const& e { char msg[200]; snprintf(msg, sizeof(msg), "error while deleing portmap: %s", e.message().c_str()); - log(msg); + log(msg, l); } else if (!p.header_finished()) { - log("error while deleting portmap: incomplete http message"); + log("error while deleting portmap: incomplete http message", l); } else if (p.status_code() != 200) { char msg[200]; snprintf(msg, sizeof(msg), "error while deleing portmap: %s", p.message().c_str()); - log(msg); + log(msg, l); } else { char msg[200]; snprintf(msg, sizeof(msg), "unmap response: %s" , std::string(p.get_body().begin, p.get_body().end).c_str()); - log(msg); + log(msg, l); } d.mapping[mapping].protocol = none; - next(d, mapping); + next(d, mapping, l); } void upnp::on_expire(error_code const& e) @@ -1275,7 +1283,7 @@ void upnp::on_expire(error_code const& e) if (d.mapping[m].expires < now) { d.mapping[m].expires = max_time(); - update_map(d, m); + update_map(d, m, l); } else if (d.mapping[m].expires < next_expire) { @@ -1319,7 +1327,7 @@ void upnp::close() j->action = mapping_t::action_delete; m_mappings[j - d.mapping.begin()].protocol = none; } - if (num_mappings() > 0) update_map(d, 0); + if (num_mappings() > 0) update_map(d, 0, l); } }