3
Copyright (c) 2008, Arvid Norberg
6
Redistribution and use in source and binary forms, with or without
7
modification, are permitted provided that the following conditions
10
* Redistributions of source code must retain the above copyright
11
notice, this list of conditions and the following disclaimer.
12
* Redistributions in binary form must reproduce the above copyright
13
notice, this list of conditions and the following disclaimer in
14
the documentation and/or other materials provided with the distribution.
15
* Neither the name of the author nor the names of its
16
contributors may be used to endorse or promote products derived
17
from this software without specific prior written permission.
19
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
POSSIBILITY OF SUCH DAMAGE.
33
#include "libtorrent/upnp.hpp"
34
#include "libtorrent/socket.hpp"
35
#include "libtorrent/connection_queue.hpp"
37
#include "setup_transfer.hpp"
39
#include <boost/bind.hpp>
40
#include <boost/ref.hpp>
41
#include <boost/intrusive_ptr.hpp>
43
using namespace libtorrent;
45
broadcast_socket* sock = 0;
54
"<URLBase>http://127.0.0.1:%d</URLBase>"
57
"urn:schemas-upnp-org:device:InternetGatewayDevice:1"
59
"<presentationURL>http://192.168.0.1:80</presentationURL>"
60
"<friendlyName>D-Link Router</friendlyName>"
61
"<manufacturer>D-Link</manufacturer>"
62
"<manufacturerURL>http://www.dlink.com</manufacturerURL>"
63
"<modelDescription>Internet Access Router</modelDescription>"
64
"<modelName>D-Link Router</modelName>"
65
"<UDN>uuid:upnp-InternetGatewayDevice-1_0-12345678900001</UDN>"
66
"<UPC>123456789001</UPC>"
69
"<serviceType>urn:schemas-upnp-org:service:Layer3Forwarding:1</serviceType>"
70
"<serviceId>urn:upnp-org:serviceId:L3Forwarding1</serviceId>"
71
"<controlURL>/Layer3Forwarding</controlURL>"
72
"<eventSubURL>/Layer3Forwarding</eventSubURL>"
73
"<SCPDURL>/Layer3Forwarding.xml</SCPDURL>"
78
"<deviceType>urn:schemas-upnp-org:device:WANDevice:1</deviceType>"
79
"<friendlyName>WANDevice</friendlyName>"
80
"<manufacturer>D-Link</manufacturer>"
81
"<manufacturerURL>http://www.dlink.com</manufacturerURL>"
82
"<modelDescription>Internet Access Router</modelDescription>"
83
"<modelName>D-Link Router</modelName>"
84
"<modelNumber>1</modelNumber>"
85
"<modelURL>http://support.dlink.com</modelURL>"
86
"<serialNumber>12345678900001</serialNumber>"
87
"<UDN>uuid:upnp-WANDevice-1_0-12345678900001</UDN>"
88
"<UPC>123456789001</UPC>"
92
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"
94
"<serviceId>urn:upnp-org:serviceId:WANCommonInterfaceConfig</serviceId>"
95
"<controlURL>/WANCommonInterfaceConfig</controlURL>"
96
"<eventSubURL>/WANCommonInterfaceConfig</eventSubURL>"
97
"<SCPDURL>/WANCommonInterfaceConfig.xml</SCPDURL>"
102
"<deviceType>urn:schemas-upnp-org:device:WANConnectionDevice:1</deviceType>"
103
"<friendlyName>WAN Connection Device</friendlyName>"
104
"<manufacturer>D-Link</manufacturer>"
105
"<manufacturerURL>http://www.dlink.com</manufacturerURL>"
106
"<modelDescription>Internet Access Router</modelDescription>"
107
"<modelName>D-Link Router</modelName>"
108
"<modelNumber>1</modelNumber>"
109
"<modelURL>http://support.dlink.com</modelURL>"
110
"<serialNumber>12345678900001</serialNumber>"
111
"<UDN>uuid:upnp-WANConnectionDevice-1_0-12345678900001</UDN>"
112
"<UPC>123456789001</UPC>"
115
"<serviceType>urn:schemas-upnp-org:service:WANIPConnection:1</serviceType>"
116
"<serviceId>urn:upnp-org:serviceId:WANIPConnection</serviceId>"
117
"<controlURL>/WANIPConnection</controlURL>"
118
"<eventSubURL>/WANIPConnection</eventSubURL>"
119
"<SCPDURL>/WANIPConnection.xml</SCPDURL>"
129
char soap_add_response[] =
130
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
131
"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
132
"<s:Body><u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">"
133
"</u:AddPortMapping></s:Body></s:Envelope>";
135
char soap_delete_response[] =
136
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
137
"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
138
"<s:Body><u:DeletePortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">"
139
"</u:DeletePortMapping></s:Body></s:Envelope>";
141
void incoming_msearch(udp::endpoint const& from, char* buffer
146
p.incoming(buffer::const_interval(buffer, buffer + size), error);
147
if (error || !p.header_finished())
149
std::cerr << "*** malformed HTTP from " << from << std::endl;
153
if (p.method() != "m-search") return;
155
std::cerr << "< incoming m-search from " << from << std::endl;
157
char msg[] = "HTTP/1.1 200 OK\r\n"
158
"ST:upnp:rootdevice\r\n"
159
"USN:uuid:000f-66d6-7296000099dc::upnp:rootdevice\r\n"
160
"Location: http://127.0.0.1:%d/upnp.xml\r\n"
161
"Server: Custom/1.0 UPnP/1.0 Proc/Ver\r\n"
163
"Cache-Control:max-age=180\r\n"
164
"DATE: Fri, 02 Jan 1970 08:10:38 GMT\r\n\r\n";
166
TORRENT_ASSERT(g_port != 0);
167
char buf[sizeof(msg) + 30];
168
int len = snprintf(buf, sizeof(buf), msg, g_port);
171
sock->send(buf, len, ec);
173
if (ec) std::cerr << "*** error sending " << ec.message() << std::endl;
176
void log_callback(char const* err)
178
std::cerr << "UPnP: " << err << std::endl;
179
//TODO: store the log and verify that some key messages are there
187
bool operator==(callback_info const& e)
188
{ return mapping == e.mapping && port == e.port && !ec == !e.ec; }
191
std::list<callback_info> callbacks;
193
void callback(int mapping, int port, error_code const& err)
195
callback_info info = {mapping, port, err};
196
callbacks.push_back(info);
197
std::cerr << "mapping: " << mapping << ", port: " << port
198
<< ", error: \"" << err.message() << "\"\n";
199
//TODO: store the callbacks and verify that the ports were successful
204
libtorrent::io_service ios;
206
g_port = start_web_server();
207
FILE* xml_file = fopen("upnp.xml", "w+");
208
fprintf(xml_file, upnp_xml, g_port);
211
std::ofstream xml("WANIPConnection", std::ios::trunc);
212
xml.write(soap_add_response, sizeof(soap_add_response)-1);
215
sock = new broadcast_socket(ios, udp::endpoint(address_v4::from_string("239.255.255.250"), 1900)
216
, &incoming_msearch);
218
std::string user_agent = "test agent";
220
connection_queue cc(ios);
221
boost::intrusive_ptr<upnp> upnp_handler = new upnp(ios, cc, address_v4::from_string("127.0.0.1")
222
, user_agent, &callback, &log_callback, false);
223
upnp_handler->discover_device();
225
libtorrent::deadline_timer timer(ios);
227
timer.expires_from_now(seconds(10), ec);
228
timer.async_wait(boost::bind(&libtorrent::io_service::stop, boost::ref(ios)));
233
int mapping1 = upnp_handler->add_mapping(upnp::tcp, 500, 500);
234
int mapping2 = upnp_handler->add_mapping(upnp::udp, 501, 501);
235
timer.expires_from_now(seconds(10), ec);
236
timer.async_wait(boost::bind(&libtorrent::io_service::stop, boost::ref(ios)));
241
xml.open("WANIPConnection", std::ios::trunc);
242
xml.write(soap_delete_response, sizeof(soap_delete_response)-1);
245
std::cerr << "router: " << upnp_handler->router_model() << std::endl;
246
TEST_CHECK(upnp_handler->router_model() == "D-Link Router");
247
upnp_handler->close();
253
callback_info expected1 = {mapping1, 500, error_code()};
254
callback_info expected2 = {mapping2, 501, error_code()};
255
TEST_CHECK(std::count(callbacks.begin(), callbacks.end(), expected1) == 1);
256
TEST_CHECK(std::count(callbacks.begin(), callbacks.end(), expected2) == 1);