Mercurial > pidgin
annotate src/upnp.c @ 12264:2be62353f708
[gaim-migrate @ 14566]
this was TRUE in oldstatus
committer: Tailor Script <tailor@pidgin.im>
| author | Nathan Walp <nwalp@pidgin.im> |
|---|---|
| date | Tue, 29 Nov 2005 23:50:39 +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 } |
