Mercurial > pidgin
annotate src/upnp.c @ 12192:fb89d3a31c19
[gaim-migrate @ 14494]
Deconflict key bindings and fix a capitalization normalization I missed. Keybindings suck. I agree that GTK+ should do this automagically.
committer: Tailor Script <tailor@pidgin.im>
| author | Richard Laager <rlaager@wiktel.com> |
|---|---|
| date | Tue, 22 Nov 2005 22:47:59 +0000 |
| parents | f9c5480ad0ce |
| children | 201be1b681a4 |
| 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; | |
| 162 extern int errno; | |
| 11391 | 163 NetResponseData* nrd = data; |
| 11195 | 164 |
| 11391 | 165 sizeRecv = recv(sock, &(nrd->recvBuffer[nrd->totalSizeRecv]), |
| 11492 | 166 MAX_DESCRIPTION_RECEIVE_SIZE-nrd->totalSizeRecv, 0); |
| 11195 | 167 if(sizeRecv < 0 && errno != EINTR) { |
| 11391 | 168 gaim_debug_error("upnp", |
| 11195 | 169 "gaim_upnp_http_read(): recv < 0: %i!\n\n", errno); |
| 11391 | 170 g_free(nrd->recvBuffer); |
| 171 nrd->recvBuffer = NULL; | |
| 172 gaim_timeout_remove(nrd->tima); | |
| 173 gaim_input_remove(nrd->inpa); | |
| 174 nrd->done = TRUE; | |
| 11195 | 175 return; |
| 176 }else if(errno == EINTR) { | |
| 177 sizeRecv = 0; | |
| 178 } | |
| 11391 | 179 nrd->totalSizeRecv += sizeRecv; |
| 11195 | 180 |
| 181 if(sizeRecv == 0) { | |
| 11391 | 182 gaim_timeout_remove(nrd->tima); |
| 183 gaim_input_remove(nrd->inpa); | |
| 184 if(nrd->totalSizeRecv == 0) { | |
| 185 gaim_debug_error("upnp", | |
| 11195 | 186 "gaim_upnp_http_read(): totalSizeRecv == 0\n\n"); |
| 11391 | 187 g_free(nrd->recvBuffer); |
| 188 nrd->recvBuffer = NULL; | |
| 11195 | 189 } else { |
| 11391 | 190 nrd->recvBuffer[nrd->totalSizeRecv] = '\0'; |
| 11195 | 191 } |
| 11391 | 192 nrd->done = TRUE; |
| 11195 | 193 } else { |
| 11391 | 194 gaim_timeout_remove(nrd->tima); |
| 195 gaim_input_remove(nrd->inpa); | |
| 11492 | 196 nrd->tima = gaim_timeout_add(CONSECUTIVE_RECEIVE_TIMEOUT, |
| 11391 | 197 (GSourceFunc)gaim_upnp_timeout, nrd); |
| 198 nrd->inpa = gaim_input_add(sock, GAIM_INPUT_READ, | |
| 199 gaim_upnp_http_read, nrd); | |
| 11195 | 200 } |
| 201 } | |
| 202 | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
203 static void |
| 11391 | 204 gaim_upnp_http_send(gpointer data, |
| 205 gint sock, | |
| 206 GaimInputCondition cond) | |
| 11195 | 207 { |
| 11586 | 208 gsize sizeSent, totalSizeSent = 0; |
| 11195 | 209 extern int errno; |
| 11391 | 210 NetResponseData* nrd = data; |
| 11195 | 211 |
| 11391 | 212 gaim_timeout_remove(nrd->tima); |
| 213 while(totalSizeSent < strlen(nrd->sendBuffer)) { | |
| 11586 | 214 sizeSent = send(sock,(gchar*)(nrd->sendBuffer+totalSizeSent), |
| 11391 | 215 strlen(nrd->sendBuffer)-totalSizeSent,0); |
| 11195 | 216 if(sizeSent <= 0 && errno != EINTR) { |
| 11391 | 217 gaim_debug_error("upnp", |
| 11195 | 218 "gaim_upnp_http_request(): Failed In send\n\n"); |
| 11391 | 219 nrd->done = TRUE; |
| 220 g_free(nrd->recvBuffer); | |
| 221 nrd->recvBuffer = NULL; | |
| 11195 | 222 close(sock); |
| 11391 | 223 return; |
| 11195 | 224 }else if(errno == EINTR) { |
| 225 sizeSent = 0; | |
| 226 } | |
| 227 totalSizeSent += sizeSent; | |
| 228 } | |
| 229 | |
| 11492 | 230 nrd->tima = gaim_timeout_add(RECEIVE_TIMEOUT, |
| 11391 | 231 (GSourceFunc)gaim_upnp_timeout, nrd); |
| 232 nrd->inpa = gaim_input_add(sock, GAIM_INPUT_READ, | |
| 233 gaim_upnp_http_read, nrd); | |
| 234 while (!nrd->done) { | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
235 g_main_context_iteration(NULL, TRUE); |
| 11195 | 236 } |
| 237 close(sock); | |
| 11391 | 238 } |
| 11195 | 239 |
| 11391 | 240 static gchar* |
| 241 gaim_upnp_http_request(const gchar* address, | |
| 242 int port, | |
| 243 gchar* httpRequest) | |
| 244 { | |
| 245 gchar* recvBuffer; | |
| 246 NetResponseData* nrd = (NetResponseData*)g_malloc0(sizeof(NetResponseData)); | |
| 247 nrd->sendBuffer = httpRequest; | |
| 11492 | 248 nrd->recvBuffer = (gchar*)g_malloc(MAX_DESCRIPTION_RECEIVE_SIZE); |
| 11391 | 249 |
| 11492 | 250 nrd->tima = gaim_timeout_add(RECEIVE_TIMEOUT, |
| 11391 | 251 (GSourceFunc)gaim_upnp_timeout, nrd); |
| 252 | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
253 if(gaim_proxy_connect(NULL, address, port, |
| 11391 | 254 gaim_upnp_http_send, nrd)) { |
| 255 | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
256 gaim_debug_error("upnp", "Connect Failed: Address: %s @@@ Port %d @@@ Request %s\n\n", |
| 11391 | 257 address, port, nrd->sendBuffer); |
| 258 | |
| 259 gaim_timeout_remove(nrd->tima); | |
| 260 g_free(nrd->recvBuffer); | |
| 261 nrd->recvBuffer = NULL; | |
| 262 } else { | |
| 263 while (!nrd->done) { | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
264 g_main_context_iteration(NULL, TRUE); |
| 11391 | 265 } |
| 266 } | |
| 267 | |
| 268 recvBuffer = nrd->recvBuffer; | |
| 269 g_free(nrd); | |
| 270 | |
| 11195 | 271 return recvBuffer; |
| 272 } | |
| 273 | |
| 274 | |
| 275 | |
| 11391 | 276 static gboolean |
| 277 gaim_upnp_compare_device(const xmlnode* device, | |
| 278 const gchar* deviceType) | |
| 279 { | |
| 280 xmlnode* deviceTypeNode = xmlnode_get_child(device, "deviceType"); | |
| 281 if(deviceTypeNode == NULL) { | |
| 282 return FALSE; | |
| 283 } | |
| 284 return !g_ascii_strcasecmp(xmlnode_get_data(deviceTypeNode), deviceType); | |
| 285 } | |
| 11195 | 286 |
| 11391 | 287 |
| 288 static gboolean | |
| 289 gaim_upnp_compare_service(const xmlnode* service, | |
| 290 const gchar* serviceType) | |
| 11195 | 291 { |
| 11391 | 292 xmlnode* serviceTypeNode = xmlnode_get_child(service, "serviceType"); |
| 293 if(serviceTypeNode == NULL) { | |
| 294 return FALSE; | |
| 295 } | |
| 296 return !g_ascii_strcasecmp(xmlnode_get_data(serviceTypeNode), serviceType); | |
| 297 } | |
| 298 | |
| 299 | |
| 11195 | 300 |
| 11391 | 301 static gchar* |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
302 gaim_upnp_parse_description_response(const gchar* httpResponse, |
| 11391 | 303 const gchar* httpURL, |
| 304 const gchar* serviceType) | |
| 305 { | |
| 306 gchar* xmlRoot; | |
| 307 gchar* baseURL; | |
| 308 gchar* controlURL; | |
| 309 gchar* service; | |
| 310 xmlnode* xmlRootNode; | |
| 311 xmlnode* serviceTypeNode; | |
| 312 xmlnode* controlURLNode; | |
| 313 xmlnode* baseURLNode; | |
| 314 | |
| 315 /* make sure we have a valid http response */ | |
| 316 if(g_strstr_len(httpResponse, strlen(httpResponse), HTTP_OK) == NULL) { | |
| 317 gaim_debug_error("upnp", | |
| 11195 | 318 "parse_description_response(): Failed In HTTP_OK\n\n"); |
| 319 return NULL; | |
| 320 } | |
| 321 | |
| 11391 | 322 /* find the root of the xml document */ |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
323 if((xmlRoot = g_strstr_len(httpResponse, strlen(httpResponse), |
| 11391 | 324 "<root")) == NULL) { |
| 325 gaim_debug_error("upnp", | |
| 326 "parse_description_response(): Failed finding root\n\n"); | |
| 327 return NULL; | |
| 328 } | |
| 329 | |
| 330 /* create the xml root node */ | |
| 331 if((xmlRootNode = xmlnode_from_str(xmlRoot, -1)) == NULL) { | |
| 332 gaim_debug_error("upnp", | |
| 333 "parse_description_response(): Could not parse xml root node\n\n"); | |
| 11195 | 334 return NULL; |
| 335 } | |
| 11391 | 336 |
| 337 /* get the baseURL of the device */ | |
| 338 if((baseURLNode = xmlnode_get_child(xmlRootNode, | |
| 339 "URLBase")) != NULL) { | |
| 340 baseURL = g_strdup(xmlnode_get_data(baseURLNode)); | |
| 341 } else { | |
| 342 baseURL = g_strdup(httpURL); | |
| 343 } | |
| 344 | |
| 345 /* get the serviceType child that has the service type as it's data */ | |
| 346 | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
347 /* get urn:schemas-upnp-org:device:InternetGatewayDevice:1 |
| 11391 | 348 and it's devicelist */ |
| 349 serviceTypeNode = xmlnode_get_child(xmlRootNode, "device"); | |
| 350 while(!gaim_upnp_compare_device(serviceTypeNode, | |
| 351 "urn:schemas-upnp-org:device:InternetGatewayDevice:1") && | |
| 352 serviceTypeNode != NULL) { | |
| 353 serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); | |
| 354 } | |
| 355 if(serviceTypeNode == NULL) { | |
| 356 gaim_debug_error("upnp", | |
| 357 "parse_description_response(): could not get serviceTypeNode 1\n\n"); | |
| 11195 | 358 return NULL; |
| 359 } | |
| 11391 | 360 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "deviceList"); |
| 361 if(serviceTypeNode == NULL) { | |
| 362 gaim_debug_error("upnp", | |
| 363 "parse_description_response(): could not get serviceTypeNode 2\n\n"); | |
| 11195 | 364 return NULL; |
| 365 } | |
| 366 | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
367 /* get urn:schemas-upnp-org:device:WANDevice:1 |
| 11391 | 368 and it's devicelist */ |
| 369 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "device"); | |
| 370 while(!gaim_upnp_compare_device(serviceTypeNode, | |
| 371 "urn:schemas-upnp-org:device:WANDevice:1") && | |
| 372 serviceTypeNode != NULL) { | |
| 373 serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); | |
| 374 } | |
| 375 if(serviceTypeNode == NULL) { | |
| 376 gaim_debug_error("upnp", | |
| 377 "parse_description_response(): could not get serviceTypeNode 3\n\n"); | |
| 378 return NULL; | |
| 379 } | |
| 380 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "deviceList"); | |
| 381 if(serviceTypeNode == NULL) { | |
| 382 gaim_debug_error("upnp", | |
| 383 "parse_description_response(): could not get serviceTypeNode 4\n\n"); | |
| 384 return NULL; | |
| 385 } | |
| 11195 | 386 |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
387 /* get urn:schemas-upnp-org:device:WANConnectionDevice:1 |
| 11391 | 388 and it's servicelist */ |
| 389 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "device"); | |
| 390 while(!gaim_upnp_compare_device(serviceTypeNode, | |
| 391 "urn:schemas-upnp-org:device:WANConnectionDevice:1") && | |
| 392 serviceTypeNode != NULL) { | |
| 393 serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); | |
| 394 } | |
| 395 if(serviceTypeNode == NULL) { | |
| 396 gaim_debug_error("upnp", | |
| 397 "parse_description_response(): could not get serviceTypeNode 5\n\n"); | |
| 11195 | 398 return NULL; |
| 399 } | |
| 11391 | 400 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "serviceList"); |
| 401 if(serviceTypeNode == NULL) { | |
| 402 gaim_debug_error("upnp", | |
| 403 "parse_description_response(): could not get serviceTypeNode 6\n\n"); | |
| 404 return NULL; | |
| 405 } | |
| 11195 | 406 |
| 11391 | 407 /* get the serviceType variable passed to this function */ |
| 408 service = g_strdup_printf(SEARCH_REQUEST_DEVICE, serviceType); | |
| 409 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "service"); | |
| 410 while(!gaim_upnp_compare_service(serviceTypeNode, service) && | |
| 411 serviceTypeNode != NULL) { | |
| 412 serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); | |
| 11195 | 413 } |
| 414 | |
| 11391 | 415 g_free(service); |
| 416 if(serviceTypeNode == NULL) { | |
| 417 gaim_debug_error("upnp", | |
| 418 "parse_description_response(): could not get serviceTypeNode 7\n\n"); | |
| 419 return NULL; | |
| 420 } | |
| 421 | |
| 422 /* get the controlURL of the service */ | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
423 if((controlURLNode = xmlnode_get_child(serviceTypeNode, |
| 11391 | 424 "controlURL")) == NULL) { |
| 425 gaim_debug_error("upnp", | |
| 426 "parse_description_response(): Could not find controlURL\n\n"); | |
| 427 return NULL; | |
| 428 } | |
| 429 | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
430 if(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 g_strstr_len(xmlnode_get_data(controlURLNode), |
| 11391 | 433 SIZEOF_HTTP, "HTTP://") == NULL) { |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
434 controlURL = g_strdup_printf("%s%s", baseURL, |
| 11391 | 435 xmlnode_get_data(controlURLNode)); |
| 11195 | 436 }else{ |
| 11391 | 437 controlURL = g_strdup(xmlnode_get_data(controlURLNode)); |
| 11195 | 438 } |
| 11391 | 439 g_free(baseURL); |
| 440 xmlnode_free(xmlRootNode); | |
| 11195 | 441 |
| 442 return controlURL; | |
| 443 } | |
| 444 | |
| 445 | |
| 11391 | 446 static gchar* |
| 447 gaim_upnp_parse_description(const gchar* descriptionURL, | |
| 448 const gchar* serviceType) | |
| 11195 | 449 { |
| 11391 | 450 gchar* fullURL; |
| 451 gchar* controlURL; | |
| 452 gchar* httpResponse; | |
| 453 gchar* httpRequest; | |
| 11195 | 454 |
| 11391 | 455 gchar* descriptionXMLAddress; |
| 456 gchar* descriptionAddressPort; | |
| 457 gchar* descriptionAddress; | |
| 458 gchar descriptionPort[MAX_PORT_SIZE]; | |
| 459 int port = 0; | |
| 11195 | 460 |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
461 /* parse the 4 above variables out of the descriptionURL |
| 11195 | 462 example description URL: http://192.168.1.1:5678/rootDesc.xml */ |
| 463 | |
| 464 /* parse the url into address, port, path variables */ | |
| 11391 | 465 if(!gaim_url_parse(descriptionURL, &descriptionAddress, |
| 466 &port, &descriptionXMLAddress, NULL, NULL)) { | |
| 11195 | 467 return NULL; |
| 468 } | |
| 11391 | 469 if(port == 0 || port == -1) { |
| 470 port = DEFAULT_HTTP_PORT; | |
| 11195 | 471 } |
| 11391 | 472 g_ascii_dtostr(descriptionPort, MAX_PORT_SIZE, port); |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
473 descriptionAddressPort = g_strdup_printf("%s:%s", descriptionAddress, |
| 11391 | 474 descriptionPort); |
| 11195 | 475 |
| 11391 | 476 fullURL = g_strdup_printf("http://%s", descriptionAddressPort); |
| 11195 | 477 |
| 478 /* for example... | |
| 479 GET /rootDesc.xml HTTP/1.1\r\nHost: 192.168.1.1:5678\r\n\r\n */ | |
| 11391 | 480 httpRequest = g_strdup_printf("GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n", |
| 481 descriptionXMLAddress, descriptionAddressPort); | |
| 11195 | 482 |
| 483 httpResponse = gaim_upnp_http_request(descriptionAddress, | |
| 484 port, httpRequest); | |
| 485 if(httpResponse == NULL) { | |
| 11391 | 486 gaim_debug_error("upnp", |
| 11195 | 487 "gaim_upnp_parse_description(): httpResponse is NULL\n\n"); |
| 11391 | 488 g_free(descriptionXMLAddress); |
| 489 g_free(descriptionAddress); | |
| 490 g_free(descriptionAddressPort); | |
| 491 g_free(httpRequest); | |
| 492 g_free(fullURL); | |
| 11195 | 493 return NULL; |
| 494 } | |
| 495 | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
496 controlURL = gaim_upnp_parse_description_response(httpResponse, |
| 11391 | 497 fullURL, serviceType); |
| 11195 | 498 |
| 11391 | 499 g_free(descriptionXMLAddress); |
| 500 g_free(descriptionAddress); | |
| 501 g_free(descriptionAddressPort); | |
| 502 g_free(fullURL); | |
| 503 g_free(httpRequest); | |
| 504 g_free(httpResponse); | |
| 11195 | 505 |
| 506 if(controlURL == NULL) { | |
| 11391 | 507 gaim_debug_error("upnp", |
| 11195 | 508 "gaim_upnp_parse_description(): controlURL is NULL\n\n"); |
| 509 return NULL; | |
| 510 } | |
| 511 | |
| 512 return controlURL; | |
| 513 } | |
| 514 | |
| 515 | |
| 11391 | 516 static gchar* |
| 517 gaim_upnp_parse_discover_response(const gchar* buf, | |
| 518 unsigned int bufSize, | |
| 519 const gchar* serviceType) | |
| 11195 | 520 { |
| 11391 | 521 gchar* startDescURL; |
| 522 gchar* endDescURL; | |
| 523 gchar* descURL; | |
| 524 gchar* retVal; | |
| 11195 | 525 |
| 11391 | 526 if(g_strstr_len(buf, strlen(buf), HTTP_OK) == NULL) { |
| 527 gaim_debug_error("upnp", | |
| 11195 | 528 "parse_discover_response(): Failed In HTTP_OK\n\n"); |
| 529 return NULL; | |
| 530 } | |
| 531 | |
| 11391 | 532 if((startDescURL = g_strstr_len(buf, strlen(buf), "http://")) == NULL) { |
| 533 gaim_debug_error("upnp", | |
| 534 "parse_discover_response(): Failed In finding http://\n\n"); | |
| 11195 | 535 return NULL; |
| 536 } | |
| 537 | |
| 11391 | 538 endDescURL = g_strstr_len(startDescURL, strlen(startDescURL), "\r"); |
| 11195 | 539 if(endDescURL == NULL) { |
| 11391 | 540 endDescURL = g_strstr_len(startDescURL, strlen(startDescURL), "\n"); |
| 11195 | 541 if(endDescURL == NULL) { |
| 11391 | 542 gaim_debug_error("upnp", |
| 543 "parse_discover_response(): Failed In endDescURL\n\n"); | |
| 11195 | 544 return NULL; |
| 545 }else if(endDescURL == startDescURL) { | |
| 11391 | 546 gaim_debug_error("upnp", |
| 547 "parse_discover_response(): endDescURL == startDescURL\n\n"); | |
| 11195 | 548 return NULL; |
| 549 } | |
| 550 }else if(endDescURL == startDescURL) { | |
| 11391 | 551 gaim_debug_error("upnp", |
| 552 "parse_discover_response(): 2nd endDescURL == startDescURL\n\n"); | |
| 11195 | 553 return NULL; |
| 554 } | |
| 11391 | 555 descURL = g_strndup(startDescURL, endDescURL-startDescURL); |
| 11195 | 556 |
| 11391 | 557 retVal = gaim_upnp_parse_description(descURL, serviceType); |
| 558 g_free(descURL); | |
| 11195 | 559 return retVal; |
| 560 } | |
| 561 | |
| 562 | |
| 563 | |
| 564 static void | |
| 565 gaim_upnp_discover_udp_read(gpointer data, | |
| 566 gint sock, | |
| 567 GaimInputCondition cond) | |
| 568 { | |
| 569 unsigned int length; | |
| 570 extern int errno; | |
| 571 struct sockaddr_in from; | |
| 572 int sizeRecv; | |
| 11391 | 573 NetResponseData* nrd = data; |
| 11195 | 574 |
| 11391 | 575 gaim_timeout_remove(nrd->tima); |
| 11195 | 576 length = sizeof(struct sockaddr_in); |
| 577 | |
| 578 do { | |
| 11391 | 579 sizeRecv = recvfrom(sock, nrd->recvBuffer, |
| 11492 | 580 MAX_DISCOVERY_RECEIVE_SIZE, 0, |
| 11195 | 581 (struct sockaddr*)&from, &length); |
| 582 | |
| 583 if(sizeRecv > 0) { | |
| 11391 | 584 nrd->recvBuffer[sizeRecv] = '\0'; |
| 11195 | 585 }else if(errno != EINTR) { |
| 11391 | 586 g_free(nrd->recvBuffer); |
| 587 nrd->recvBuffer = NULL; | |
| 11195 | 588 } |
| 589 }while(errno == EINTR); | |
| 590 | |
| 11391 | 591 gaim_input_remove(nrd->inpa); |
| 592 nrd->done = TRUE; | |
| 11195 | 593 return; |
| 594 } | |
| 595 | |
| 596 | |
| 11213 | 597 |
| 11391 | 598 GaimUPnPControlInfo* |
| 11195 | 599 gaim_upnp_discover(void) |
| 600 { | |
| 11391 | 601 /* Socket Setup Variables */ |
| 11195 | 602 int sock, i; |
| 603 extern int errno; | |
| 604 struct sockaddr_in server; | |
| 11391 | 605 struct hostent* hp; |
| 11195 | 606 |
| 11391 | 607 /* UDP SEND VARIABLES */ |
| 608 gboolean sentSuccess, recvSuccess; | |
| 609 int sizeSent, totalSizeSent; | |
| 610 gchar wanIP[] = "WANIPConnection:1"; | |
| 611 gchar wanPPP[] = "WANPPPConnection:1"; | |
| 612 gchar* serviceToUse; | |
| 613 gchar* sendMessage = NULL; | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
614 |
| 11492 | 615 /* UDP RECEIVE VARIABLES */ |
| 11391 | 616 GaimUPnPControlInfo* controlInfo = g_malloc(sizeof(GaimUPnPControlInfo)); |
| 617 NetResponseData* nrd = g_malloc(sizeof(NetResponseData)); | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
618 |
| 11391 | 619 /* Set up the sockets */ |
| 11195 | 620 sock = socket(AF_INET, SOCK_DGRAM, 0); |
| 621 if (sock == -1) { | |
| 622 close(sock); | |
| 11391 | 623 gaim_debug_error("upnp", |
| 11195 | 624 "gaim_upnp_discover(): Failed In sock creation\n\n"); |
| 11391 | 625 g_free(nrd); |
| 626 g_free(controlInfo); | |
| 11195 | 627 return NULL; |
| 628 } | |
| 629 memset(&server, 0, sizeof(struct sockaddr)); | |
| 630 server.sin_family = AF_INET; | |
| 631 if((hp = gethostbyname(HTTPMU_HOST_ADDRESS)) == NULL) { | |
| 632 close(sock); | |
| 11391 | 633 gaim_debug_error("upnp", |
| 11195 | 634 "gaim_upnp_discover(): Failed In gethostbyname\n\n"); |
| 11391 | 635 g_free(nrd); |
| 636 g_free(controlInfo); | |
| 11195 | 637 return NULL; |
| 638 } | |
| 639 memcpy(&server.sin_addr, | |
| 640 hp->h_addr_list[0], | |
| 641 hp->h_length); | |
| 642 server.sin_port = htons(HTTPMU_HOST_PORT); | |
| 643 | |
| 644 /* because we are sending over UDP, if there is a failure | |
| 11391 | 645 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
|
646 try different requests for WANIPConnection and |
| 11391 | 647 WANPPPConnection*/ |
| 11195 | 648 for(i = 0; i < NUM_UDP_ATTEMPTS; i++) { |
| 649 sentSuccess = TRUE; | |
| 650 recvSuccess = TRUE; | |
| 651 totalSizeSent = 0; | |
| 652 | |
| 11391 | 653 nrd->recvBuffer = NULL; |
| 654 nrd->totalSizeRecv = 0; | |
| 655 nrd->done = FALSE; | |
| 656 | |
| 657 if(sendMessage != NULL) { | |
| 658 g_free(sendMessage); | |
| 659 } | |
| 11213 | 660 |
| 11391 | 661 if(i%2 == 0) { |
| 662 serviceToUse = wanIP; | |
| 663 } else { | |
| 664 serviceToUse = wanPPP; | |
| 11213 | 665 } |
| 11391 | 666 sendMessage = g_strdup_printf(SEARCH_REQUEST_STRING, serviceToUse); |
| 667 | |
| 11492 | 668 nrd->recvBuffer = (char*)g_malloc(MAX_DISCOVERY_RECEIVE_SIZE); |
| 11213 | 669 |
| 11195 | 670 while(totalSizeSent < strlen(sendMessage)) { |
| 671 sizeSent = sendto(sock,(void*)&sendMessage[totalSizeSent], | |
| 672 strlen(&sendMessage[totalSizeSent]),0, | |
| 673 (struct sockaddr*)&server, | |
| 674 sizeof(struct sockaddr_in)); | |
| 675 if(sizeSent <= 0 && errno != EINTR) { | |
| 676 sentSuccess = FALSE; | |
| 677 break; | |
| 678 }else if(errno == EINTR) { | |
| 679 sizeSent = 0; | |
| 680 } | |
| 681 totalSizeSent += sizeSent; | |
| 682 } | |
| 683 | |
| 684 if(sentSuccess) { | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
685 nrd->tima = gaim_timeout_add(DISCOVERY_TIMEOUT, |
| 11391 | 686 (GSourceFunc)gaim_upnp_timeout, nrd); |
| 687 nrd->inpa = gaim_input_add(sock, GAIM_INPUT_READ, | |
| 688 gaim_upnp_discover_udp_read, nrd); | |
| 689 while (!nrd->done) { | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
690 g_main_context_iteration(NULL, TRUE); |
| 11195 | 691 } |
| 11391 | 692 if(nrd->recvBuffer == NULL) { |
| 11195 | 693 recvSuccess = FALSE; |
| 694 } else { | |
| 695 /* parse the response, and see if it was a success */ | |
| 696 close(sock); | |
| 11391 | 697 if((controlInfo->controlURL= |
| 698 gaim_upnp_parse_discover_response(nrd->recvBuffer, | |
| 699 strlen(nrd->recvBuffer), | |
| 700 serviceToUse))==NULL) { | |
| 701 gaim_debug_error("upnp", | |
| 11195 | 702 "gaim_upnp_discover(): Failed In parse response\n\n"); |
| 11391 | 703 g_free(nrd->recvBuffer); |
| 704 g_free(nrd); | |
| 705 g_free(controlInfo); | |
| 11195 | 706 return NULL; |
| 707 } | |
| 11391 | 708 |
| 709 controlInfo->serviceType = g_strdup(serviceToUse); | |
| 11195 | 710 } |
| 711 } | |
| 712 | |
| 713 /* if sent success and recv successful, then break */ | |
| 714 if(sentSuccess && recvSuccess) { | |
| 715 i = NUM_UDP_ATTEMPTS; | |
| 716 } | |
| 717 } | |
| 11213 | 718 |
| 11391 | 719 if(nrd->recvBuffer != NULL) { |
| 720 g_free(nrd->recvBuffer); | |
| 11213 | 721 } |
| 11391 | 722 g_free(sendMessage); |
| 723 g_free(nrd); | |
| 11213 | 724 |
| 11195 | 725 if(!sentSuccess || !recvSuccess) { |
| 726 close(sock); | |
| 11391 | 727 gaim_debug_error("upnp", |
| 11195 | 728 "gaim_upnp_discover(): Failed In sent/recv success\n\n"); |
| 11391 | 729 g_free(controlInfo); |
| 11195 | 730 return NULL; |
| 731 } | |
| 732 | |
| 11391 | 733 return controlInfo; |
| 11195 | 734 } |
| 735 | |
| 736 | |
| 737 static char* | |
| 11391 | 738 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
|
739 const gchar* actionName, |
| 11391 | 740 const gchar* actionParams) |
| 11195 | 741 { |
| 11391 | 742 gchar* actionMessage; |
| 743 gchar* soapMessage; | |
| 744 gchar* totalSendMessage; | |
| 745 gchar* httpResponse; | |
| 11195 | 746 |
| 11391 | 747 gchar* pathOfControl; |
| 748 gchar* addressOfControl; | |
| 749 gchar* addressPortOfControl; | |
| 750 gchar portOfControl[MAX_PORT_SIZE]; | |
| 751 int port=0; | |
| 11195 | 752 |
| 753 /* set the soap message */ | |
| 11391 | 754 soapMessage = g_strdup_printf(SOAP_ACTION, actionName, |
| 755 controlInfo->serviceType, | |
| 756 actionParams, actionName); | |
| 11195 | 757 |
| 758 /* parse the url into address, port, path variables */ | |
| 11391 | 759 if(!gaim_url_parse(controlInfo->controlURL, &addressOfControl, |
| 760 &port, &pathOfControl, NULL, NULL)) { | |
| 761 gaim_debug_error("upnp", | |
| 11195 | 762 "generate_action_message_and_send(): Failed In Parse URL\n\n"); |
| 11391 | 763 g_free(soapMessage); |
| 11195 | 764 return NULL; |
| 765 } | |
| 11391 | 766 if(port == 0 || port == -1) { |
| 767 port = DEFAULT_HTTP_PORT; | |
| 768 } | |
| 769 g_ascii_dtostr(portOfControl, MAX_PORT_SIZE, port); | |
| 11195 | 770 |
| 771 /* set the addressPortOfControl variable which should have a | |
| 772 form like the following: 192.168.1.1:8000 */ | |
| 11391 | 773 addressPortOfControl = g_strdup_printf("%s:%s", |
| 774 addressOfControl, portOfControl); | |
| 11195 | 775 |
| 776 /* set the HTTP Header */ | |
| 11391 | 777 actionMessage = g_strdup_printf(HTTP_HEADER_ACTION, |
| 778 pathOfControl, addressPortOfControl, | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
779 controlInfo->serviceType, actionName, |
| 11391 | 780 strlen(soapMessage)); |
| 11195 | 781 |
| 782 /* append to the header the body */ | |
| 11391 | 783 totalSendMessage = g_strdup_printf("%s%s", actionMessage, soapMessage); |
| 11195 | 784 |
| 785 /* get the return of the http response */ | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
786 httpResponse = gaim_upnp_http_request(addressOfControl, |
| 11391 | 787 port, totalSendMessage); |
| 11195 | 788 if(httpResponse == NULL) { |
| 11391 | 789 gaim_debug_error("upnp", |
| 11195 | 790 "generate_action_message_and_send(): Failed In httpResponse\n\n"); |
| 791 } | |
| 792 | |
| 11391 | 793 g_free(actionMessage); |
| 794 g_free(soapMessage); | |
| 795 g_free(totalSendMessage); | |
| 796 g_free(pathOfControl); | |
| 797 g_free(addressOfControl); | |
| 798 g_free(addressPortOfControl); | |
| 11195 | 799 |
| 800 return httpResponse; | |
| 801 } | |
| 802 | |
| 803 | |
| 804 | |
| 805 | |
| 11391 | 806 gchar* |
| 807 gaim_upnp_get_public_ip(const GaimUPnPControlInfo* controlInfo) | |
| 11195 | 808 { |
| 11391 | 809 gchar* extIPAddress; |
| 810 gchar* httpResponse; | |
| 811 gchar actionName[] = "GetExternalIPAddress"; | |
| 812 gchar actionParams[] = ""; | |
| 813 gchar* temp, *temp2; | |
| 11195 | 814 |
| 11391 | 815 httpResponse = gaim_upnp_generate_action_message_and_send(controlInfo, |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
816 actionName, |
| 11195 | 817 actionParams); |
| 818 if(httpResponse == NULL) { | |
| 11391 | 819 gaim_debug_error("upnp", |
| 11195 | 820 "gaim_upnp_get_public_ip(): Failed In httpResponse\n\n"); |
| 821 return NULL; | |
| 822 } | |
| 823 | |
| 824 /* extract the ip, or see if there is an error */ | |
| 11391 | 825 if((temp = g_strstr_len(httpResponse, strlen(httpResponse), |
| 826 "<NewExternalIPAddress")) == NULL) { | |
| 827 gaim_debug_error("upnp", | |
| 11195 | 828 "gaim_upnp_get_public_ip(): Failed Finding <NewExternalIPAddress\n\n"); |
| 11391 | 829 g_free(httpResponse); |
| 11195 | 830 return NULL; |
| 831 } | |
| 11391 | 832 if((temp = g_strstr_len(temp, strlen(temp), ">")) == NULL) { |
| 833 gaim_debug_error("upnp", | |
| 11195 | 834 "gaim_upnp_get_public_ip(): Failed In Finding >\n\n"); |
| 11391 | 835 g_free(httpResponse); |
| 11195 | 836 return NULL; |
| 837 } | |
| 11391 | 838 if((temp2 = g_strstr_len(temp, strlen(temp), "<")) == NULL) { |
| 839 gaim_debug_error("upnp", | |
| 11195 | 840 "gaim_upnp_get_public_ip(): Failed In Finding <\n\n"); |
| 11391 | 841 g_free(httpResponse); |
| 11195 | 842 return NULL; |
| 843 } | |
| 11391 | 844 |
| 845 extIPAddress = g_strndup(&temp[1], (temp2-1)-temp); | |
| 11195 | 846 |
| 11391 | 847 g_free(httpResponse); |
| 848 | |
| 849 gaim_debug_info("upnp", "NAT Returned IP: %s\n", extIPAddress); | |
| 11195 | 850 return extIPAddress; |
| 851 } | |
| 852 | |
| 11391 | 853 static void |
| 854 gaim_upnp_get_local_system_ip(gpointer data, | |
| 855 gint sock, | |
| 856 GaimInputCondition cond) | |
| 857 { | |
| 858 NetResponseData* nrd = data; | |
|
11443
d9d60002065b
[gaim-migrate @ 13682]
Richard Laager <rlaager@wiktel.com>
parents:
11391
diff
changeset
|
859 nrd->recvBuffer = g_strdup(gaim_network_get_local_system_ip(sock)); |
| 11195 | 860 |
| 11391 | 861 gaim_timeout_remove(nrd->tima); |
| 862 nrd->done = TRUE; | |
| 11195 | 863 |
| 11391 | 864 close(sock); |
| 865 } | |
| 11195 | 866 |
| 11492 | 867 static gchar* |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
868 gaim_upnp_get_local_ip_address(const gchar* address) |
| 11391 | 869 { |
| 11492 | 870 gchar* ip; |
| 11391 | 871 gchar* pathOfControl; |
| 872 gchar* addressOfControl; | |
| 873 int port = 0; | |
| 874 NetResponseData* nrd = (NetResponseData*)g_malloc0(sizeof(NetResponseData)); | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
875 |
| 11391 | 876 if(!gaim_url_parse(address, &addressOfControl, |
| 877 &port, &pathOfControl, NULL, NULL)) { | |
| 878 gaim_debug_error("upnp", | |
| 11195 | 879 "get_local_ip_address(): Failed In Parse URL\n\n"); |
| 880 return NULL; | |
| 881 } | |
| 11391 | 882 if(port == 0 || port == -1) { |
| 883 port = DEFAULT_HTTP_PORT; | |
| 11195 | 884 } |
| 885 | |
| 11492 | 886 nrd->tima = gaim_timeout_add(RECEIVE_TIMEOUT, |
| 11391 | 887 (GSourceFunc)gaim_upnp_timeout, nrd); |
| 888 | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
889 if(gaim_proxy_connect(NULL, addressOfControl, port, |
| 11391 | 890 gaim_upnp_get_local_system_ip, nrd)) { |
| 11195 | 891 |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
892 gaim_debug_error("upnp", "Get Local IP Connect Failed: Address: %s @@@ Port %d @@@ Request %s\n\n", |
| 11391 | 893 address, port, nrd->sendBuffer); |
| 894 | |
| 895 gaim_timeout_remove(nrd->tima); | |
| 896 } else { | |
| 897 while (!nrd->done) { | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
898 g_main_context_iteration(NULL, TRUE); |
| 11391 | 899 } |
| 11195 | 900 } |
| 901 | |
| 11391 | 902 ip = nrd->recvBuffer; |
| 903 g_free(nrd); | |
| 11195 | 904 |
| 11391 | 905 gaim_debug_info("upnp", "local ip: %s\n", ip); |
| 906 | |
| 11195 | 907 return ip; |
| 908 } | |
| 909 | |
| 910 | |
| 911 | |
| 912 gboolean | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
913 gaim_upnp_set_port_mapping(const GaimUPnPControlInfo* controlInfo, |
| 11391 | 914 unsigned short portMap, |
| 915 const gchar* protocol) | |
| 11195 | 916 { |
| 11391 | 917 gchar* httpResponse; |
| 918 gchar actionName[] = "AddPortMapping"; | |
| 919 gchar* actionParams; | |
| 11492 | 920 gchar* internalIP; |
| 11195 | 921 |
| 922 /* get the internal IP */ | |
| 11391 | 923 if((internalIP = gaim_upnp_get_local_ip_address(controlInfo->controlURL)) |
| 924 == NULL) { | |
| 925 gaim_debug_error("upnp", | |
| 11195 | 926 "gaim_upnp_set_port_mapping(): couldn't get local ip\n\n"); |
| 927 return FALSE; | |
| 928 } | |
| 929 | |
| 930 /* make the portMappingParams variable */ | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
931 actionParams = g_strdup_printf(ADD_PORT_MAPPING_PARAMS, portMap, |
| 11391 | 932 protocol, portMap, internalIP); |
| 11195 | 933 |
| 11391 | 934 httpResponse = gaim_upnp_generate_action_message_and_send(controlInfo, |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
935 actionName, |
| 11195 | 936 actionParams); |
| 937 if(httpResponse == NULL) { | |
| 11391 | 938 gaim_debug_error("upnp", |
| 11195 | 939 "gaim_upnp_set_port_mapping(): Failed In httpResponse\n\n"); |
| 11391 | 940 g_free(actionParams); |
| 11492 | 941 g_free(internalIP); |
| 11195 | 942 return FALSE; |
| 943 } | |
| 944 | |
| 945 /* determine if port mapping was a success */ | |
| 946 if(strstr(httpResponse, HTTP_OK) == NULL) { | |
| 11391 | 947 gaim_debug_error("upnp", |
| 11195 | 948 "gaim_upnp_set_port_mapping(): Failed HTTP_OK\n\n%s\n\n", httpResponse); |
| 11391 | 949 g_free(actionParams); |
| 950 g_free(httpResponse); | |
| 11492 | 951 g_free(internalIP); |
| 11195 | 952 return FALSE; |
| 953 } | |
| 954 | |
| 11391 | 955 g_free(actionParams); |
| 956 g_free(httpResponse); | |
| 957 | |
| 958 gaim_debug_info("upnp", "NAT Added Port Forward On Port: %d: To IP: %s\n", portMap, internalIP); | |
| 11492 | 959 g_free(internalIP); |
| 11195 | 960 return TRUE; |
| 961 } | |
| 962 | |
| 963 | |
| 964 gboolean | |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
965 gaim_upnp_remove_port_mapping(const GaimUPnPControlInfo* controlInfo, |
| 11391 | 966 unsigned short portMap, |
| 967 const char* protocol) | |
| 11195 | 968 { |
| 11391 | 969 gchar* httpResponse; |
| 970 gchar actionName[] = "DeletePortMapping"; | |
| 971 gchar* actionParams; | |
| 11195 | 972 |
| 973 /* make the portMappingParams variable */ | |
| 11391 | 974 actionParams = g_strdup_printf(DELETE_PORT_MAPPING_PARAMS, |
| 975 portMap, protocol); | |
| 11195 | 976 |
| 11391 | 977 httpResponse = gaim_upnp_generate_action_message_and_send(controlInfo, |
|
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
978 actionName, |
| 11195 | 979 actionParams); |
| 980 | |
| 981 if(httpResponse == NULL) { | |
| 11391 | 982 gaim_debug_error("upnp", |
| 983 "gaim_upnp_remove_port_mapping(): Failed In httpResponse\n\n"); | |
| 984 g_free(actionParams); | |
| 11195 | 985 return FALSE; |
| 986 } | |
| 987 | |
| 988 /* determine if port mapping was a success */ | |
| 989 if(strstr(httpResponse, HTTP_OK) == NULL) { | |
| 11391 | 990 gaim_debug_error("upnp", |
| 11195 | 991 "gaim_upnp_set_port_mapping(): Failed HTTP_OK\n\n%s\n\n", httpResponse); |
| 11391 | 992 g_free(actionParams); |
| 993 g_free(httpResponse); | |
| 11195 | 994 return FALSE; |
| 995 } | |
| 996 | |
| 11391 | 997 g_free(actionParams); |
| 998 g_free(httpResponse); | |
| 999 | |
| 1000 gaim_debug_info("upnp", "NAT Removed Port Forward On Port: %d\n", portMap); | |
| 11195 | 1001 return TRUE; |
| 1002 } |
