65
61
upnp::upnp(io_service& ios, connection_queue& cc
66
62
, address const& listen_interface, std::string const& user_agent
67
, portmap_callback_t const& cb, bool ignore_nonrouters, void* state)
68
: m_user_agent(user_agent)
63
, portmap_callback_t const& cb, log_callback_t const& lcb
64
, bool ignore_nonrouters, void* state)
65
: m_user_agent(user_agent)
71
69
, m_io_service(ios)
72
70
, m_socket(ios, udp::endpoint(address_v4::from_string("239.255.255.250", ec), 1900)
73
, bind(&upnp::on_reply, self(), _1, _2, _3), false)
71
, bind(&upnp::on_reply, self(), _1, _2, _3))
74
72
, m_broadcast_timer(ios)
75
73
, m_refresh_timer(ios)
76
74
, m_disabled(false)
111
106
void upnp::discover_device()
113
108
mutex_t::scoped_lock l(m_mutex);
115
discover_device_impl();
118
void upnp::discover_device_impl()
109
if (m_socket.num_send_sockets() == 0)
110
log("No network interfaces to broadcast to", l);
112
discover_device_impl(l);
115
void upnp::log(char const* msg, mutex_t::scoped_lock& l)
122
void upnp::discover_device_impl(mutex_t::scoped_lock& l)
120
124
const char msearch[] =
121
125
"M-SEARCH * HTTP/1.1\r\n"
160
159
mutex_t::scoped_lock l(m_mutex);
162
#ifdef TORRENT_UPNP_LOGGING
163
m_log << time_now_string()
164
<< " *** add mapping [ proto: " << (p == tcp?"tcp":"udp")
165
<< " ext_port: " << external_port
166
<< " local_port :" << local_port << " ]";
167
if (m_disabled) m_log << " DISABLED";
162
snprintf(msg, sizeof(msg), "adding port map: [ protocol: %s ext_port: %u "
163
"local_port: %u ] %s", (p == tcp?"tcp":"udp"), external_port
164
, local_port, m_disabled ? "DISABLED": "");
170
166
if (m_disabled) return -1;
172
168
std::vector<global_mapping_t>::iterator i = std::find_if(
215
211
global_mapping_t& m = m_mappings[mapping];
217
#ifdef TORRENT_UPNP_LOGGING
218
m_log << time_now_string()
219
<< " *** delete mapping [ proto: " << (m.protocol == tcp?"tcp":"udp")
220
<< " ext_port:" << m.external_port
221
<< " local_port:" << m.local_port << " ]";
214
snprintf(msg, sizeof(msg), "deleting port map: [ protocol: %s ext_port: %u "
215
"local_port: %u ]", (m.protocol == tcp?"tcp":"udp"), m.external_port
225
219
if (m.protocol == none) return;
233
227
TORRENT_ASSERT(mapping < int(d.mapping.size()));
234
228
d.mapping[mapping].action = mapping_t::action_delete;
236
if (d.service_namespace) update_map(d, mapping);
230
if (d.service_namespace) update_map(d, mapping, l);
234
bool upnp::get_mapping(int index, int& local_port, int& external_port, int& protocol) const
236
TORRENT_ASSERT(index < int(m_mappings.size()) && index >= 0);
237
if (index >= int(m_mappings.size()) || index < 0) return false;
238
global_mapping_t const& m = m_mappings[index];
239
if (m.protocol == none) return false;
240
local_port = m.local_port;
241
external_port = m.external_port;
242
protocol = m.protocol;
240
246
void upnp::resend_request(error_code const& e)
250
256
if (m_retry_count < 12
251
257
&& (m_devices.empty() || m_retry_count < 4))
253
discover_device_impl();
259
discover_device_impl(l);
257
263
if (m_devices.empty())
259
#ifdef TORRENT_UPNP_LOGGING
260
m_log << time_now_string()
261
<< " *** Got no response in 12 retries. Giving up, "
262
"disabling UPnP." << std::endl;
264
disable("no UPnP router found");
265
disable(errors::no_router, l);
275
276
rootdevice& d = const_cast<rootdevice&>(*i);
276
277
TORRENT_ASSERT(d.magic == 1337);
278
#ifndef BOOST_NO_EXCEPTIONS
279
#ifdef TORRENT_UPNP_LOGGING
280
m_log << time_now_string()
281
<< " ==> connecting to " << d.url << std::endl;
283
snprintf(msg, sizeof(msg), "connecting to: %s", d.url.c_str());
283
285
if (d.upnp_connection) d.upnp_connection->close();
284
286
d.upnp_connection.reset(new http_connection(m_io_service
285
287
, m_cc, bind(&upnp::on_upnp_xml, self(), _1, _2
286
288
, boost::ref(d), _5)));
287
289
d.upnp_connection->get(d.url, seconds(30), 1);
290
#ifndef BOOST_NO_EXCEPTIONS
289
292
catch (std::exception& e)
292
#ifdef TORRENT_UPNP_LOGGING
293
m_log << time_now_string()
294
<< " *** Connection failed to: " << d.url
295
<< " " << e.what() << std::endl;
296
snprintf(msg, sizeof(msg), "connection failed to: %s %s", d.url.c_str(), e.what());
297
298
d.disabled = true;
339
341
if (!in_local_network(m_io_service, from.address(), ec))
341
#ifdef TORRENT_UPNP_LOGGING
344
m_log << time_now_string() << " <== (" << from << ") error: "
345
<< ec.message() << std::endl;
346
snprintf(msg, sizeof(msg), "when receiving response from: %s: %s"
347
, print_endpoint(from).c_str(), ec.message().c_str());
349
m_log << time_now_string() << " <== (" << from << ") UPnP device "
350
"ignored because it's not on our local network ";
353
int num_chars = snprintf(msg, sizeof(msg)
354
, "ignoring response from: %s. IP is not on local network. "
355
, print_endpoint(from).c_str());
351
358
std::vector<ip_interface> net = enum_net_interfaces(m_io_service, ec);
352
359
for (std::vector<ip_interface>::const_iterator i = net.begin()
353
360
, end(net.end()); i != end; ++i)
355
m_log << "(" << i->interface_address << ", " << i->netmask << ") ";
362
num_chars += snprintf(msg + num_chars, sizeof(msg) - num_chars, "(%s,%s) "
363
, print_address(i->interface_address).c_str(), print_address(i->netmask).c_str());
363
370
if (m_ignore_non_routers)
365
372
std::vector<ip_route> routes = enum_routes(m_io_service, ec);
367
373
if (std::find_if(routes.begin(), routes.end()
368
374
, bind(&ip_route::gateway, _1) == from.address()) == routes.end())
370
376
// this upnp device is filtered because it's not in the
371
377
// list of configured routers
372
#ifdef TORRENT_UPNP_LOGGING
375
m_log << time_now_string() << " <== (" << from << ") error: "
376
<< ec.message() << std::endl;
381
snprintf(msg, sizeof(msg), "when receiving response from: %s: %s"
382
, print_endpoint(from).c_str(), ec.message().c_str());
380
m_log << time_now_string() << " <== (" << from << ") UPnP device "
381
"ignored because it's not a router on our network ";
388
int num_chars = snprintf(msg, sizeof(msg), "ignoring response from: %s: IP is not a router. "
389
, print_endpoint(from).c_str());
382
390
for (std::vector<ip_route>::const_iterator i = routes.begin()
383
391
, end(routes.end()); i != end; ++i)
385
m_log << "(" << i->gateway << ", " << i->netmask << ") ";
393
num_chars += snprintf(msg + num_chars, sizeof(msg) - num_chars, "(%s,%s) "
394
, print_address(i->gateway).c_str(), print_address(i->netmask).c_str());
397
405
, buffer + bytes_transferred), error);
400
#ifdef TORRENT_UPNP_LOGGING
401
m_log << time_now_string() << " <== (" << from << ") Rootdevice "
402
"responded with incorrect HTTP packet. Ignoring device" << std::endl;
409
snprintf(msg, sizeof(msg), "received malformed HTTP from: %s"
410
, print_endpoint(from).c_str());
407
415
if (p.status_code() != 200 && p.method() != "notify")
409
#ifdef TORRENT_UPNP_LOGGING
410
417
if (p.method().empty())
411
m_log << time_now_string()
412
<< " <== (" << from << ") Device responded with HTTP status: " << p.status_code()
413
<< ". Ignoring device" << std::endl;
420
snprintf(msg, sizeof(msg), "HTTP status %u from %s"
421
, p.status_code(), print_endpoint(from).c_str());
415
m_log << time_now_string()
416
<< " <== (" << from << ") Device with HTTP method: " << p.method()
417
<< ". Ignoring device" << std::endl;
427
snprintf(msg, sizeof(msg), "HTTP method %s from %s"
428
, p.method().c_str(), print_endpoint(from).c_str());
422
434
if (!p.header_finished())
424
#ifdef TORRENT_UPNP_LOGGING
425
m_log << time_now_string()
426
<< " <== (" << from << ") Rootdevice responded with incomplete HTTP "
427
"packet. Ignoring device" << std::endl;
437
snprintf(msg, sizeof(msg), "incomplete HTTP packet from %s"
438
, print_endpoint(from).c_str());
432
443
std::string url = p.header("location");
435
#ifdef TORRENT_UPNP_LOGGING
436
m_log << time_now_string()
437
<< " <== (" << from << ") Rootdevice response is missing a location header. "
438
"Ignoring device" << std::endl;
447
snprintf(msg, sizeof(msg), "missing location header from %s"
448
, print_endpoint(from).c_str());
451
461
std::string protocol;
452
462
std::string auth;
454
464
// we don't have this device in our list. Add it
455
boost::tie(protocol, auth, d.hostname, d.port, d.path, error)
456
= parse_url_components(d.url);
465
boost::tie(protocol, auth, d.hostname, d.port, d.path)
466
= parse_url_components(d.url, ec);
460
#ifdef TORRENT_UPNP_LOGGING
461
m_log << time_now_string()
462
<< " <== (" << from << ") Rootdevice advertized an invalid url: '" << d.url
463
<< "'. " << error << ". Ignoring device" << std::endl;
471
snprintf(msg, sizeof(msg), "invalid URL %s from %s: %s"
472
, d.url.c_str(), print_endpoint(from).c_str(), ec.message().c_str());
471
480
if (protocol != "http")
473
#ifdef TORRENT_UPNP_LOGGING
474
m_log << time_now_string()
475
<< " <== (" << from << ") Rootdevice uses unsupported protocol: '" << protocol
476
<< "'. Ignoring device" << std::endl;
483
snprintf(msg, sizeof(msg), "unsupported protocol %s from %s"
484
, protocol.c_str(), print_endpoint(from).c_str());
483
#ifdef TORRENT_UPNP_LOGGING
484
m_log << time_now_string()
485
<< " <== (" << from << ") Rootdevice responded with a url with port 0. "
486
"Ignoring device" << std::endl;
492
snprintf(msg, sizeof(msg), "URL with port 0 from %s"
493
, print_endpoint(from).c_str());
490
#ifdef TORRENT_UPNP_LOGGING
491
m_log << time_now_string()
492
<< " <== (" << from << ") Found rootdevice: " << d.url
493
<< " total: " << m_devices.size() << std::endl;
499
snprintf(msg, sizeof(msg), "found rootdevice: %s (%d)"
500
, d.url.c_str(), int(m_devices.size()));
496
503
if (m_devices.size() >= 50)
498
#ifdef TORRENT_UPNP_LOGGING
499
m_log << time_now_string()
500
<< " <== (" << from << ") Too many devices (" << m_devices.size() << "), "
501
"ignoring: " << d.url << std::endl;
506
snprintf(msg, sizeof(msg), "too many rootdevices: (%d). Ignoring %s"
507
, int(m_devices.size()), d.url.c_str());
535
#ifdef TORRENT_UPNP_LOGGING
536
m_log << time_now_string()
537
<< " ==> connecting to " << d.url << std::endl;
543
snprintf(msg, sizeof(msg), "connecting to: %s"
539
547
if (d.upnp_connection) d.upnp_connection->close();
540
548
d.upnp_connection.reset(new http_connection(m_io_service
541
549
, m_cc, bind(&upnp::on_upnp_xml, self(), _1, _2
546
554
catch (std::exception& e)
549
#ifdef TORRENT_UPNP_LOGGING
550
m_log << time_now_string()
551
<< " *** Connection failed to: " << d.url
552
<< " " << e.what() << std::endl;
559
snprintf(msg, sizeof(msg), "connection failed to: %s %s"
560
, d.url.c_str(), e.what());
554
562
d.disabled = true;
562
void upnp::post(upnp::rootdevice const& d, std::string const& soap
563
, std::string const& soap_action)
570
void upnp::post(upnp::rootdevice const& d, char const* soap
571
, char const* soap_action, mutex_t::scoped_lock& l)
565
573
TORRENT_ASSERT(d.magic == 1337);
566
574
TORRENT_ASSERT(d.upnp_connection);
568
std::stringstream header;
570
header << "POST " << d.path << " HTTP/1.0\r\n"
571
"Host: " << d.hostname << ":" << d.port << "\r\n"
577
snprintf(header, sizeof(header), "POST %s HTTP/1.0\r\n"
572
579
"Content-Type: text/xml; charset=\"utf-8\"\r\n"
573
"Content-Length: " << soap.size() << "\r\n"
574
"Soapaction: \"" << d.service_namespace << "#" << soap_action << "\"\r\n\r\n" << soap;
576
d.upnp_connection->sendbuffer = header.str();
578
#ifdef TORRENT_UPNP_LOGGING
579
m_log << time_now_string()
580
<< " ==> sending: " << header.str() << std::endl;
580
"Content-Length: %d\r\n"
581
"Soapaction: \"%s#%s\"\r\n\r\n"
583
, d.path.c_str(), d.hostname.c_str(), d.port
584
, int(strlen(soap)), d.service_namespace, soap_action
587
d.upnp_connection->sendbuffer = header;
590
snprintf(msg, sizeof(msg), "sending: %s", header);
585
594
void upnp::create_port_mapping(http_connection& c, rootdevice& d, int i)
591
600
if (!d.upnp_connection)
593
602
TORRENT_ASSERT(d.disabled);
594
#ifdef TORRENT_UPNP_LOGGING
595
m_log << time_now_string() << " *** mapping (" << i
596
<< ") aborted" << std::endl;
604
snprintf(msg, sizeof(msg), "mapping %u aborted", i);
601
std::string soap_action = "AddPortMapping";
603
std::stringstream soap;
605
soap << "<?xml version=\"1.0\"?>\n"
609
char const* soap_action = "AddPortMapping";
611
std::string local_endpoint = print_address(c.socket().local_endpoint(ec).address());
615
snprintf(soap, sizeof(soap), "<?xml version=\"1.0\"?>\n"
606
616
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
607
617
"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
608
"<s:Body><u:" << soap_action << " xmlns:u=\"" << d.service_namespace << "\">";
611
soap << "<NewRemoteHost></NewRemoteHost>"
612
"<NewExternalPort>" << d.mapping[i].external_port << "</NewExternalPort>"
613
"<NewProtocol>" << (d.mapping[i].protocol == udp ? "UDP" : "TCP") << "</NewProtocol>"
614
"<NewInternalPort>" << d.mapping[i].local_port << "</NewInternalPort>"
615
"<NewInternalClient>" << c.socket().local_endpoint(ec).address() << "</NewInternalClient>"
618
"<s:Body><u:%s xmlns:u=\"%s\">"
619
"<NewRemoteHost></NewRemoteHost>"
620
"<NewExternalPort>%u</NewExternalPort>"
621
"<NewProtocol>%s</NewProtocol>"
622
"<NewInternalPort>%u</NewInternalPort>"
623
"<NewInternalClient>%s</NewInternalClient>"
616
624
"<NewEnabled>1</NewEnabled>"
617
"<NewPortMappingDescription>" << m_user_agent << " at " <<
618
c.socket().local_endpoint(ec).address() << ":" << to_string(d.mapping[i].local_port).elems
619
<< "</NewPortMappingDescription>"
620
"<NewLeaseDuration>" << d.lease_duration << "</NewLeaseDuration>";
621
soap << "</u:" << soap_action << "></s:Body></s:Envelope>";
625
"<NewPortMappingDescription>%s at %s:%d</NewPortMappingDescription>"
626
"<NewLeaseDuration>%u</NewLeaseDuration>"
627
"</u:%s></s:Body></s:Envelope>"
628
, soap_action, d.service_namespace, d.mapping[i].external_port
629
, (d.mapping[i].protocol == udp ? "UDP" : "TCP")
630
, d.mapping[i].local_port
631
, local_endpoint.c_str()
632
, m_user_agent.c_str(), local_endpoint.c_str(), d.mapping[i].local_port
633
, d.lease_duration, soap_action);
623
post(d, soap.str(), soap_action);
635
post(d, soap, soap_action, l);
626
void upnp::next(rootdevice& d, int i)
638
void upnp::next(rootdevice& d, int i, mutex_t::scoped_lock& l)
628
640
if (i < num_mappings() - 1)
630
update_map(d, i + 1);
642
update_map(d, i + 1, l);
636
648
, boost::bind(&mapping_t::action, _1) != int(mapping_t::action_none));
637
649
if (i == d.mapping.end()) return;
639
update_map(d, i - d.mapping.begin());
651
update_map(d, i - d.mapping.begin(), l);
643
void upnp::update_map(rootdevice& d, int i)
655
void upnp::update_map(rootdevice& d, int i, mutex_t::scoped_lock& l)
645
657
TORRENT_ASSERT(d.magic == 1337);
646
658
TORRENT_ASSERT(i < int(d.mapping.size()));
655
667
if (m.action == mapping_t::action_none
656
668
|| m.protocol == none)
658
#ifdef TORRENT_UPNP_LOGGING
659
if (m.protocol != none)
660
m_log << time_now_string() << " *** mapping (" << i
661
<< ") does not need update, skipping" << std::endl;
671
snprintf(msg, sizeof(msg), "mapping %u does not need updating, skipping", i);
663
673
m.action = mapping_t::action_none;
668
678
TORRENT_ASSERT(!d.upnp_connection);
669
679
TORRENT_ASSERT(d.service_namespace);
671
#ifdef TORRENT_UPNP_LOGGING
672
m_log << time_now_string()
673
<< " ==> connecting to " << d.hostname << std::endl;
682
snprintf(msg, sizeof(msg), "connecting to %s", d.hostname.c_str());
675
684
if (m.action == mapping_t::action_add)
677
686
if (m.failcount > 5)
679
688
m.action = mapping_t::action_none;
714
723
if (!d.upnp_connection)
716
725
TORRENT_ASSERT(d.disabled);
717
#ifdef TORRENT_UPNP_LOGGING
718
m_log << time_now_string() << " *** unmapping (" << i
719
<< ") aborted" << std::endl;
727
snprintf(msg, sizeof(msg), "unmapping %u aborted", i);
724
std::stringstream soap;
726
std::string soap_action = "DeletePortMapping";
732
char const* soap_action = "DeletePortMapping";
728
soap << "<?xml version=\"1.0\"?>\n"
736
snprintf(soap, sizeof(soap), "<?xml version=\"1.0\"?>\n"
729
737
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
730
738
"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
731
"<s:Body><u:" << soap_action << " xmlns:u=\"" << d.service_namespace << "\">";
733
soap << "<NewRemoteHost></NewRemoteHost>"
734
"<NewExternalPort>" << d.mapping[i].external_port << "</NewExternalPort>"
735
"<NewProtocol>" << (d.mapping[i].protocol == udp ? "UDP" : "TCP") << "</NewProtocol>";
736
soap << "</u:" << soap_action << "></s:Body></s:Envelope>";
739
"<s:Body><u:%s xmlns:u=\"%s\">"
740
"<NewExternalPort>%u</NewExternalPort>"
741
"<NewProtocol>%s</NewProtocol>"
742
"</u:%s></s:Body></s:Envelope>"
743
, soap_action, d.service_namespace
744
, d.mapping[i].external_port
745
, (d.mapping[i].protocol == udp ? "UDP" : "TCP")
738
post(d, soap.str(), soap_action);
748
post(d, soap, soap_action, l);
745
if (c >= 'A' && c <= 'Z') return c + ('a' - 'A');
749
753
void copy_tolower(std::string& dst, char const* src)
752
while (*src) dst.push_back(tolower(*src++));
755
bool string_equal_nocase(char const* lhs, char const* rhs)
757
while (tolower(*lhs) == tolower(*rhs))
759
if (*lhs == 0) return true;
756
while (*src) dst.push_back(to_lower(*src++));
787
780
std::list<std::string>::reverse_iterator i = tag_stack.rbegin();
788
781
if (i == tag_stack.rend()) return false;
789
if (!string_equal_nocase(i->c_str(), str2)) return false;
782
if (!string_equal_no_case(i->c_str(), str2)) return false;
791
784
if (i == tag_stack.rend()) return false;
792
if (!string_equal_nocase(i->c_str(), str1)) return false;
785
if (!string_equal_no_case(i->c_str(), str1)) return false;
797
void find_control_url(int type, char const* string, parse_state& state)
790
TORRENT_EXPORT void find_control_url(int type, char const* string, parse_state& state)
799
792
if (type == xml_start_tag)
855
848
if (e && e != asio::error::eof)
857
#ifdef TORRENT_UPNP_LOGGING
858
m_log << time_now_string()
859
<< " <== (" << d.url << ") error while fetching control url: "
860
<< e.message() << std::endl;
851
snprintf(msg, sizeof(msg), "error while fetching control url from: %s: %s"
852
, d.url.c_str(), e.message().c_str());
862
854
d.disabled = true;
866
858
if (!p.header_finished())
868
#ifdef TORRENT_UPNP_LOGGING
869
m_log << time_now_string()
870
<< " <== (" << d.url << ") error while fetching control url: incomplete http message" << std::endl;
861
snprintf(msg, sizeof(msg), "error while fetching control url from: %s: incomplete HTTP message"
872
864
d.disabled = true;
876
868
if (p.status_code() != 200)
878
#ifdef TORRENT_UPNP_LOGGING
879
m_log << time_now_string()
880
<< " <== (" << d.url << ") error while fetching control url: " << p.message() << std::endl;
871
snprintf(msg, sizeof(msg), "error while fetching control url from: %s: %s"
872
, d.url.c_str(), p.message().c_str());
882
874
d.disabled = true;
930
921
std::string protocol;
931
922
std::string auth;
933
924
if (!d.control_url.empty() && d.control_url[0] == '/')
935
boost::tie(protocol, auth, d.hostname, d.port, d.path, error)
936
= parse_url_components(d.url);
926
boost::tie(protocol, auth, d.hostname, d.port, d.path)
927
= parse_url_components(d.url, ec);
937
928
d.control_url = protocol + "://" + d.hostname + ":"
938
929
+ to_string(d.port).elems + s.control_url;
941
#ifdef TORRENT_UPNP_LOGGING
942
m_log << time_now_string()
943
<< " <== (" << d.url << ") Rootdevice response, found control URL: " << d.control_url
944
<< " urlbase: " << s.url_base << " namespace: " << d.service_namespace << std::endl;
947
boost::tie(protocol, auth, d.hostname, d.port, d.path, error)
948
= parse_url_components(d.control_url);
933
snprintf(msg, sizeof(msg), "found control URL: %s namespace %s "
934
"urlbase: %s in response from %s"
935
, d.control_url.c_str(), d.service_namespace
936
, s.url_base.c_str(), d.url.c_str());
939
boost::tie(protocol, auth, d.hostname, d.port, d.path)
940
= parse_url_components(d.control_url, ec);
952
#ifdef TORRENT_UPNP_LOGGING
953
m_log << time_now_string()
954
<< " *** Failed to parse URL '" << d.control_url << "': " << error << std::endl;
945
snprintf(msg, sizeof(msg), "failed to parse URL '%s': %s"
946
, d.control_url.c_str(), ec.message().c_str());
956
948
d.disabled = true;
960
if (num_mappings() > 0) update_map(d, 0);
952
if (num_mappings() > 0) update_map(d, 0, l);
963
void upnp::disable(char const* msg)
955
void upnp::disable(error_code const& ec, mutex_t::scoped_lock& l)
965
957
m_disabled = true;
971
963
if (i->protocol == none) continue;
972
964
i->protocol = none;
973
m_callback(i - m_mappings.begin(), 0, msg);
966
m_callback(i - m_mappings.begin(), 0, ec);
976
// m_devices.clear();
978
m_broadcast_timer.cancel(ec);
979
m_refresh_timer.cancel(ec);
970
// we cannot clear the devices since there
971
// might be outstanding requests relying on
972
// the device entry being present when they
975
m_broadcast_timer.cancel(e);
976
m_refresh_timer.cancel(e);
980
977
m_socket.close();
1016
1010
error_code_t error_codes[] =
1018
{402, "Invalid Arguments"}
1013
, {402, "Invalid Arguments"}
1019
1014
, {501, "Action Failed"}
1020
1015
, {714, "The specified value does not exist in the array"}
1021
1016
, {715, "The source IP address cannot be wild-carded"}
1030
#if BOOST_VERSION >= 103500
1033
const char* upnp_error_category::name() const
1035
return "UPnP error";
1038
std::string upnp_error_category::message(int ev) const
1040
int num_errors = sizeof(error_codes) / sizeof(error_codes[0]);
1041
error_code_t* end = error_codes + num_errors;
1042
error_code_t tmp = {ev, 0};
1043
error_code_t* e = std::lower_bound(error_codes, end, tmp
1044
, bind(&error_code_t::code, _1) < bind(&error_code_t::code, _2));
1045
if (e != end && e->code == ev)
1049
return "unknown UPnP error";
1052
namespace libtorrent
1054
TORRENT_EXPORT upnp_error_category upnp_category;
1059
namespace libtorrent
1061
TORRENT_EXPORT ::asio::error::error_category upnp_category(21);
1035
1066
void upnp::on_upnp_map_response(error_code const& e
1036
1067
, libtorrent::http_parser const& p, rootdevice& d, int mapping
1037
1068
, http_connection& c)
1093
1121
xml_parse((char*)p.get_body().begin, (char*)p.get_body().end
1094
1122
, bind(&find_error_code, _1, _2, boost::ref(s)));
1096
#ifdef TORRENT_UPNP_LOGGING
1097
1124
if (s.error_code != -1)
1099
m_log << time_now_string()
1100
<< " <== got error message: " << s.error_code << std::endl;
1127
snprintf(msg, sizeof(msg), "error while adding port map, code: %u"
1104
1132
mapping_t& m = d.mapping[mapping];
1133
1161
m.external_port = 40000 + (std::rand() % 10000);
1134
1162
m.action = mapping_t::action_add;
1136
update_map(d, mapping);
1164
update_map(d, mapping, l);
1139
1167
else if (s.error_code != -1)
1141
return_error(mapping, s.error_code);
1169
return_error(mapping, s.error_code, l);
1144
#ifdef TORRENT_UPNP_LOGGING
1145
m_log << time_now_string()
1146
<< " <== map response: " << std::string(p.get_body().begin, p.get_body().end)
1173
snprintf(msg, sizeof(msg), "map response: %s"
1174
, std::string(p.get_body().begin, p.get_body().end).c_str());
1150
1177
if (s.error_code == -1)
1152
m_callback(mapping, m.external_port, "");
1180
m_callback(mapping, m.external_port, error_code());
1153
1182
if (d.lease_duration > 0)
1155
1184
m.expires = time_now()
1208
1239
if (e && e != asio::error::eof)
1210
#ifdef TORRENT_UPNP_LOGGING
1211
m_log << time_now_string()
1212
<< " <== error while deleting portmap: " << e.message() << std::endl;
1214
} else if (!p.header_finished())
1242
snprintf(msg, sizeof(msg), "error while deleting portmap: %s", e.message().c_str());
1245
else if (!p.header_finished())
1216
#ifdef TORRENT_UPNP_LOGGING
1217
m_log << time_now_string()
1218
<< " <== error while deleting portmap: incomplete http message" << std::endl;
1247
log("error while deleting portmap: incomplete http message", l);
1221
1249
else if (p.status_code() != 200)
1223
#ifdef TORRENT_UPNP_LOGGING
1224
m_log << time_now_string()
1225
<< " <== error while deleting portmap: " << p.message() << std::endl;
1252
snprintf(msg, sizeof(msg), "error while deleting portmap: %s", p.message().c_str());
1231
#ifdef TORRENT_UPNP_LOGGING
1232
m_log << time_now_string()
1233
<< " <== unmap response: " << std::string(p.get_body().begin, p.get_body().end)
1258
snprintf(msg, sizeof(msg), "unmap response: %s"
1259
, std::string(p.get_body().begin, p.get_body().end).c_str());
1238
1263
d.mapping[mapping].protocol = none;
1265
next(d, mapping, l);
1243
1268
void upnp::on_expire(error_code const& e)