Mercurial > pidgin.yaz
annotate src/upnp.c @ 12547:a25bdcad6b21
[gaim-migrate @ 14865]
La la la la laaaaaaa, little birdies
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Sun, 18 Dec 2005 15:22:58 +0000 |
parents | 201be1b681a4 |
children | 0f499f27b29a |
rev | line source |
---|---|
11195 | 1 /** |
2 * @file upnp.c UPnP Implementation | |
3 * @ingroup core | |
4 * | |
5 * gaim | |
6 * | |
7 * Gaim is the legal property of its developers, whose names are too numerous | |
8 * to list here. Please refer to the COPYRIGHT file distributed with this | |
9 * source distribution. | |
10 * | |
11 * This program is free software; you can redistribute it and/or modify | |
12 * it under the terms of the GNU General Public License as published by | |
13 * the Free Software Foundation; either version 2 of the License, or | |
14 * (at your option) any later version. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
24 */ | |
25 #include "internal.h" | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
26 #include "gaim.h" |
11195 | 27 |
28 #include "debug.h" | |
11391 | 29 #include "util.h" |
30 #include "proxy.h" | |
31 #include "xmlnode.h" | |
11195 | 32 #include "network.h" |
33 #include "eventloop.h" | |
34 #include "upnp.h" | |
35 | |
36 | |
37 /** | |
38 * Information on the httpResponse callback | |
39 */ | |
40 typedef struct | |
41 { | |
42 guint inpa; /* gaim_input_add handle */ | |
43 guint tima; /* gaim_timout_add handle */ | |
11391 | 44 gchar* sendBuffer; /* send data */ |
45 gchar* recvBuffer; /* response data */ | |
11195 | 46 guint totalSizeRecv; |
47 gboolean done; | |
48 | |
11391 | 49 } NetResponseData; |
11195 | 50 |
51 | |
52 /*************************************************************** | |
53 ** General Defines * | |
54 ****************************************************************/ | |
55 #define HTTP_OK "200 OK" | |
11391 | 56 #define DEFAULT_HTTP_PORT 80 |
57 #define MAX_PORT_SIZE 6 | |
58 #define SIZEOF_HTTP 7 /* size of "http://" string */ | |
11492 | 59 #define RECEIVE_TIMEOUT 10000 |
60 #define CONSECUTIVE_RECEIVE_TIMEOUT 500 | |
11195 | 61 #define DISCOVERY_TIMEOUT 1000 |
62 | |
63 | |
64 /*************************************************************** | |
65 ** Discovery/Description Defines * | |
66 ****************************************************************/ | |
67 #define NUM_UDP_ATTEMPTS 2 | |
68 | |
69 /* Address and port of an SSDP request used for discovery */ | |
70 #define HTTPMU_HOST_ADDRESS "239.255.255.250" | |
71 #define HTTPMU_HOST_PORT 1900 | |
72 | |
73 #define SEARCH_REQUEST_DEVICE "urn:schemas-upnp-org:service:" \ | |
11391 | 74 "%s" |
11195 | 75 |
76 #define SEARCH_REQUEST_STRING "M-SEARCH * HTTP/1.1\r\n" \ | |
77 "MX: 2\r\n" \ | |
78 "HOST: 239.255.255.250:1900\r\n" \ | |
79 "MAN: \"ssdp:discover\"\r\n" \ | |
80 "ST: urn:schemas-upnp-org:service:" \ | |
11391 | 81 "%s\r\n" \ |
11195 | 82 "\r\n" |
83 | |
11492 | 84 #define MAX_DISCOVERY_RECEIVE_SIZE 400 |
85 #define MAX_DESCRIPTION_RECEIVE_SIZE 7000 | |
11195 | 86 #define MAX_DESCRIPTION_HTTP_HEADER_SIZE 100 |
87 | |
88 | |
89 /****************************************************************** | |
90 ** Action Defines * | |
91 *******************************************************************/ | |
11391 | 92 #define HTTP_HEADER_ACTION "POST /%s HTTP/1.1\r\n" \ |
11195 | 93 "HOST: %s\r\n" \ |
94 "SOAPACTION: " \ | |
95 "\"urn:schemas-upnp-org:" \ | |
96 "service:%s#%s\"\r\n" \ | |
97 "CONTENT-TYPE: text/xml ; charset=\"utf-8\"\r\n"\ | |
11656
f9c5480ad0ce
[gaim-migrate @ 13940]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
98 "Content-Length: %" G_GSIZE_FORMAT "\r\n\r\n" |
11195 | 99 |
100 #define SOAP_ACTION "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" \ | |
101 "<s:Envelope xmlns:s=" \ | |
102 "\"http://schemas.xmlsoap.org/soap/envelope/\" " \ | |
103 "s:encodingStyle=" \ | |
104 "\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n" \ | |
105 "<s:Body>\r\n" \ | |
106 "<u:%s xmlns:u=" \ | |
107 "\"urn:schemas-upnp-org:service:%s\">\r\n%s" \ | |
108 "</u:%s>\r\n" \ | |
109 "</s:Body>\r\n" \ | |
110 "</s:Envelope>\r\n" | |
111 | |
112 #define PORT_MAPPING_LEASE_TIME "0" | |
113 #define PORT_MAPPING_DESCRIPTION "GAIM_UPNP_PORT_FORWARD" | |
114 | |
115 #define ADD_PORT_MAPPING_PARAMS "<NewRemoteHost></NewRemoteHost>\r\n" \ | |
116 "<NewExternalPort>%i</NewExternalPort>\r\n"\ | |
117 "<NewProtocol>%s</NewProtocol>\r\n" \ | |
118 "<NewInternalPort>%i</NewInternalPort>\r\n"\ | |
119 "<NewInternalClient>%s" \ | |
120 "</NewInternalClient>\r\n" \ | |
121 "<NewEnabled>1</NewEnabled>\r\n" \ | |
122 "<NewPortMappingDescription>" \ | |
123 PORT_MAPPING_DESCRIPTION \ | |
124 "</NewPortMappingDescription>\r\n" \ | |
125 "<NewLeaseDuration>" \ | |
126 PORT_MAPPING_LEASE_TIME \ | |
127 "</NewLeaseDuration>\r\n" | |
128 | |
129 #define DELETE_PORT_MAPPING_PARAMS "<NewRemoteHost></NewRemoteHost>\r\n" \ | |
130 "<NewExternalPort>%i" \ | |
131 "</NewExternalPort>\r\n" \ | |
132 "<NewProtocol>%s</NewProtocol>\r\n" | |
133 | |
134 | |
135 static void | |
136 gaim_upnp_timeout(gpointer data, | |
11213 | 137 gint source, |
11195 | 138 GaimInputCondition cond) |
139 { | |
11391 | 140 NetResponseData* nrd = data; |
11195 | 141 |
11391 | 142 gaim_input_remove(nrd->inpa); |
143 gaim_timeout_remove(nrd->tima); | |
11195 | 144 |
11391 | 145 if(nrd->totalSizeRecv == 0 && nrd->recvBuffer != NULL) { |
146 g_free(nrd->recvBuffer); | |
147 nrd->recvBuffer = NULL; | |
148 } else if(nrd->recvBuffer != NULL) { | |
149 nrd->recvBuffer[nrd->totalSizeRecv] = '\0'; | |
11195 | 150 } |
151 | |
11391 | 152 nrd->done = TRUE; |
11195 | 153 } |
154 | |
155 | |
156 static void | |
157 gaim_upnp_http_read(gpointer data, | |
158 gint sock, | |
159 GaimInputCondition cond) | |
160 { | |
161 int sizeRecv; | |
11391 | 162 NetResponseData* nrd = data; |
11195 | 163 |
11391 | 164 sizeRecv = recv(sock, &(nrd->recvBuffer[nrd->totalSizeRecv]), |
11492 | 165 MAX_DESCRIPTION_RECEIVE_SIZE-nrd->totalSizeRecv, 0); |
11195 | 166 if(sizeRecv < 0 && errno != EINTR) { |
11391 | 167 gaim_debug_error("upnp", |
11195 | 168 "gaim_upnp_http_read(): recv < 0: %i!\n\n", errno); |
11391 | 169 g_free(nrd->recvBuffer); |
170 nrd->recvBuffer = NULL; | |
171 gaim_timeout_remove(nrd->tima); | |
172 gaim_input_remove(nrd->inpa); | |
173 nrd->done = TRUE; | |
11195 | 174 return; |
175 }else if(errno == EINTR) { | |
176 sizeRecv = 0; | |
177 } | |
11391 | 178 nrd->totalSizeRecv += sizeRecv; |
11195 | 179 |
180 if(sizeRecv == 0) { | |
11391 | 181 gaim_timeout_remove(nrd->tima); |
182 gaim_input_remove(nrd->inpa); | |
183 if(nrd->totalSizeRecv == 0) { | |
184 gaim_debug_error("upnp", | |
11195 | 185 "gaim_upnp_http_read(): totalSizeRecv == 0\n\n"); |
11391 | 186 g_free(nrd->recvBuffer); |
187 nrd->recvBuffer = NULL; | |
11195 | 188 } else { |
11391 | 189 nrd->recvBuffer[nrd->totalSizeRecv] = '\0'; |
11195 | 190 } |
11391 | 191 nrd->done = TRUE; |
11195 | 192 } else { |
11391 | 193 gaim_timeout_remove(nrd->tima); |
194 gaim_input_remove(nrd->inpa); | |
11492 | 195 nrd->tima = gaim_timeout_add(CONSECUTIVE_RECEIVE_TIMEOUT, |
11391 | 196 (GSourceFunc)gaim_upnp_timeout, nrd); |
197 nrd->inpa = gaim_input_add(sock, GAIM_INPUT_READ, | |
198 gaim_upnp_http_read, nrd); | |
11195 | 199 } |
200 } | |
201 | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
202 static void |
11391 | 203 gaim_upnp_http_send(gpointer data, |
204 gint sock, | |
205 GaimInputCondition cond) | |
11195 | 206 { |
11586 | 207 gsize sizeSent, totalSizeSent = 0; |
11391 | 208 NetResponseData* nrd = data; |
11195 | 209 |
11391 | 210 gaim_timeout_remove(nrd->tima); |
211 while(totalSizeSent < strlen(nrd->sendBuffer)) { | |
11586 | 212 sizeSent = send(sock,(gchar*)(nrd->sendBuffer+totalSizeSent), |
11391 | 213 strlen(nrd->sendBuffer)-totalSizeSent,0); |
11195 | 214 if(sizeSent <= 0 && errno != EINTR) { |
11391 | 215 gaim_debug_error("upnp", |
11195 | 216 "gaim_upnp_http_request(): Failed In send\n\n"); |
11391 | 217 nrd->done = TRUE; |
218 g_free(nrd->recvBuffer); | |
219 nrd->recvBuffer = NULL; | |
11195 | 220 close(sock); |
11391 | 221 return; |
11195 | 222 }else if(errno == EINTR) { |
223 sizeSent = 0; | |
224 } | |
225 totalSizeSent += sizeSent; | |
226 } | |
227 | |
11492 | 228 nrd->tima = gaim_timeout_add(RECEIVE_TIMEOUT, |
11391 | 229 (GSourceFunc)gaim_upnp_timeout, nrd); |
230 nrd->inpa = gaim_input_add(sock, GAIM_INPUT_READ, | |
231 gaim_upnp_http_read, nrd); | |
232 while (!nrd->done) { | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
233 g_main_context_iteration(NULL, TRUE); |
11195 | 234 } |
235 close(sock); | |
11391 | 236 } |
11195 | 237 |
11391 | 238 static gchar* |
239 gaim_upnp_http_request(const gchar* address, | |
240 int port, | |
241 gchar* httpRequest) | |
242 { | |
243 gchar* recvBuffer; | |
244 NetResponseData* nrd = (NetResponseData*)g_malloc0(sizeof(NetResponseData)); | |
245 nrd->sendBuffer = httpRequest; | |
11492 | 246 nrd->recvBuffer = (gchar*)g_malloc(MAX_DESCRIPTION_RECEIVE_SIZE); |
11391 | 247 |
11492 | 248 nrd->tima = gaim_timeout_add(RECEIVE_TIMEOUT, |
11391 | 249 (GSourceFunc)gaim_upnp_timeout, nrd); |
250 | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
251 if(gaim_proxy_connect(NULL, address, port, |
11391 | 252 gaim_upnp_http_send, nrd)) { |
253 | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
254 gaim_debug_error("upnp", "Connect Failed: Address: %s @@@ Port %d @@@ Request %s\n\n", |
11391 | 255 address, port, nrd->sendBuffer); |
256 | |
257 gaim_timeout_remove(nrd->tima); | |
258 g_free(nrd->recvBuffer); | |
259 nrd->recvBuffer = NULL; | |
260 } else { | |
261 while (!nrd->done) { | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
262 g_main_context_iteration(NULL, TRUE); |
11391 | 263 } |
264 } | |
265 | |
266 recvBuffer = nrd->recvBuffer; | |
267 g_free(nrd); | |
268 | |
11195 | 269 return recvBuffer; |
270 } | |
271 | |
272 | |
273 | |
11391 | 274 static gboolean |
275 gaim_upnp_compare_device(const xmlnode* device, | |
276 const gchar* deviceType) | |
277 { | |
278 xmlnode* deviceTypeNode = xmlnode_get_child(device, "deviceType"); | |
279 if(deviceTypeNode == NULL) { | |
280 return FALSE; | |
281 } | |
282 return !g_ascii_strcasecmp(xmlnode_get_data(deviceTypeNode), deviceType); | |
283 } | |
11195 | 284 |
11391 | 285 |
286 static gboolean | |
287 gaim_upnp_compare_service(const xmlnode* service, | |
288 const gchar* serviceType) | |
11195 | 289 { |
11391 | 290 xmlnode* serviceTypeNode = xmlnode_get_child(service, "serviceType"); |
291 if(serviceTypeNode == NULL) { | |
292 return FALSE; | |
293 } | |
294 return !g_ascii_strcasecmp(xmlnode_get_data(serviceTypeNode), serviceType); | |
295 } | |
296 | |
297 | |
11195 | 298 |
11391 | 299 static gchar* |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
300 gaim_upnp_parse_description_response(const gchar* httpResponse, |
11391 | 301 const gchar* httpURL, |
302 const gchar* serviceType) | |
303 { | |
304 gchar* xmlRoot; | |
305 gchar* baseURL; | |
306 gchar* controlURL; | |
307 gchar* service; | |
308 xmlnode* xmlRootNode; | |
309 xmlnode* serviceTypeNode; | |
310 xmlnode* controlURLNode; | |
311 xmlnode* baseURLNode; | |
312 | |
313 /* make sure we have a valid http response */ | |
314 if(g_strstr_len(httpResponse, strlen(httpResponse), HTTP_OK) == NULL) { | |
315 gaim_debug_error("upnp", | |
11195 | 316 "parse_description_response(): Failed In HTTP_OK\n\n"); |
317 return NULL; | |
318 } | |
319 | |
11391 | 320 /* find the root of the xml document */ |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
321 if((xmlRoot = g_strstr_len(httpResponse, strlen(httpResponse), |
11391 | 322 "<root")) == NULL) { |
323 gaim_debug_error("upnp", | |
324 "parse_description_response(): Failed finding root\n\n"); | |
325 return NULL; | |
326 } | |
327 | |
328 /* create the xml root node */ | |
329 if((xmlRootNode = xmlnode_from_str(xmlRoot, -1)) == NULL) { | |
330 gaim_debug_error("upnp", | |
331 "parse_description_response(): Could not parse xml root node\n\n"); | |
11195 | 332 return NULL; |
333 } | |
11391 | 334 |
335 /* get the baseURL of the device */ | |
336 if((baseURLNode = xmlnode_get_child(xmlRootNode, | |
337 "URLBase")) != NULL) { | |
338 baseURL = g_strdup(xmlnode_get_data(baseURLNode)); | |
339 } else { | |
340 baseURL = g_strdup(httpURL); | |
341 } | |
342 | |
343 /* get the serviceType child that has the service type as it's data */ | |
344 | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
345 /* get urn:schemas-upnp-org:device:InternetGatewayDevice:1 |
11391 | 346 and it's devicelist */ |
347 serviceTypeNode = xmlnode_get_child(xmlRootNode, "device"); | |
348 while(!gaim_upnp_compare_device(serviceTypeNode, | |
349 "urn:schemas-upnp-org:device:InternetGatewayDevice:1") && | |
350 serviceTypeNode != NULL) { | |
351 serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); | |
352 } | |
353 if(serviceTypeNode == NULL) { | |
354 gaim_debug_error("upnp", | |
355 "parse_description_response(): could not get serviceTypeNode 1\n\n"); | |
11195 | 356 return NULL; |
357 } | |
11391 | 358 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "deviceList"); |
359 if(serviceTypeNode == NULL) { | |
360 gaim_debug_error("upnp", | |
361 "parse_description_response(): could not get serviceTypeNode 2\n\n"); | |
11195 | 362 return NULL; |
363 } | |
364 | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
365 /* get urn:schemas-upnp-org:device:WANDevice:1 |
11391 | 366 and it's devicelist */ |
367 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "device"); | |
368 while(!gaim_upnp_compare_device(serviceTypeNode, | |
369 "urn:schemas-upnp-org:device:WANDevice:1") && | |
370 serviceTypeNode != NULL) { | |
371 serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); | |
372 } | |
373 if(serviceTypeNode == NULL) { | |
374 gaim_debug_error("upnp", | |
375 "parse_description_response(): could not get serviceTypeNode 3\n\n"); | |
376 return NULL; | |
377 } | |
378 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "deviceList"); | |
379 if(serviceTypeNode == NULL) { | |
380 gaim_debug_error("upnp", | |
381 "parse_description_response(): could not get serviceTypeNode 4\n\n"); | |
382 return NULL; | |
383 } | |
11195 | 384 |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
385 /* get urn:schemas-upnp-org:device:WANConnectionDevice:1 |
11391 | 386 and it's servicelist */ |
387 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "device"); | |
388 while(!gaim_upnp_compare_device(serviceTypeNode, | |
389 "urn:schemas-upnp-org:device:WANConnectionDevice:1") && | |
390 serviceTypeNode != NULL) { | |
391 serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); | |
392 } | |
393 if(serviceTypeNode == NULL) { | |
394 gaim_debug_error("upnp", | |
395 "parse_description_response(): could not get serviceTypeNode 5\n\n"); | |
11195 | 396 return NULL; |
397 } | |
11391 | 398 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "serviceList"); |
399 if(serviceTypeNode == NULL) { | |
400 gaim_debug_error("upnp", | |
401 "parse_description_response(): could not get serviceTypeNode 6\n\n"); | |
402 return NULL; | |
403 } | |
11195 | 404 |
11391 | 405 /* get the serviceType variable passed to this function */ |
406 service = g_strdup_printf(SEARCH_REQUEST_DEVICE, serviceType); | |
407 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "service"); | |
408 while(!gaim_upnp_compare_service(serviceTypeNode, service) && | |
409 serviceTypeNode != NULL) { | |
410 serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); | |
11195 | 411 } |
412 | |
11391 | 413 g_free(service); |
414 if(serviceTypeNode == NULL) { | |
415 gaim_debug_error("upnp", | |
416 "parse_description_response(): could not get serviceTypeNode 7\n\n"); | |
417 return NULL; | |
418 } | |
419 | |
420 /* get the controlURL of the service */ | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
421 if((controlURLNode = xmlnode_get_child(serviceTypeNode, |
11391 | 422 "controlURL")) == NULL) { |
423 gaim_debug_error("upnp", | |
424 "parse_description_response(): Could not find controlURL\n\n"); | |
425 return NULL; | |
426 } | |
427 | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
428 if(g_strstr_len(xmlnode_get_data(controlURLNode), |
11391 | 429 SIZEOF_HTTP, "http://") == NULL && |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
430 g_strstr_len(xmlnode_get_data(controlURLNode), |
11391 | 431 SIZEOF_HTTP, "HTTP://") == NULL) { |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
432 controlURL = g_strdup_printf("%s%s", baseURL, |
11391 | 433 xmlnode_get_data(controlURLNode)); |
11195 | 434 }else{ |
11391 | 435 controlURL = g_strdup(xmlnode_get_data(controlURLNode)); |
11195 | 436 } |
11391 | 437 g_free(baseURL); |
438 xmlnode_free(xmlRootNode); | |
11195 | 439 |
440 return controlURL; | |
441 } | |
442 | |
443 | |
11391 | 444 static gchar* |
445 gaim_upnp_parse_description(const gchar* descriptionURL, | |
446 const gchar* serviceType) | |
11195 | 447 { |
11391 | 448 gchar* fullURL; |
449 gchar* controlURL; | |
450 gchar* httpResponse; | |
451 gchar* httpRequest; | |
11195 | 452 |
11391 | 453 gchar* descriptionXMLAddress; |
454 gchar* descriptionAddressPort; | |
455 gchar* descriptionAddress; | |
456 gchar descriptionPort[MAX_PORT_SIZE]; | |
457 int port = 0; | |
11195 | 458 |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
459 /* parse the 4 above variables out of the descriptionURL |
11195 | 460 example description URL: http://192.168.1.1:5678/rootDesc.xml */ |
461 | |
462 /* parse the url into address, port, path variables */ | |
11391 | 463 if(!gaim_url_parse(descriptionURL, &descriptionAddress, |
464 &port, &descriptionXMLAddress, NULL, NULL)) { | |
11195 | 465 return NULL; |
466 } | |
11391 | 467 if(port == 0 || port == -1) { |
468 port = DEFAULT_HTTP_PORT; | |
11195 | 469 } |
11391 | 470 g_ascii_dtostr(descriptionPort, MAX_PORT_SIZE, port); |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
471 descriptionAddressPort = g_strdup_printf("%s:%s", descriptionAddress, |
11391 | 472 descriptionPort); |
11195 | 473 |
11391 | 474 fullURL = g_strdup_printf("http://%s", descriptionAddressPort); |
11195 | 475 |
476 /* for example... | |
477 GET /rootDesc.xml HTTP/1.1\r\nHost: 192.168.1.1:5678\r\n\r\n */ | |
11391 | 478 httpRequest = g_strdup_printf("GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n", |
479 descriptionXMLAddress, descriptionAddressPort); | |
11195 | 480 |
481 httpResponse = gaim_upnp_http_request(descriptionAddress, | |
482 port, httpRequest); | |
483 if(httpResponse == NULL) { | |
11391 | 484 gaim_debug_error("upnp", |
11195 | 485 "gaim_upnp_parse_description(): httpResponse is NULL\n\n"); |
11391 | 486 g_free(descriptionXMLAddress); |
487 g_free(descriptionAddress); | |
488 g_free(descriptionAddressPort); | |
489 g_free(httpRequest); | |
490 g_free(fullURL); | |
11195 | 491 return NULL; |
492 } | |
493 | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
494 controlURL = gaim_upnp_parse_description_response(httpResponse, |
11391 | 495 fullURL, serviceType); |
11195 | 496 |
11391 | 497 g_free(descriptionXMLAddress); |
498 g_free(descriptionAddress); | |
499 g_free(descriptionAddressPort); | |
500 g_free(fullURL); | |
501 g_free(httpRequest); | |
502 g_free(httpResponse); | |
11195 | 503 |
504 if(controlURL == NULL) { | |
11391 | 505 gaim_debug_error("upnp", |
11195 | 506 "gaim_upnp_parse_description(): controlURL is NULL\n\n"); |
507 return NULL; | |
508 } | |
509 | |
510 return controlURL; | |
511 } | |
512 | |
513 | |
11391 | 514 static gchar* |
515 gaim_upnp_parse_discover_response(const gchar* buf, | |
516 unsigned int bufSize, | |
517 const gchar* serviceType) | |
11195 | 518 { |
11391 | 519 gchar* startDescURL; |
520 gchar* endDescURL; | |
521 gchar* descURL; | |
522 gchar* retVal; | |
11195 | 523 |
11391 | 524 if(g_strstr_len(buf, strlen(buf), HTTP_OK) == NULL) { |
525 gaim_debug_error("upnp", | |
11195 | 526 "parse_discover_response(): Failed In HTTP_OK\n\n"); |
527 return NULL; | |
528 } | |
529 | |
11391 | 530 if((startDescURL = g_strstr_len(buf, strlen(buf), "http://")) == NULL) { |
531 gaim_debug_error("upnp", | |
532 "parse_discover_response(): Failed In finding http://\n\n"); | |
11195 | 533 return NULL; |
534 } | |
535 | |
11391 | 536 endDescURL = g_strstr_len(startDescURL, strlen(startDescURL), "\r"); |
11195 | 537 if(endDescURL == NULL) { |
11391 | 538 endDescURL = g_strstr_len(startDescURL, strlen(startDescURL), "\n"); |
11195 | 539 if(endDescURL == NULL) { |
11391 | 540 gaim_debug_error("upnp", |
541 "parse_discover_response(): Failed In endDescURL\n\n"); | |
11195 | 542 return NULL; |
543 }else if(endDescURL == startDescURL) { | |
11391 | 544 gaim_debug_error("upnp", |
545 "parse_discover_response(): endDescURL == startDescURL\n\n"); | |
11195 | 546 return NULL; |
547 } | |
548 }else if(endDescURL == startDescURL) { | |
11391 | 549 gaim_debug_error("upnp", |
550 "parse_discover_response(): 2nd endDescURL == startDescURL\n\n"); | |
11195 | 551 return NULL; |
552 } | |
11391 | 553 descURL = g_strndup(startDescURL, endDescURL-startDescURL); |
11195 | 554 |
11391 | 555 retVal = gaim_upnp_parse_description(descURL, serviceType); |
556 g_free(descURL); | |
11195 | 557 return retVal; |
558 } | |
559 | |
560 | |
561 | |
562 static void | |
563 gaim_upnp_discover_udp_read(gpointer data, | |
564 gint sock, | |
565 GaimInputCondition cond) | |
566 { | |
567 unsigned int length; | |
568 struct sockaddr_in from; | |
569 int sizeRecv; | |
11391 | 570 NetResponseData* nrd = data; |
11195 | 571 |
11391 | 572 gaim_timeout_remove(nrd->tima); |
11195 | 573 length = sizeof(struct sockaddr_in); |
574 | |
575 do { | |
11391 | 576 sizeRecv = recvfrom(sock, nrd->recvBuffer, |
11492 | 577 MAX_DISCOVERY_RECEIVE_SIZE, 0, |
11195 | 578 (struct sockaddr*)&from, &length); |
579 | |
580 if(sizeRecv > 0) { | |
11391 | 581 nrd->recvBuffer[sizeRecv] = '\0'; |
11195 | 582 }else if(errno != EINTR) { |
11391 | 583 g_free(nrd->recvBuffer); |
584 nrd->recvBuffer = NULL; | |
11195 | 585 } |
586 }while(errno == EINTR); | |
587 | |
11391 | 588 gaim_input_remove(nrd->inpa); |
589 nrd->done = TRUE; | |
11195 | 590 return; |
591 } | |
592 | |
593 | |
11213 | 594 |
11391 | 595 GaimUPnPControlInfo* |
11195 | 596 gaim_upnp_discover(void) |
597 { | |
11391 | 598 /* Socket Setup Variables */ |
11195 | 599 int sock, i; |
600 struct sockaddr_in server; | |
11391 | 601 struct hostent* hp; |
11195 | 602 |
11391 | 603 /* UDP SEND VARIABLES */ |
604 gboolean sentSuccess, recvSuccess; | |
12207
201be1b681a4
[gaim-migrate @ 14509]
Richard Laager <rlaager@wiktel.com>
parents:
11656
diff
changeset
|
605 ssize_t sizeSent; |
201be1b681a4
[gaim-migrate @ 14509]
Richard Laager <rlaager@wiktel.com>
parents:
11656
diff
changeset
|
606 ssize_t totalSizeSent; |
11391 | 607 gchar wanIP[] = "WANIPConnection:1"; |
608 gchar wanPPP[] = "WANPPPConnection:1"; | |
609 gchar* serviceToUse; | |
610 gchar* sendMessage = NULL; | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
611 |
11492 | 612 /* UDP RECEIVE VARIABLES */ |
11391 | 613 GaimUPnPControlInfo* controlInfo = g_malloc(sizeof(GaimUPnPControlInfo)); |
614 NetResponseData* nrd = g_malloc(sizeof(NetResponseData)); | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
615 |
11391 | 616 /* Set up the sockets */ |
11195 | 617 sock = socket(AF_INET, SOCK_DGRAM, 0); |
618 if (sock == -1) { | |
619 close(sock); | |
11391 | 620 gaim_debug_error("upnp", |
11195 | 621 "gaim_upnp_discover(): Failed In sock creation\n\n"); |
11391 | 622 g_free(nrd); |
623 g_free(controlInfo); | |
11195 | 624 return NULL; |
625 } | |
626 memset(&server, 0, sizeof(struct sockaddr)); | |
627 server.sin_family = AF_INET; | |
628 if((hp = gethostbyname(HTTPMU_HOST_ADDRESS)) == NULL) { | |
629 close(sock); | |
11391 | 630 gaim_debug_error("upnp", |
11195 | 631 "gaim_upnp_discover(): Failed In gethostbyname\n\n"); |
11391 | 632 g_free(nrd); |
633 g_free(controlInfo); | |
11195 | 634 return NULL; |
635 } | |
636 memcpy(&server.sin_addr, | |
637 hp->h_addr_list[0], | |
638 hp->h_length); | |
639 server.sin_port = htons(HTTPMU_HOST_PORT); | |
640 | |
641 /* because we are sending over UDP, if there is a failure | |
11391 | 642 we should retry the send NUM_UDP_ATTEMPTS times. Also, |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
643 try different requests for WANIPConnection and |
11391 | 644 WANPPPConnection*/ |
11195 | 645 for(i = 0; i < NUM_UDP_ATTEMPTS; i++) { |
646 sentSuccess = TRUE; | |
647 recvSuccess = TRUE; | |
648 totalSizeSent = 0; | |
649 | |
11391 | 650 nrd->recvBuffer = NULL; |
651 nrd->totalSizeRecv = 0; | |
652 nrd->done = FALSE; | |
653 | |
654 if(sendMessage != NULL) { | |
655 g_free(sendMessage); | |
656 } | |
11213 | 657 |
11391 | 658 if(i%2 == 0) { |
659 serviceToUse = wanIP; | |
660 } else { | |
661 serviceToUse = wanPPP; | |
11213 | 662 } |
11391 | 663 sendMessage = g_strdup_printf(SEARCH_REQUEST_STRING, serviceToUse); |
664 | |
11492 | 665 nrd->recvBuffer = (char*)g_malloc(MAX_DISCOVERY_RECEIVE_SIZE); |
11213 | 666 |
12207
201be1b681a4
[gaim-migrate @ 14509]
Richard Laager <rlaager@wiktel.com>
parents:
11656
diff
changeset
|
667 while(totalSizeSent < (ssize_t)strlen(sendMessage)) { |
11195 | 668 sizeSent = sendto(sock,(void*)&sendMessage[totalSizeSent], |
669 strlen(&sendMessage[totalSizeSent]),0, | |
670 (struct sockaddr*)&server, | |
671 sizeof(struct sockaddr_in)); | |
672 if(sizeSent <= 0 && errno != EINTR) { | |
673 sentSuccess = FALSE; | |
674 break; | |
675 }else if(errno == EINTR) { | |
676 sizeSent = 0; | |
677 } | |
678 totalSizeSent += sizeSent; | |
679 } | |
680 | |
681 if(sentSuccess) { | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
682 nrd->tima = gaim_timeout_add(DISCOVERY_TIMEOUT, |
11391 | 683 (GSourceFunc)gaim_upnp_timeout, nrd); |
684 nrd->inpa = gaim_input_add(sock, GAIM_INPUT_READ, | |
685 gaim_upnp_discover_udp_read, nrd); | |
686 while (!nrd->done) { | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
687 g_main_context_iteration(NULL, TRUE); |
11195 | 688 } |
11391 | 689 if(nrd->recvBuffer == NULL) { |
11195 | 690 recvSuccess = FALSE; |
691 } else { | |
692 /* parse the response, and see if it was a success */ | |
693 close(sock); | |
11391 | 694 if((controlInfo->controlURL= |
695 gaim_upnp_parse_discover_response(nrd->recvBuffer, | |
696 strlen(nrd->recvBuffer), | |
697 serviceToUse))==NULL) { | |
698 gaim_debug_error("upnp", | |
11195 | 699 "gaim_upnp_discover(): Failed In parse response\n\n"); |
11391 | 700 g_free(nrd->recvBuffer); |
701 g_free(nrd); | |
702 g_free(controlInfo); | |
11195 | 703 return NULL; |
704 } | |
11391 | 705 |
706 controlInfo->serviceType = g_strdup(serviceToUse); | |
11195 | 707 } |
708 } | |
709 | |
710 /* if sent success and recv successful, then break */ | |
711 if(sentSuccess && recvSuccess) { | |
712 i = NUM_UDP_ATTEMPTS; | |
713 } | |
714 } | |
11213 | 715 |
11391 | 716 if(nrd->recvBuffer != NULL) { |
717 g_free(nrd->recvBuffer); | |
11213 | 718 } |
11391 | 719 g_free(sendMessage); |
720 g_free(nrd); | |
11213 | 721 |
11195 | 722 if(!sentSuccess || !recvSuccess) { |
723 close(sock); | |
11391 | 724 gaim_debug_error("upnp", |
11195 | 725 "gaim_upnp_discover(): Failed In sent/recv success\n\n"); |
11391 | 726 g_free(controlInfo); |
11195 | 727 return NULL; |
728 } | |
729 | |
11391 | 730 return controlInfo; |
11195 | 731 } |
732 | |
733 | |
734 static char* | |
11391 | 735 gaim_upnp_generate_action_message_and_send(const GaimUPnPControlInfo* controlInfo, |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
736 const gchar* actionName, |
11391 | 737 const gchar* actionParams) |
11195 | 738 { |
11391 | 739 gchar* actionMessage; |
740 gchar* soapMessage; | |
741 gchar* totalSendMessage; | |
742 gchar* httpResponse; | |
11195 | 743 |
11391 | 744 gchar* pathOfControl; |
745 gchar* addressOfControl; | |
746 gchar* addressPortOfControl; | |
747 gchar portOfControl[MAX_PORT_SIZE]; | |
748 int port=0; | |
11195 | 749 |
750 /* set the soap message */ | |
11391 | 751 soapMessage = g_strdup_printf(SOAP_ACTION, actionName, |
752 controlInfo->serviceType, | |
753 actionParams, actionName); | |
11195 | 754 |
755 /* parse the url into address, port, path variables */ | |
11391 | 756 if(!gaim_url_parse(controlInfo->controlURL, &addressOfControl, |
757 &port, &pathOfControl, NULL, NULL)) { | |
758 gaim_debug_error("upnp", | |
11195 | 759 "generate_action_message_and_send(): Failed In Parse URL\n\n"); |
11391 | 760 g_free(soapMessage); |
11195 | 761 return NULL; |
762 } | |
11391 | 763 if(port == 0 || port == -1) { |
764 port = DEFAULT_HTTP_PORT; | |
765 } | |
766 g_ascii_dtostr(portOfControl, MAX_PORT_SIZE, port); | |
11195 | 767 |
768 /* set the addressPortOfControl variable which should have a | |
769 form like the following: 192.168.1.1:8000 */ | |
11391 | 770 addressPortOfControl = g_strdup_printf("%s:%s", |
771 addressOfControl, portOfControl); | |
11195 | 772 |
773 /* set the HTTP Header */ | |
11391 | 774 actionMessage = g_strdup_printf(HTTP_HEADER_ACTION, |
775 pathOfControl, addressPortOfControl, | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
776 controlInfo->serviceType, actionName, |
11391 | 777 strlen(soapMessage)); |
11195 | 778 |
779 /* append to the header the body */ | |
11391 | 780 totalSendMessage = g_strdup_printf("%s%s", actionMessage, soapMessage); |
11195 | 781 |
782 /* get the return of the http response */ | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
783 httpResponse = gaim_upnp_http_request(addressOfControl, |
11391 | 784 port, totalSendMessage); |
11195 | 785 if(httpResponse == NULL) { |
11391 | 786 gaim_debug_error("upnp", |
11195 | 787 "generate_action_message_and_send(): Failed In httpResponse\n\n"); |
788 } | |
789 | |
11391 | 790 g_free(actionMessage); |
791 g_free(soapMessage); | |
792 g_free(totalSendMessage); | |
793 g_free(pathOfControl); | |
794 g_free(addressOfControl); | |
795 g_free(addressPortOfControl); | |
11195 | 796 |
797 return httpResponse; | |
798 } | |
799 | |
800 | |
801 | |
802 | |
11391 | 803 gchar* |
804 gaim_upnp_get_public_ip(const GaimUPnPControlInfo* controlInfo) | |
11195 | 805 { |
11391 | 806 gchar* extIPAddress; |
807 gchar* httpResponse; | |
808 gchar actionName[] = "GetExternalIPAddress"; | |
809 gchar actionParams[] = ""; | |
810 gchar* temp, *temp2; | |
11195 | 811 |
11391 | 812 httpResponse = gaim_upnp_generate_action_message_and_send(controlInfo, |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
813 actionName, |
11195 | 814 actionParams); |
815 if(httpResponse == NULL) { | |
11391 | 816 gaim_debug_error("upnp", |
11195 | 817 "gaim_upnp_get_public_ip(): Failed In httpResponse\n\n"); |
818 return NULL; | |
819 } | |
820 | |
821 /* extract the ip, or see if there is an error */ | |
11391 | 822 if((temp = g_strstr_len(httpResponse, strlen(httpResponse), |
823 "<NewExternalIPAddress")) == NULL) { | |
824 gaim_debug_error("upnp", | |
11195 | 825 "gaim_upnp_get_public_ip(): Failed Finding <NewExternalIPAddress\n\n"); |
11391 | 826 g_free(httpResponse); |
11195 | 827 return NULL; |
828 } | |
11391 | 829 if((temp = g_strstr_len(temp, strlen(temp), ">")) == NULL) { |
830 gaim_debug_error("upnp", | |
11195 | 831 "gaim_upnp_get_public_ip(): Failed In Finding >\n\n"); |
11391 | 832 g_free(httpResponse); |
11195 | 833 return NULL; |
834 } | |
11391 | 835 if((temp2 = g_strstr_len(temp, strlen(temp), "<")) == NULL) { |
836 gaim_debug_error("upnp", | |
11195 | 837 "gaim_upnp_get_public_ip(): Failed In Finding <\n\n"); |
11391 | 838 g_free(httpResponse); |
11195 | 839 return NULL; |
840 } | |
11391 | 841 |
842 extIPAddress = g_strndup(&temp[1], (temp2-1)-temp); | |
11195 | 843 |
11391 | 844 g_free(httpResponse); |
845 | |
846 gaim_debug_info("upnp", "NAT Returned IP: %s\n", extIPAddress); | |
11195 | 847 return extIPAddress; |
848 } | |
849 | |
11391 | 850 static void |
851 gaim_upnp_get_local_system_ip(gpointer data, | |
852 gint sock, | |
853 GaimInputCondition cond) | |
854 { | |
855 NetResponseData* nrd = data; | |
11443
d9d60002065b
[gaim-migrate @ 13682]
Richard Laager <rlaager@wiktel.com>
parents:
11391
diff
changeset
|
856 nrd->recvBuffer = g_strdup(gaim_network_get_local_system_ip(sock)); |
11195 | 857 |
11391 | 858 gaim_timeout_remove(nrd->tima); |
859 nrd->done = TRUE; | |
11195 | 860 |
11391 | 861 close(sock); |
862 } | |
11195 | 863 |
11492 | 864 static gchar* |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
865 gaim_upnp_get_local_ip_address(const gchar* address) |
11391 | 866 { |
11492 | 867 gchar* ip; |
11391 | 868 gchar* pathOfControl; |
869 gchar* addressOfControl; | |
870 int port = 0; | |
871 NetResponseData* nrd = (NetResponseData*)g_malloc0(sizeof(NetResponseData)); | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
872 |
11391 | 873 if(!gaim_url_parse(address, &addressOfControl, |
874 &port, &pathOfControl, NULL, NULL)) { | |
875 gaim_debug_error("upnp", | |
11195 | 876 "get_local_ip_address(): Failed In Parse URL\n\n"); |
877 return NULL; | |
878 } | |
11391 | 879 if(port == 0 || port == -1) { |
880 port = DEFAULT_HTTP_PORT; | |
11195 | 881 } |
882 | |
11492 | 883 nrd->tima = gaim_timeout_add(RECEIVE_TIMEOUT, |
11391 | 884 (GSourceFunc)gaim_upnp_timeout, nrd); |
885 | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
886 if(gaim_proxy_connect(NULL, addressOfControl, port, |
11391 | 887 gaim_upnp_get_local_system_ip, nrd)) { |
11195 | 888 |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
889 gaim_debug_error("upnp", "Get Local IP Connect Failed: Address: %s @@@ Port %d @@@ Request %s\n\n", |
11391 | 890 address, port, nrd->sendBuffer); |
891 | |
892 gaim_timeout_remove(nrd->tima); | |
893 } else { | |
894 while (!nrd->done) { | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
895 g_main_context_iteration(NULL, TRUE); |
11391 | 896 } |
11195 | 897 } |
898 | |
11391 | 899 ip = nrd->recvBuffer; |
900 g_free(nrd); | |
11195 | 901 |
11391 | 902 gaim_debug_info("upnp", "local ip: %s\n", ip); |
903 | |
11195 | 904 return ip; |
905 } | |
906 | |
907 | |
908 | |
909 gboolean | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
910 gaim_upnp_set_port_mapping(const GaimUPnPControlInfo* controlInfo, |
11391 | 911 unsigned short portMap, |
912 const gchar* protocol) | |
11195 | 913 { |
11391 | 914 gchar* httpResponse; |
915 gchar actionName[] = "AddPortMapping"; | |
916 gchar* actionParams; | |
11492 | 917 gchar* internalIP; |
11195 | 918 |
919 /* get the internal IP */ | |
11391 | 920 if((internalIP = gaim_upnp_get_local_ip_address(controlInfo->controlURL)) |
921 == NULL) { | |
922 gaim_debug_error("upnp", | |
11195 | 923 "gaim_upnp_set_port_mapping(): couldn't get local ip\n\n"); |
924 return FALSE; | |
925 } | |
926 | |
927 /* make the portMappingParams variable */ | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
928 actionParams = g_strdup_printf(ADD_PORT_MAPPING_PARAMS, portMap, |
11391 | 929 protocol, portMap, internalIP); |
11195 | 930 |
11391 | 931 httpResponse = gaim_upnp_generate_action_message_and_send(controlInfo, |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
932 actionName, |
11195 | 933 actionParams); |
934 if(httpResponse == NULL) { | |
11391 | 935 gaim_debug_error("upnp", |
11195 | 936 "gaim_upnp_set_port_mapping(): Failed In httpResponse\n\n"); |
11391 | 937 g_free(actionParams); |
11492 | 938 g_free(internalIP); |
11195 | 939 return FALSE; |
940 } | |
941 | |
942 /* determine if port mapping was a success */ | |
943 if(strstr(httpResponse, HTTP_OK) == NULL) { | |
11391 | 944 gaim_debug_error("upnp", |
11195 | 945 "gaim_upnp_set_port_mapping(): Failed HTTP_OK\n\n%s\n\n", httpResponse); |
11391 | 946 g_free(actionParams); |
947 g_free(httpResponse); | |
11492 | 948 g_free(internalIP); |
11195 | 949 return FALSE; |
950 } | |
951 | |
11391 | 952 g_free(actionParams); |
953 g_free(httpResponse); | |
954 | |
955 gaim_debug_info("upnp", "NAT Added Port Forward On Port: %d: To IP: %s\n", portMap, internalIP); | |
11492 | 956 g_free(internalIP); |
11195 | 957 return TRUE; |
958 } | |
959 | |
960 | |
961 gboolean | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
962 gaim_upnp_remove_port_mapping(const GaimUPnPControlInfo* controlInfo, |
11391 | 963 unsigned short portMap, |
964 const char* protocol) | |
11195 | 965 { |
11391 | 966 gchar* httpResponse; |
967 gchar actionName[] = "DeletePortMapping"; | |
968 gchar* actionParams; | |
11195 | 969 |
970 /* make the portMappingParams variable */ | |
11391 | 971 actionParams = g_strdup_printf(DELETE_PORT_MAPPING_PARAMS, |
972 portMap, protocol); | |
11195 | 973 |
11391 | 974 httpResponse = gaim_upnp_generate_action_message_and_send(controlInfo, |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
975 actionName, |
11195 | 976 actionParams); |
977 | |
978 if(httpResponse == NULL) { | |
11391 | 979 gaim_debug_error("upnp", |
980 "gaim_upnp_remove_port_mapping(): Failed In httpResponse\n\n"); | |
981 g_free(actionParams); | |
11195 | 982 return FALSE; |
983 } | |
984 | |
985 /* determine if port mapping was a success */ | |
986 if(strstr(httpResponse, HTTP_OK) == NULL) { | |
11391 | 987 gaim_debug_error("upnp", |
11195 | 988 "gaim_upnp_set_port_mapping(): Failed HTTP_OK\n\n%s\n\n", httpResponse); |
11391 | 989 g_free(actionParams); |
990 g_free(httpResponse); | |
11195 | 991 return FALSE; |
992 } | |
993 | |
11391 | 994 g_free(actionParams); |
995 g_free(httpResponse); | |
996 | |
997 gaim_debug_info("upnp", "NAT Removed Port Forward On Port: %d\n", portMap); | |
11195 | 998 return TRUE; |
999 } |