comparison src/upnp.c @ 11391:d3755a7ddd82

[gaim-migrate @ 13620] *** empty log message *** committer: Tailor Script <tailor@pidgin.im>
author Adam Warrington <awarring>
date Wed, 31 Aug 2005 18:50:38 +0000
parents ff728e84d59a
children d9d60002065b
comparison
equal deleted inserted replaced
11390:869cef00a947 11391:d3755a7ddd82
24 */ 24 */
25 #include "internal.h" 25 #include "internal.h"
26 #include "gtkgaim.h" 26 #include "gtkgaim.h"
27 27
28 #include "debug.h" 28 #include "debug.h"
29 #include "util.h"
30 #include "proxy.h"
31 #include "xmlnode.h"
29 #include "network.h" 32 #include "network.h"
30 #include "eventloop.h" 33 #include "eventloop.h"
31 #include "upnp.h" 34 #include "upnp.h"
32 35
33 36
36 */ 39 */
37 typedef struct 40 typedef struct
38 { 41 {
39 guint inpa; /* gaim_input_add handle */ 42 guint inpa; /* gaim_input_add handle */
40 guint tima; /* gaim_timout_add handle */ 43 guint tima; /* gaim_timout_add handle */
41 char* recvBuffer; /* response data */ 44 gchar* sendBuffer; /* send data */
45 gchar* recvBuffer; /* response data */
42 guint totalSizeRecv; 46 guint totalSizeRecv;
43 gboolean done; 47 gboolean done;
44 48
45 } HRD; 49 } NetResponseData;
46 50
47 51
48 /*************************************************************** 52 /***************************************************************
49 ** General Defines * 53 ** General Defines *
50 ****************************************************************/ 54 ****************************************************************/
51 #define HTTP_OK "200 OK" 55 #define HTTP_OK "200 OK"
52 #define SIZEOF_HTTP 7 /* size of "http://" */ 56 #define DEFAULT_HTTP_PORT 80
57 #define MAX_PORT_SIZE 6
58 #define SIZEOF_HTTP 7 /* size of "http://" string */
53 #define RECIEVE_TIMEOUT 10000 59 #define RECIEVE_TIMEOUT 10000
54 #define CONSECUTIVE_RECIEVE_TIMEOUT 500 60 #define CONSECUTIVE_RECIEVE_TIMEOUT 500
55 #define DISCOVERY_TIMEOUT 1000 61 #define DISCOVERY_TIMEOUT 1000
56 62
57 63
63 /* Address and port of an SSDP request used for discovery */ 69 /* Address and port of an SSDP request used for discovery */
64 #define HTTPMU_HOST_ADDRESS "239.255.255.250" 70 #define HTTPMU_HOST_ADDRESS "239.255.255.250"
65 #define HTTPMU_HOST_PORT 1900 71 #define HTTPMU_HOST_PORT 1900
66 72
67 #define SEARCH_REQUEST_DEVICE "urn:schemas-upnp-org:service:" \ 73 #define SEARCH_REQUEST_DEVICE "urn:schemas-upnp-org:service:" \
68 "WANIPConnection:1" 74 "%s"
69 75
70 #define SEARCH_REQUEST_STRING "M-SEARCH * HTTP/1.1\r\n" \ 76 #define SEARCH_REQUEST_STRING "M-SEARCH * HTTP/1.1\r\n" \
71 "MX: 2\r\n" \ 77 "MX: 2\r\n" \
72 "HOST: 239.255.255.250:1900\r\n" \ 78 "HOST: 239.255.255.250:1900\r\n" \
73 "MAN: \"ssdp:discover\"\r\n" \ 79 "MAN: \"ssdp:discover\"\r\n" \
74 "ST: urn:schemas-upnp-org:service:" \ 80 "ST: urn:schemas-upnp-org:service:" \
75 "WANIPConnection:1\r\n" \ 81 "%s\r\n" \
76 "\r\n" 82 "\r\n"
77 83
78 #define MAX_DISCOVERY_RECIEVE_SIZE 400 84 #define MAX_DISCOVERY_RECIEVE_SIZE 400
79 #define MAX_DESCRIPTION_RECIEVE_SIZE 7000 85 #define MAX_DESCRIPTION_RECIEVE_SIZE 7000
80 #define MAX_DESCRIPTION_HTTP_HEADER_SIZE 100 86 #define MAX_DESCRIPTION_HTTP_HEADER_SIZE 100
81 87
82 88
83 /****************************************************************** 89 /******************************************************************
84 ** Action Defines * 90 ** Action Defines *
85 *******************************************************************/ 91 *******************************************************************/
86 #define HTTP_HEADER_ACTION "POST %s HTTP/1.1\r\n" \ 92 #define HTTP_HEADER_ACTION "POST /%s HTTP/1.1\r\n" \
87 "HOST: %s\r\n" \ 93 "HOST: %s\r\n" \
88 "SOAPACTION: " \ 94 "SOAPACTION: " \
89 "\"urn:schemas-upnp-org:" \ 95 "\"urn:schemas-upnp-org:" \
90 "service:%s#%s\"\r\n" \ 96 "service:%s#%s\"\r\n" \
91 "CONTENT-TYPE: text/xml ; charset=\"utf-8\"\r\n"\ 97 "CONTENT-TYPE: text/xml ; charset=\"utf-8\"\r\n"\
124 "<NewExternalPort>%i" \ 130 "<NewExternalPort>%i" \
125 "</NewExternalPort>\r\n" \ 131 "</NewExternalPort>\r\n" \
126 "<NewProtocol>%s</NewProtocol>\r\n" 132 "<NewProtocol>%s</NewProtocol>\r\n"
127 133
128 134
129
130 /* validate an http url without a port */
131 static gboolean
132 gaim_upnp_validate_url(const char* url)
133 {
134 int i1, i2, i3, i4, r;
135
136 if(url == NULL) {
137 gaim_debug_info("upnp",
138 "gaim_upnp_validate_url(): url == NULL\n\n");
139 return FALSE;
140 }
141 r = sscanf(url, "http://%3i.%3i.%3i.%3i/", &i1, &i2, &i3, &i4);
142 if(r == 4) {
143 return TRUE;
144 }
145
146 gaim_debug_info("upnp",
147 "gaim_upnp_validate_url(): Failed In validate URL\n\n");
148 return FALSE;
149 }
150
151
152 static void 135 static void
153 gaim_upnp_timeout(gpointer data, 136 gaim_upnp_timeout(gpointer data,
154 gint source, 137 gint source,
155 GaimInputCondition cond) 138 GaimInputCondition cond)
156 { 139 {
157 HRD* hrd = data; 140 NetResponseData* nrd = data;
158 141
159 gaim_input_remove(hrd->inpa); 142 gaim_input_remove(nrd->inpa);
160 gaim_timeout_remove(hrd->tima); 143 gaim_timeout_remove(nrd->tima);
161 144
162 if(hrd->totalSizeRecv == 0) { 145 if(nrd->totalSizeRecv == 0 && nrd->recvBuffer != NULL) {
163 free(hrd->recvBuffer); 146 g_free(nrd->recvBuffer);
164 hrd->recvBuffer = NULL; 147 nrd->recvBuffer = NULL;
165 } else { 148 } else if(nrd->recvBuffer != NULL) {
166 hrd->recvBuffer[hrd->totalSizeRecv] = '\0'; 149 nrd->recvBuffer[nrd->totalSizeRecv] = '\0';
167 } 150 }
168 151
169 hrd->done = TRUE; 152 nrd->done = TRUE;
170 } 153 }
171 154
172 155
173 static void 156 static void
174 gaim_upnp_http_read(gpointer data, 157 gaim_upnp_http_read(gpointer data,
175 gint sock, 158 gint sock,
176 GaimInputCondition cond) 159 GaimInputCondition cond)
177 { 160 {
178 int sizeRecv; 161 int sizeRecv;
179 extern int errno; 162 extern int errno;
180 HRD* hrd = data; 163 NetResponseData* nrd = data;
181 164
182 sizeRecv = recv(sock, &(hrd->recvBuffer[hrd->totalSizeRecv]), 165 sizeRecv = recv(sock, &(nrd->recvBuffer[nrd->totalSizeRecv]),
183 MAX_DESCRIPTION_RECIEVE_SIZE-hrd->totalSizeRecv, 0); 166 MAX_DESCRIPTION_RECIEVE_SIZE-nrd->totalSizeRecv, 0);
184 if(sizeRecv < 0 && errno != EINTR) { 167 if(sizeRecv < 0 && errno != EINTR) {
185 gaim_debug_info("upnp", 168 gaim_debug_error("upnp",
186 "gaim_upnp_http_read(): recv < 0: %i!\n\n", errno); 169 "gaim_upnp_http_read(): recv < 0: %i!\n\n", errno);
187 free(hrd->recvBuffer); 170 g_free(nrd->recvBuffer);
188 hrd->recvBuffer = NULL; 171 nrd->recvBuffer = NULL;
189 gaim_timeout_remove(hrd->tima); 172 gaim_timeout_remove(nrd->tima);
190 gaim_input_remove(hrd->inpa); 173 gaim_input_remove(nrd->inpa);
191 hrd->done = TRUE; 174 nrd->done = TRUE;
192 return; 175 return;
193 }else if(errno == EINTR) { 176 }else if(errno == EINTR) {
194 sizeRecv = 0; 177 sizeRecv = 0;
195 } 178 }
196 hrd->totalSizeRecv += sizeRecv; 179 nrd->totalSizeRecv += sizeRecv;
197 180
198 if(sizeRecv == 0) { 181 if(sizeRecv == 0) {
199 if(hrd->totalSizeRecv == 0) { 182 gaim_timeout_remove(nrd->tima);
200 gaim_debug_info("upnp", 183 gaim_input_remove(nrd->inpa);
184 if(nrd->totalSizeRecv == 0) {
185 gaim_debug_error("upnp",
201 "gaim_upnp_http_read(): totalSizeRecv == 0\n\n"); 186 "gaim_upnp_http_read(): totalSizeRecv == 0\n\n");
202 free(hrd->recvBuffer); 187 g_free(nrd->recvBuffer);
203 hrd->recvBuffer = NULL; 188 nrd->recvBuffer = NULL;
204 } else { 189 } else {
205 hrd->recvBuffer[hrd->totalSizeRecv] = '\0'; 190 nrd->recvBuffer[nrd->totalSizeRecv] = '\0';
206 } 191 }
207 gaim_timeout_remove(hrd->tima); 192 nrd->done = TRUE;
208 gaim_input_remove(hrd->inpa);
209 hrd->done = TRUE;
210 } else { 193 } else {
211 gaim_timeout_remove(hrd->tima); 194 gaim_timeout_remove(nrd->tima);
212 gaim_input_remove(hrd->inpa); 195 gaim_input_remove(nrd->inpa);
213 hrd->tima = gaim_timeout_add(CONSECUTIVE_RECIEVE_TIMEOUT, 196 nrd->tima = gaim_timeout_add(CONSECUTIVE_RECIEVE_TIMEOUT,
214 (GSourceFunc)gaim_upnp_timeout, hrd); 197 (GSourceFunc)gaim_upnp_timeout, nrd);
215 hrd->inpa = gaim_input_add(sock, GAIM_INPUT_READ, 198 nrd->inpa = gaim_input_add(sock, GAIM_INPUT_READ,
216 gaim_upnp_http_read, hrd); 199 gaim_upnp_http_read, nrd);
217 } 200 }
218 201 }
219 } 202
220 203 static void
221 204 gaim_upnp_http_send(gpointer data,
222 205 gint sock,
223 static char* 206 GaimInputCondition cond)
224 gaim_upnp_http_request(const char* address, 207 {
225 unsigned short port,
226 const char* httpRequest)
227 {
228 int sock;
229 int sizeSent, totalSizeSent = 0; 208 int sizeSent, totalSizeSent = 0;
230 extern int errno; 209 extern int errno;
231 struct sockaddr_in serv_addr; 210 NetResponseData* nrd = data;
232 struct hostent *server; 211
233 char* recvBuffer; 212 gaim_timeout_remove(nrd->tima);
234 213 while(totalSizeSent < strlen(nrd->sendBuffer)) {
235 HRD* hrd = (HRD*)malloc(sizeof(HRD)); 214 sizeSent = send(sock,(gchar*)((int)nrd->sendBuffer+totalSizeSent),
236 if(hrd == NULL) { 215 strlen(nrd->sendBuffer)-totalSizeSent,0);
237 gaim_debug_info("upnp",
238 "gaim_upnp_http_request(): Failed in hrd MALLOC\n\n");
239 return NULL;
240 }
241
242 hrd->recvBuffer = NULL;
243 hrd->totalSizeRecv = 0;
244 hrd->done = FALSE;
245
246 hrd->recvBuffer = (char*)malloc(MAX_DESCRIPTION_RECIEVE_SIZE);
247 if(hrd->recvBuffer == NULL) {
248 gaim_debug_info("upnp",
249 "gaim_upnp_http_request(): Failed in recvBuffer MALLOC\n\n");
250 free(hrd);
251 return NULL;
252 }
253
254 sock = socket(AF_INET, SOCK_STREAM, 0);
255 if(sock < 0) {
256 gaim_debug_info("upnp",
257 "gaim_upnp_http_request(): Failed In sock creation\n\n");
258 free(hrd->recvBuffer);
259 free(hrd);
260 return NULL;
261 }
262
263 server = gethostbyname(address);
264 if(server == NULL) {
265 gaim_debug_info("upnp",
266 "gaim_upnp_http_request(): Failed In gethostbyname\n\n");
267 free(hrd->recvBuffer);
268 free(hrd);
269 close(sock);
270 return NULL;
271 }
272 memset((char*)&serv_addr, 0, sizeof(serv_addr));
273 serv_addr.sin_family = AF_INET;
274 memcpy(&serv_addr.sin_addr,
275 server->h_addr_list[0],
276 server->h_length);
277 serv_addr.sin_port = htons(port);
278
279 if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) < 0) {
280 gaim_debug_info("upnp",
281 "gaim_upnp_http_request(): Failed In connect\n\n");
282 free(hrd->recvBuffer);
283 free(hrd);
284 close(sock);
285 return NULL;
286 }
287
288 while(totalSizeSent < strlen(httpRequest)) {
289 sizeSent = send(sock,(char*)((int)httpRequest+totalSizeSent),
290 strlen(httpRequest),0);
291 if(sizeSent <= 0 && errno != EINTR) { 216 if(sizeSent <= 0 && errno != EINTR) {
292 gaim_debug_info("upnp", 217 gaim_debug_error("upnp",
293 "gaim_upnp_http_request(): Failed In send\n\n"); 218 "gaim_upnp_http_request(): Failed In send\n\n");
294 free(hrd->recvBuffer); 219 nrd->done = TRUE;
295 free(hrd); 220 g_free(nrd->recvBuffer);
221 nrd->recvBuffer = NULL;
296 close(sock); 222 close(sock);
297 return NULL; 223 return;
298 }else if(errno == EINTR) { 224 }else if(errno == EINTR) {
299 sizeSent = 0; 225 sizeSent = 0;
300 } 226 }
301 totalSizeSent += sizeSent; 227 totalSizeSent += sizeSent;
302 } 228 }
303 229
304 hrd->tima = gaim_timeout_add(RECIEVE_TIMEOUT, 230 nrd->tima = gaim_timeout_add(RECIEVE_TIMEOUT,
305 (GSourceFunc)gaim_upnp_timeout, hrd); 231 (GSourceFunc)gaim_upnp_timeout, nrd);
306 hrd->inpa = gaim_input_add(sock, GAIM_INPUT_READ, 232 nrd->inpa = gaim_input_add(sock, GAIM_INPUT_READ,
307 gaim_upnp_http_read, hrd); 233 gaim_upnp_http_read, nrd);
308 while (!hrd->done) { 234 while (!nrd->done) {
309 gtk_main_iteration(); 235 gtk_main_iteration();
310 } 236 }
311 close(sock); 237 close(sock);
312 238 }
313 recvBuffer = hrd->recvBuffer; 239
314 free(hrd); 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;
248 nrd->recvBuffer = (gchar*)g_malloc(MAX_DESCRIPTION_RECIEVE_SIZE);
249
250 nrd->tima = gaim_timeout_add(RECIEVE_TIMEOUT,
251 (GSourceFunc)gaim_upnp_timeout, nrd);
252
253 if(gaim_proxy_connect(NULL, address, port,
254 gaim_upnp_http_send, nrd)) {
255
256 gaim_debug_error("upnp", "Connect Failed: Address: %s @@@ Port %d @@@ Request %s\n\n",
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) {
264 gtk_main_iteration();
265 }
266 }
267
268 recvBuffer = nrd->recvBuffer;
269 g_free(nrd);
270
315 return recvBuffer; 271 return recvBuffer;
316 } 272 }
317 273
318 274
319 275
320 /* This function takes the HTTP response requesting the description xml from 276 static gboolean
321 * the UPnP enabled IGD. It also takes as input the URL the request was sent 277 gaim_upnp_compare_device(const xmlnode* device,
322 * to. 278 const gchar* deviceType)
323 * 279 {
324 * The description contains the URL needed to control the actions of the UPnP 280 xmlnode* deviceTypeNode = xmlnode_get_child(device, "deviceType");
325 * enabled IGD. This URL can be in the form of just a path, in whcih case we 281 if(deviceTypeNode == NULL) {
326 * have to append the path to the base URL. The base URL might be specified 282 return FALSE;
327 * in the XML, or it might not, in which case u append to the httpURL. 283 }
328 */ 284 return !g_ascii_strcasecmp(xmlnode_get_data(deviceTypeNode), deviceType);
329 285 }
330 /* at some point, maybe parse the description response using an xml library */ 286
331 static char* 287
332 gaim_upnp_parse_description_response(const char* httpResponse, 288 static gboolean
333 const char* httpURL) 289 gaim_upnp_compare_service(const xmlnode* service,
334 { 290 const gchar* serviceType)
335 char* wanIPConnectionStart; 291 {
336 char urlBaseTag[] = "<URLBase>"; 292 xmlnode* serviceTypeNode = xmlnode_get_child(service, "serviceType");
337 char urlBaseEndTag[] = "</URLBase>"; 293 if(serviceTypeNode == NULL) {
338 char controlURLTag[] = "<controlURL>"; 294 return FALSE;
339 char controlURLEndTag[] = "</controlURL>"; 295 }
340 char* urlBaseTagLoc; 296 return !g_ascii_strcasecmp(xmlnode_get_data(serviceTypeNode), serviceType);
341 char* urlBaseEndTagLoc; 297 }
342 char* controlURLTagLoc; 298
343 char* controlURLEndTagLoc; 299
344 int controlURLSize; 300
345 int baseURLSize; 301 static gchar*
346 char* controlURL; 302 gaim_upnp_parse_description_response(const gchar* httpResponse,
347 char* baseURL; 303 const gchar* httpURL,
348 304 const gchar* serviceType)
349 if(strstr(httpResponse, HTTP_OK) == NULL) { 305 {
350 gaim_debug_info("upnp", 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",
351 "parse_description_response(): Failed In HTTP_OK\n\n"); 318 "parse_description_response(): Failed In HTTP_OK\n\n");
352 return NULL; 319 return NULL;
353 } 320 }
354 321
355 if((wanIPConnectionStart = 322 /* find the root of the xml document */
356 strstr(httpResponse, SEARCH_REQUEST_DEVICE)) == NULL) { 323 if((xmlRoot = g_strstr_len(httpResponse, strlen(httpResponse),
357 gaim_debug_info("upnp", 324 "<root")) == NULL) {
358 "parse_description_response(): Failed SEARCH_REQUEST_DEVICE\n\n"); 325 gaim_debug_error("upnp",
359 return NULL; 326 "parse_description_response(): Failed finding root\n\n");
360 } 327 return NULL;
361 if((controlURLTagLoc = strstr(wanIPConnectionStart, controlURLTag)) 328 }
362 == NULL) { 329
363 gaim_debug_info("upnp", 330 /* create the xml root node */
364 "parse_description_response(): Failed In controlURLTagLoc\n\n"); 331 if((xmlRootNode = xmlnode_from_str(xmlRoot, -1)) == NULL) {
365 return NULL; 332 gaim_debug_error("upnp",
366 } 333 "parse_description_response(): Could not parse xml root node\n\n");
367 if((controlURLEndTagLoc = 334 return NULL;
368 strstr(wanIPConnectionStart, controlURLEndTag)) == NULL) { 335 }
369 gaim_debug_info("upnp", 336
370 "parse_description_response(): Failed In controlURLEndTagLoc\n\n"); 337 /* get the baseURL of the device */
371 return NULL; 338 if((baseURLNode = xmlnode_get_child(xmlRootNode,
372 } 339 "URLBase")) != NULL) {
373 340 baseURL = g_strdup(xmlnode_get_data(baseURLNode));
374
375 controlURLSize =
376 controlURLEndTagLoc-&controlURLTagLoc[strlen(controlURLTag)];
377 if((controlURL = (char*)malloc(controlURLSize+1)) == NULL) {
378 gaim_debug_info("upnp",
379 "parse_description_response(): Failed In MALLOC controlURL\n\n");
380 return NULL;
381 }
382 memcpy(controlURL, &controlURLTagLoc[strlen(controlURLTag)],
383 controlURLSize);
384 controlURL[controlURLSize] = '\0';
385
386
387 if((urlBaseTagLoc = strstr(httpResponse, urlBaseTag)) == NULL) {
388 if((baseURL = (char*)malloc(strlen(httpURL)+controlURLSize+1)) == NULL) {
389 gaim_debug_info("upnp",
390 "parse_description_response(): Failed In MALLOC baseURL\n\n");
391 return NULL;
392 }
393 memcpy(baseURL, httpURL, strlen(httpURL));
394 baseURL[strlen(httpURL)] = '\0';
395 } else { 341 } else {
396 if((urlBaseEndTagLoc = strstr(httpResponse, urlBaseEndTag)) == NULL) { 342 baseURL = g_strdup(httpURL);
397 gaim_debug_info("upnp", 343 }
398 "parse_description_response(): Failed In urlBaseEndTagLoc\n\n"); 344
399 return NULL; 345 /* get the serviceType child that has the service type as it's data */
400 } 346
401 baseURLSize = 347 /* get urn:schemas-upnp-org:device:InternetGatewayDevice:1
402 urlBaseEndTagLoc - &urlBaseTagLoc[strlen(urlBaseTag)]; 348 and it's devicelist */
403 if((baseURL = (char*)malloc(baseURLSize+controlURLSize+1)) == NULL) { 349 serviceTypeNode = xmlnode_get_child(xmlRootNode, "device");
404 gaim_debug_info("upnp", 350 while(!gaim_upnp_compare_device(serviceTypeNode,
405 "parse_description_response(): Failed 2nd MALLOC baseURL\n\n"); 351 "urn:schemas-upnp-org:device:InternetGatewayDevice:1") &&
406 return NULL; 352 serviceTypeNode != NULL) {
407 } 353 serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode);
408 memcpy(baseURL, &urlBaseTagLoc[strlen(urlBaseTag)], baseURLSize); 354 }
409 baseURL[baseURLSize] = '\0'; 355 if(serviceTypeNode == NULL) {
410 } 356 gaim_debug_error("upnp",
411 357 "parse_description_response(): could not get serviceTypeNode 1\n\n");
412 if(strstr(controlURL, "http://") == NULL) { 358 return NULL;
413 memcpy(&baseURL[strlen(baseURL)], controlURL, strlen(controlURL)+1); 359 }
414 free(controlURL); 360 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "deviceList");
415 controlURL = baseURL; 361 if(serviceTypeNode == NULL) {
362 gaim_debug_error("upnp",
363 "parse_description_response(): could not get serviceTypeNode 2\n\n");
364 return NULL;
365 }
366
367 /* get urn:schemas-upnp-org:device:WANDevice:1
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 }
386
387 /* get urn:schemas-upnp-org:device:WANConnectionDevice:1
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");
398 return NULL;
399 }
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 }
406
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);
413 }
414
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 */
423 if((controlURLNode = xmlnode_get_child(serviceTypeNode,
424 "controlURL")) == NULL) {
425 gaim_debug_error("upnp",
426 "parse_description_response(): Could not find controlURL\n\n");
427 return NULL;
428 }
429
430 if(g_strstr_len(xmlnode_get_data(controlURLNode),
431 SIZEOF_HTTP, "http://") == NULL &&
432 g_strstr_len(xmlnode_get_data(controlURLNode),
433 SIZEOF_HTTP, "HTTP://") == NULL) {
434 controlURL = g_strdup_printf("%s%s", baseURL,
435 xmlnode_get_data(controlURLNode));
416 }else{ 436 }else{
417 free(baseURL); 437 controlURL = g_strdup(xmlnode_get_data(controlURLNode));
418 } 438 }
439 g_free(baseURL);
440 xmlnode_free(xmlRootNode);
419 441
420 return controlURL; 442 return controlURL;
421 } 443 }
422 444
423 445
424 446 static gchar*
425 447 gaim_upnp_parse_description(const gchar* descriptionURL,
426 /* parse a url into it's approrpiate parts: 448 const gchar* serviceType)
427 address, port, path. return true on success, 449 {
428 false on failure */ 450 gchar* fullURL;
429 static gboolean 451 gchar* controlURL;
430 gaim_upnp_parse_url(const char* url, char** path, 452 gchar* httpResponse;
431 char** address, char** port) 453 gchar* httpRequest;
432 { 454
433 char* temp, *temp2; 455 gchar* descriptionXMLAddress;
434 456 gchar* descriptionAddressPort;
435 /* get the path */ 457 gchar* descriptionAddress;
436 if((temp = strchr(&url[SIZEOF_HTTP], '/')) < 0) { 458 gchar descriptionPort[MAX_PORT_SIZE];
437 gaim_debug_info("upnp", 459 int port = 0;
438 "gaim_upnp_parse_url(): Failed In 1\n\n");
439 return FALSE;
440 }
441 if((*path = (char*)malloc(strlen(temp)+1)) == NULL) {
442 gaim_debug_info("upnp",
443 "gaim_upnp_parse_url(): Failed In 2\n\n");
444 return FALSE;
445 }
446 memcpy(*path, temp, strlen(temp));
447 (*path)[strlen(temp)] = '\0';
448
449 /* get the port */
450 if((temp2 = strchr(&url[SIZEOF_HTTP], ':')) == NULL) {
451 gaim_debug_info("upnp",
452 "gaim_upnp_parse_url(): Failed In 3\n\n");
453 free(*path);
454 return FALSE;
455 }
456 if((*port = (char*)malloc(temp-temp2)) == NULL) {
457 gaim_debug_info("upnp",
458 "gaim_upnp_parse_url(): Failed In 4\n\n");
459 free(*path);
460 return FALSE;
461 }
462 memcpy(*port, &temp2[1], (temp-1)-temp2);
463 (*port)[(temp-1)-temp2] = '\0';
464
465 /* get the address */
466 if((*address = (char*)malloc((temp2-&url[SIZEOF_HTTP])+1)) == NULL) {
467 gaim_debug_info("upnp",
468 "gaim_upnp_parse_url(): Failed In 5\n\n");
469 free(*path);
470 free(*port);
471 return FALSE;
472 }
473 memcpy(*address, &url[SIZEOF_HTTP],
474 temp2-&url[SIZEOF_HTTP]);
475 (*address)[temp2-&url[SIZEOF_HTTP]] = '\0';
476
477 return TRUE;
478 }
479
480
481
482 /*
483 * This function takes the URL where the UPnP enabled IGD description is
484 * located at, and sends an HTTP request to retrieve that description. Once
485 * the description is retrieved, we send the response to the
486 * gaim_upnp_parse_description_response() function. This will parse the
487 * description, and return the control URL needed to control the IGD, which
488 * this function returns.
489 */
490 static char*
491 gaim_upnp_parse_description(const char* descriptionURL)
492 {
493 char* fullURL;
494 char* controlURL;
495 char* httpResponse;
496 char httpRequest[MAX_DESCRIPTION_HTTP_HEADER_SIZE];
497
498 char* descriptionXMLAddress;
499 char* descriptionAddressPort;
500 char* descriptionAddress;
501 char* descriptionPort;
502 unsigned short port;
503 460
504 /* parse the 4 above variables out of the descriptionURL 461 /* parse the 4 above variables out of the descriptionURL
505 example description URL: http://192.168.1.1:5678/rootDesc.xml */ 462 example description URL: http://192.168.1.1:5678/rootDesc.xml */
506 463
507 /* parse the url into address, port, path variables */ 464 /* parse the url into address, port, path variables */
508 if(!gaim_upnp_parse_url(descriptionURL, &descriptionXMLAddress, 465 if(!gaim_url_parse(descriptionURL, &descriptionAddress,
509 &descriptionAddress, &descriptionPort)) { 466 &port, &descriptionXMLAddress, NULL, NULL)) {
510 return NULL; 467 return NULL;
511 } 468 }
512 if((port = atoi(descriptionPort)) == 0) { 469 if(port == 0 || port == -1) {
513 gaim_debug_info("upnp", 470 port = DEFAULT_HTTP_PORT;
514 "gaim_upnp_parse_description(): failed atoi\n\n"); 471 }
515 free(descriptionXMLAddress); 472 g_ascii_dtostr(descriptionPort, MAX_PORT_SIZE, port);
516 free(descriptionAddress); 473 descriptionAddressPort = g_strdup_printf("%s:%s", descriptionAddress,
517 free(descriptionPort); 474 descriptionPort);
518 return NULL; 475
519 } 476 fullURL = g_strdup_printf("http://%s", descriptionAddressPort);
520
521 if((descriptionAddressPort = (char*)malloc(strlen(descriptionAddress) +
522 strlen(descriptionPort) + 2))
523 == NULL) {
524 gaim_debug_info("upnp",
525 "gaim_upnp_parse_description(): failed MALLOC desAddPort\n\n");
526 free(descriptionXMLAddress);
527 free(descriptionAddress);
528 free(descriptionPort);
529 return NULL;
530 }
531 sprintf(descriptionAddressPort, "%s:%s",
532 descriptionAddress, descriptionPort);
533
534 if((fullURL = (char*)malloc(strlen(descriptionAddressPort) +
535 SIZEOF_HTTP + 1)) == NULL) {
536 gaim_debug_info("upnp",
537 "gaim_upnp_parse_description(): failed MALLOC fullURL\n\n");
538 free(descriptionXMLAddress);
539 free(descriptionAddress);
540 free(descriptionPort);
541 free(descriptionAddressPort);
542 }
543 sprintf(fullURL, "http://%s", descriptionAddressPort);
544 477
545 /* for example... 478 /* for example...
546 GET /rootDesc.xml HTTP/1.1\r\nHost: 192.168.1.1:5678\r\n\r\n */ 479 GET /rootDesc.xml HTTP/1.1\r\nHost: 192.168.1.1:5678\r\n\r\n */
547 sprintf(httpRequest, "GET %s HTTP/1.1\r\nHost: %s\r\n\r\n", 480 httpRequest = g_strdup_printf("GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n",
548 descriptionXMLAddress, descriptionAddressPort); 481 descriptionXMLAddress, descriptionAddressPort);
549 482
550 httpResponse = gaim_upnp_http_request(descriptionAddress, 483 httpResponse = gaim_upnp_http_request(descriptionAddress,
551 port, httpRequest); 484 port, httpRequest);
552 if(httpResponse == NULL) { 485 if(httpResponse == NULL) {
553 gaim_debug_info("upnp", 486 gaim_debug_error("upnp",
554 "gaim_upnp_parse_description(): httpResponse is NULL\n\n"); 487 "gaim_upnp_parse_description(): httpResponse is NULL\n\n");
555 free(descriptionXMLAddress); 488 g_free(descriptionXMLAddress);
556 free(descriptionAddress); 489 g_free(descriptionAddress);
557 free(descriptionPort); 490 g_free(descriptionAddressPort);
558 free(descriptionAddressPort); 491 g_free(httpRequest);
559 free(fullURL); 492 g_free(fullURL);
560 return NULL; 493 return NULL;
561 } 494 }
562 495
563 controlURL = gaim_upnp_parse_description_response(httpResponse, fullURL); 496 controlURL = gaim_upnp_parse_description_response(httpResponse,
564 497 fullURL, serviceType);
565 free(descriptionXMLAddress); 498
566 free(descriptionAddress); 499 g_free(descriptionXMLAddress);
567 free(descriptionPort); 500 g_free(descriptionAddress);
568 free(descriptionAddressPort); 501 g_free(descriptionAddressPort);
569 free(fullURL); 502 g_free(fullURL);
570 free(httpResponse); 503 g_free(httpRequest);
504 g_free(httpResponse);
571 505
572 if(controlURL == NULL) { 506 if(controlURL == NULL) {
573 gaim_debug_info("upnp", 507 gaim_debug_error("upnp",
574 "gaim_upnp_parse_description(): controlURL is NULL\n\n"); 508 "gaim_upnp_parse_description(): controlURL is NULL\n\n");
575 return NULL; 509 return NULL;
576 } 510 }
577 511
578 return controlURL; 512 return controlURL;
579 } 513 }
580 514
581 515
582 static char* 516 static gchar*
583 gaim_upnp_parse_discover_response(const char* buf, 517 gaim_upnp_parse_discover_response(const gchar* buf,
584 unsigned int bufSize) 518 unsigned int bufSize,
585 { 519 const gchar* serviceType)
586 char* startDescURL; 520 {
587 char* endDescURL; 521 gchar* startDescURL;
588 char* descURL; 522 gchar* endDescURL;
589 unsigned int descURLSize; 523 gchar* descURL;
590 char* retVal; 524 gchar* retVal;
591 525
592 if(strstr(buf, HTTP_OK) == NULL) { 526 if(g_strstr_len(buf, strlen(buf), HTTP_OK) == NULL) {
593 gaim_debug_info("upnp", 527 gaim_debug_error("upnp",
594 "parse_discover_response(): Failed In HTTP_OK\n\n"); 528 "parse_discover_response(): Failed In HTTP_OK\n\n");
595 return NULL; 529 return NULL;
596 } 530 }
597 531
598 if((startDescURL = strstr(buf, "http://")) == NULL) { 532 if((startDescURL = g_strstr_len(buf, strlen(buf), "http://")) == NULL) {
599 gaim_debug_info("upnp", 533 gaim_debug_error("upnp",
600 "parse_description_response(): Failed In finding http://\n\n"); 534 "parse_discover_response(): Failed In finding http://\n\n");
601 return NULL; 535 return NULL;
602 } 536 }
603 537
604 endDescURL = strchr(startDescURL, '\r'); 538 endDescURL = g_strstr_len(startDescURL, strlen(startDescURL), "\r");
605 if(endDescURL == NULL) { 539 if(endDescURL == NULL) {
606 endDescURL = strchr(startDescURL, '\n'); 540 endDescURL = g_strstr_len(startDescURL, strlen(startDescURL), "\n");
607 if(endDescURL == NULL) { 541 if(endDescURL == NULL) {
608 gaim_debug_info("upnp", 542 gaim_debug_error("upnp",
609 "parse_description_response(): Failed In endDescURL\n\n"); 543 "parse_discover_response(): Failed In endDescURL\n\n");
610 return NULL; 544 return NULL;
611 }else if(endDescURL == startDescURL) { 545 }else if(endDescURL == startDescURL) {
612 gaim_debug_info("upnp", 546 gaim_debug_error("upnp",
613 "parse_description_response(): endDescURL == startDescURL\n\n"); 547 "parse_discover_response(): endDescURL == startDescURL\n\n");
614 return NULL; 548 return NULL;
615 } 549 }
616 }else if(endDescURL == startDescURL) { 550 }else if(endDescURL == startDescURL) {
617 gaim_debug_info("upnp", 551 gaim_debug_error("upnp",
618 "parse_description_response(): 2nd endDescURL == startDescURL\n\n"); 552 "parse_discover_response(): 2nd endDescURL == startDescURL\n\n");
619 return NULL; 553 return NULL;
620 } 554 }
621 555 descURL = g_strndup(startDescURL, endDescURL-startDescURL);
622 descURLSize = (endDescURL-startDescURL)+1; 556
623 descURL = (char*)malloc(descURLSize); 557 retVal = gaim_upnp_parse_description(descURL, serviceType);
624 memcpy(descURL, startDescURL, descURLSize-1); 558 g_free(descURL);
625 descURL[descURLSize-1] = '\0';
626
627 retVal = gaim_upnp_parse_description(descURL);
628 free(descURL);
629 return retVal; 559 return retVal;
630 } 560 }
631 561
632 562
633 563
638 { 568 {
639 unsigned int length; 569 unsigned int length;
640 extern int errno; 570 extern int errno;
641 struct sockaddr_in from; 571 struct sockaddr_in from;
642 int sizeRecv; 572 int sizeRecv;
643 HRD* hrd = data; 573 NetResponseData* nrd = data;
644 574
645 gaim_timeout_remove(hrd->tima); 575 gaim_timeout_remove(nrd->tima);
646 length = sizeof(struct sockaddr_in); 576 length = sizeof(struct sockaddr_in);
647 577
648 do { 578 do {
649 sizeRecv = recvfrom(sock, hrd->recvBuffer, 579 sizeRecv = recvfrom(sock, nrd->recvBuffer,
650 MAX_DISCOVERY_RECIEVE_SIZE, 0, 580 MAX_DISCOVERY_RECIEVE_SIZE, 0,
651 (struct sockaddr*)&from, &length); 581 (struct sockaddr*)&from, &length);
652 582
653 if(sizeRecv > 0) { 583 if(sizeRecv > 0) {
654 hrd->recvBuffer[sizeRecv] = '\0'; 584 nrd->recvBuffer[sizeRecv] = '\0';
655 }else if(errno != EINTR) { 585 }else if(errno != EINTR) {
656 free(hrd->recvBuffer); 586 g_free(nrd->recvBuffer);
657 hrd->recvBuffer = NULL; 587 nrd->recvBuffer = NULL;
658 } 588 }
659 }while(errno == EINTR); 589 }while(errno == EINTR);
660 590
661 gaim_input_remove(hrd->inpa); 591 gaim_input_remove(nrd->inpa);
662 hrd->done = TRUE; 592 nrd->done = TRUE;
663 return; 593 return;
664 } 594 }
665 595
666 596
667 597
668 char* 598 GaimUPnPControlInfo*
669 gaim_upnp_discover(void) 599 gaim_upnp_discover(void)
670 { 600 {
601 /* Socket Setup Variables */
671 int sock, i; 602 int sock, i;
603 extern int errno;
604 struct sockaddr_in server;
605 struct hostent* hp;
606
607 /* UDP SEND VARIABLES */
608 gboolean sentSuccess, recvSuccess;
672 int sizeSent, totalSizeSent; 609 int sizeSent, totalSizeSent;
673 extern int errno; 610 gchar wanIP[] = "WANIPConnection:1";
674 gboolean sentSuccess, recvSuccess; 611 gchar wanPPP[] = "WANPPPConnection:1";
675 struct sockaddr_in server; 612 gchar* serviceToUse;
676 struct hostent *hp; 613 gchar* sendMessage = NULL;
677 char sendMessage[] = SEARCH_REQUEST_STRING; 614
678 char *controlURL = NULL; 615 /* UDP RECIEVE VARIABLES */
679 616 GaimUPnPControlInfo* controlInfo = g_malloc(sizeof(GaimUPnPControlInfo));
680 HRD* hrd = (HRD*)malloc(sizeof(HRD)); 617 NetResponseData* nrd = g_malloc(sizeof(NetResponseData));
681 if(hrd == NULL) { 618
682 gaim_debug_info("upnp", 619 /* Set up the sockets */
683 "gaim_upnp_discover(): Failed in hrd MALLOC\n\n");
684 return NULL;
685 }
686
687 sock = socket(AF_INET, SOCK_DGRAM, 0); 620 sock = socket(AF_INET, SOCK_DGRAM, 0);
688 if (sock == -1) { 621 if (sock == -1) {
689 close(sock); 622 close(sock);
690 gaim_debug_info("upnp", 623 gaim_debug_error("upnp",
691 "gaim_upnp_discover(): Failed In sock creation\n\n"); 624 "gaim_upnp_discover(): Failed In sock creation\n\n");
692 free(hrd->recvBuffer); 625 g_free(nrd);
693 free(hrd); 626 g_free(controlInfo);
694 return NULL; 627 return NULL;
695 } 628 }
696
697 memset(&server, 0, sizeof(struct sockaddr)); 629 memset(&server, 0, sizeof(struct sockaddr));
698 server.sin_family = AF_INET; 630 server.sin_family = AF_INET;
699 if((hp = gethostbyname(HTTPMU_HOST_ADDRESS)) == NULL) { 631 if((hp = gethostbyname(HTTPMU_HOST_ADDRESS)) == NULL) {
700 close(sock); 632 close(sock);
701 gaim_debug_info("upnp", 633 gaim_debug_error("upnp",
702 "gaim_upnp_discover(): Failed In gethostbyname\n\n"); 634 "gaim_upnp_discover(): Failed In gethostbyname\n\n");
703 free(hrd->recvBuffer); 635 g_free(nrd);
704 free(hrd); 636 g_free(controlInfo);
705 return NULL; 637 return NULL;
706 } 638 }
707
708 memcpy(&server.sin_addr, 639 memcpy(&server.sin_addr,
709 hp->h_addr_list[0], 640 hp->h_addr_list[0],
710 hp->h_length); 641 hp->h_length);
711 server.sin_port = htons(HTTPMU_HOST_PORT); 642 server.sin_port = htons(HTTPMU_HOST_PORT);
712 643
713 /* because we are sending over UDP, if there is a failure 644 /* because we are sending over UDP, if there is a failure
714 we should retry the send NUM_UDP_ATTEMPTS times */ 645 we should retry the send NUM_UDP_ATTEMPTS times. Also,
646 try different requests for WANIPConnection and
647 WANPPPConnection*/
715 for(i = 0; i < NUM_UDP_ATTEMPTS; i++) { 648 for(i = 0; i < NUM_UDP_ATTEMPTS; i++) {
716 sentSuccess = TRUE; 649 sentSuccess = TRUE;
717 recvSuccess = TRUE; 650 recvSuccess = TRUE;
718 totalSizeSent = 0; 651 totalSizeSent = 0;
719 652
720 hrd->recvBuffer = NULL; 653 nrd->recvBuffer = NULL;
721 hrd->totalSizeRecv = 0; 654 nrd->totalSizeRecv = 0;
722 hrd->done = FALSE; 655 nrd->done = FALSE;
723 656
724 hrd->recvBuffer = (char*)malloc(MAX_DISCOVERY_RECIEVE_SIZE); 657 if(sendMessage != NULL) {
725 if(hrd->recvBuffer == NULL) { 658 g_free(sendMessage);
726 gaim_debug_info("upnp", 659 }
727 "gaim_upnp_discover(): Failed in hrd->recvBuffer MALLOC\n\n"); 660
728 free(hrd); 661 if(i%2 == 0) {
729 return NULL; 662 serviceToUse = wanIP;
730 } 663 } else {
664 serviceToUse = wanPPP;
665 }
666 sendMessage = g_strdup_printf(SEARCH_REQUEST_STRING, serviceToUse);
667
668 nrd->recvBuffer = (char*)g_malloc(MAX_DISCOVERY_RECIEVE_SIZE);
731 669
732 while(totalSizeSent < strlen(sendMessage)) { 670 while(totalSizeSent < strlen(sendMessage)) {
733 sizeSent = sendto(sock,(void*)&sendMessage[totalSizeSent], 671 sizeSent = sendto(sock,(void*)&sendMessage[totalSizeSent],
734 strlen(&sendMessage[totalSizeSent]),0, 672 strlen(&sendMessage[totalSizeSent]),0,
735 (struct sockaddr*)&server, 673 (struct sockaddr*)&server,
742 } 680 }
743 totalSizeSent += sizeSent; 681 totalSizeSent += sizeSent;
744 } 682 }
745 683
746 if(sentSuccess) { 684 if(sentSuccess) {
747 hrd->tima = gaim_timeout_add(DISCOVERY_TIMEOUT, 685 nrd->tima = gaim_timeout_add(DISCOVERY_TIMEOUT,
748 (GSourceFunc)gaim_upnp_timeout, hrd); 686 (GSourceFunc)gaim_upnp_timeout, nrd);
749 hrd->inpa = gaim_input_add(sock, GAIM_INPUT_READ, 687 nrd->inpa = gaim_input_add(sock, GAIM_INPUT_READ,
750 gaim_upnp_discover_udp_read, hrd); 688 gaim_upnp_discover_udp_read, nrd);
751 while (!hrd->done) { 689 while (!nrd->done) {
752 gtk_main_iteration(); 690 gtk_main_iteration();
753 } 691 }
754 if(hrd->recvBuffer == NULL) { 692 if(nrd->recvBuffer == NULL) {
755 recvSuccess = FALSE; 693 recvSuccess = FALSE;
756 } else { 694 } else {
757 /* parse the response, and see if it was a success */ 695 /* parse the response, and see if it was a success */
758 close(sock); 696 close(sock);
759 if((controlURL= 697 if((controlInfo->controlURL=
760 gaim_upnp_parse_discover_response(hrd->recvBuffer, 698 gaim_upnp_parse_discover_response(nrd->recvBuffer,
761 strlen(hrd->recvBuffer)))==NULL) { 699 strlen(nrd->recvBuffer),
762 gaim_debug_info("upnp", 700 serviceToUse))==NULL) {
701 gaim_debug_error("upnp",
763 "gaim_upnp_discover(): Failed In parse response\n\n"); 702 "gaim_upnp_discover(): Failed In parse response\n\n");
764 free(hrd->recvBuffer); 703 g_free(nrd->recvBuffer);
765 free(hrd); 704 g_free(nrd);
705 g_free(controlInfo);
766 return NULL; 706 return NULL;
767 } 707 }
708
709 controlInfo->serviceType = g_strdup(serviceToUse);
768 } 710 }
769 } 711 }
770 712
771 /* if sent success and recv successful, then break */ 713 /* if sent success and recv successful, then break */
772 if(sentSuccess && recvSuccess) { 714 if(sentSuccess && recvSuccess) {
773 i = NUM_UDP_ATTEMPTS; 715 i = NUM_UDP_ATTEMPTS;
774 } 716 }
775 } 717 }
776 718
777 if(hrd->recvBuffer != NULL) { 719 if(nrd->recvBuffer != NULL) {
778 free(hrd->recvBuffer); 720 g_free(nrd->recvBuffer);
779 } 721 }
780 free(hrd); 722 g_free(sendMessage);
723 g_free(nrd);
781 724
782 if(!sentSuccess || !recvSuccess) { 725 if(!sentSuccess || !recvSuccess) {
783 close(sock); 726 close(sock);
784 gaim_debug_info("upnp", 727 gaim_debug_error("upnp",
785 "gaim_upnp_discover(): Failed In sent/recv success\n\n"); 728 "gaim_upnp_discover(): Failed In sent/recv success\n\n");
786 return NULL; 729 g_free(controlInfo);
787 } 730 return NULL;
788 731 }
789 return controlURL; 732
790 } 733 return controlInfo;
791 734 }
792
793 735
794 736
795 static char* 737 static char*
796 gaim_upnp_generate_action_message_and_send(const char* controlURL, 738 gaim_upnp_generate_action_message_and_send(const GaimUPnPControlInfo* controlInfo,
797 const char* actionName, 739 const gchar* actionName,
798 const char* actionParams) 740 const gchar* actionParams)
799 { 741 {
800 char serviceType[] = "WANIPConnection:1"; 742 gchar* actionMessage;
801 char* actionMessage; 743 gchar* soapMessage;
802 char* soapMessage; 744 gchar* totalSendMessage;
803 char* httpResponse; 745 gchar* httpResponse;
804 746
805 char* pathOfControl; 747 gchar* pathOfControl;
806 char* addressOfControl; 748 gchar* addressOfControl;
807 char* addressPortOfControl; 749 gchar* addressPortOfControl;
808 char* portOfControl; 750 gchar portOfControl[MAX_PORT_SIZE];
809 unsigned short port; 751 int port=0;
810 752
811 /* set the soap message */ 753 /* set the soap message */
812 if((soapMessage = (char*)malloc(strlen(SOAP_ACTION) + 754 soapMessage = g_strdup_printf(SOAP_ACTION, actionName,
813 strlen(serviceType) + 755 controlInfo->serviceType,
814 strlen(actionParams) + 756 actionParams, actionName);
815 strlen(actionName) +
816 strlen(actionName))) == NULL) {
817 gaim_debug_info("upnp",
818 "generate_action_message_and_send(): Failed MALLOC soapMessage\n\n");
819 return NULL;
820 }
821 sprintf(soapMessage, SOAP_ACTION, actionName, serviceType,
822 actionParams, actionName);
823 757
824 /* parse the url into address, port, path variables */ 758 /* parse the url into address, port, path variables */
825 if(!gaim_upnp_parse_url(controlURL, &pathOfControl, 759 if(!gaim_url_parse(controlInfo->controlURL, &addressOfControl,
826 &addressOfControl, &portOfControl)) { 760 &port, &pathOfControl, NULL, NULL)) {
827 gaim_debug_info("upnp", 761 gaim_debug_error("upnp",
828 "generate_action_message_and_send(): Failed In Parse URL\n\n"); 762 "generate_action_message_and_send(): Failed In Parse URL\n\n");
829 free(soapMessage); 763 g_free(soapMessage);
830 return NULL; 764 return NULL;
831 } 765 }
766 if(port == 0 || port == -1) {
767 port = DEFAULT_HTTP_PORT;
768 }
769 g_ascii_dtostr(portOfControl, MAX_PORT_SIZE, port);
832 770
833 /* set the addressPortOfControl variable which should have a 771 /* set the addressPortOfControl variable which should have a
834 form like the following: 192.168.1.1:8000 */ 772 form like the following: 192.168.1.1:8000 */
835 if((addressPortOfControl = (char*)malloc(strlen(addressOfControl) + 773 addressPortOfControl = g_strdup_printf("%s:%s",
836 strlen(portOfControl) + 774 addressOfControl, portOfControl);
837 2)) == NULL) {
838 gaim_debug_info("upnp",
839 "generate_action_message_and_send(): MALLOC addressPortOfControl\n\n");
840 free(soapMessage);
841 free(pathOfControl);
842 free(addressOfControl);
843 free(portOfControl);
844 return NULL;
845 }
846 sprintf(addressPortOfControl, "%s:%s", addressOfControl, portOfControl);
847 if((port = atoi(portOfControl)) == 0) {
848 gaim_debug_info("upnp",
849 "generate_action_message_and_send(): Failed In port = atoi\n\n");
850 free(soapMessage);
851 free(pathOfControl);
852 free(addressOfControl);
853 free(portOfControl);
854 free(addressPortOfControl);
855 return NULL;
856 }
857 775
858 /* set the HTTP Header */ 776 /* set the HTTP Header */
859 if((actionMessage = (char*)malloc(strlen(HTTP_HEADER_ACTION) + 777 actionMessage = g_strdup_printf(HTTP_HEADER_ACTION,
860 strlen(pathOfControl) + 778 pathOfControl, addressPortOfControl,
861 strlen(addressPortOfControl) + 779 controlInfo->serviceType, actionName,
862 strlen(serviceType) + 780 strlen(soapMessage));
863 strlen(actionName) +
864 strlen(soapMessage))) == NULL) {
865 gaim_debug_info("upnp",
866 "generate_action_message_and_send(): Failed MALLOC actionMessage\n\n");
867 free(soapMessage);
868 free(pathOfControl);
869 free(addressOfControl);
870 free(portOfControl);
871 free(addressPortOfControl);
872 return NULL;
873 }
874 sprintf(actionMessage, HTTP_HEADER_ACTION,
875 pathOfControl, addressPortOfControl,
876 serviceType, actionName, strlen(soapMessage));
877 781
878 /* append to the header the body */ 782 /* append to the header the body */
879 strcat(actionMessage, soapMessage); 783 totalSendMessage = g_strdup_printf("%s%s", actionMessage, soapMessage);
880 784
881 /* get the return of the http response */ 785 /* get the return of the http response */
882 httpResponse = gaim_upnp_http_request(addressOfControl, 786 httpResponse = gaim_upnp_http_request(addressOfControl,
883 port, actionMessage); 787 port, totalSendMessage);
884 if(httpResponse == NULL) { 788 if(httpResponse == NULL) {
885 gaim_debug_info("upnp", 789 gaim_debug_error("upnp",
886 "generate_action_message_and_send(): Failed In httpResponse\n\n"); 790 "generate_action_message_and_send(): Failed In httpResponse\n\n");
887 } 791 }
888 792
889 free(actionMessage); 793 g_free(actionMessage);
890 free(soapMessage); 794 g_free(soapMessage);
891 free(pathOfControl); 795 g_free(totalSendMessage);
892 free(addressOfControl); 796 g_free(pathOfControl);
893 free(portOfControl); 797 g_free(addressOfControl);
894 free(addressPortOfControl); 798 g_free(addressPortOfControl);
895 799
896 return httpResponse; 800 return httpResponse;
897 } 801 }
898 802
899 803
900 804
901 805
902 char* 806 gchar*
903 gaim_upnp_get_public_ip(const char* controlURL) 807 gaim_upnp_get_public_ip(const GaimUPnPControlInfo* controlInfo)
904 { 808 {
905 char* extIPAddress; 809 gchar* extIPAddress;
906 char* httpResponse; 810 gchar* httpResponse;
907 char actionName[] = "GetExternalIPAddress"; 811 gchar actionName[] = "GetExternalIPAddress";
908 char actionParams[] = ""; 812 gchar actionParams[] = "";
909 char* temp, *temp2; 813 gchar* temp, *temp2;
910 814
911 /* make sure controlURL is a valid URL */ 815 httpResponse = gaim_upnp_generate_action_message_and_send(controlInfo,
912 if(!gaim_upnp_validate_url(controlURL)) {
913 gaim_debug_info("upnp",
914 "gaim_upnp_get_public_ip(): Failed In Validate URL\n\n");
915 return NULL;
916 }
917
918 httpResponse = gaim_upnp_generate_action_message_and_send(controlURL,
919 actionName, 816 actionName,
920 actionParams); 817 actionParams);
921 if(httpResponse == NULL) { 818 if(httpResponse == NULL) {
922 gaim_debug_info("upnp", 819 gaim_debug_error("upnp",
923 "gaim_upnp_get_public_ip(): Failed In httpResponse\n\n"); 820 "gaim_upnp_get_public_ip(): Failed In httpResponse\n\n");
924 return NULL; 821 return NULL;
925 } 822 }
926 823
927 /* extract the ip, or see if there is an error */ 824 /* extract the ip, or see if there is an error */
928 /* at some point, maybe extract the ip using an xml library */ 825 if((temp = g_strstr_len(httpResponse, strlen(httpResponse),
929 if((temp = strstr(httpResponse, "<NewExternalIPAddress")) == NULL) { 826 "<NewExternalIPAddress")) == NULL) {
930 gaim_debug_info("upnp", 827 gaim_debug_error("upnp",
931 "gaim_upnp_get_public_ip(): Failed Finding <NewExternalIPAddress\n\n"); 828 "gaim_upnp_get_public_ip(): Failed Finding <NewExternalIPAddress\n\n");
932 free(httpResponse); 829 g_free(httpResponse);
933 return NULL; 830 return NULL;
934 } 831 }
935 if((temp = strchr(temp, '>')) == NULL) { 832 if((temp = g_strstr_len(temp, strlen(temp), ">")) == NULL) {
936 gaim_debug_info("upnp", 833 gaim_debug_error("upnp",
937 "gaim_upnp_get_public_ip(): Failed In Finding >\n\n"); 834 "gaim_upnp_get_public_ip(): Failed In Finding >\n\n");
938 free(httpResponse); 835 g_free(httpResponse);
939 return NULL; 836 return NULL;
940 } 837 }
941 if((temp2 = strchr(temp, '<')) == NULL) { 838 if((temp2 = g_strstr_len(temp, strlen(temp), "<")) == NULL) {
942 gaim_debug_info("upnp", 839 gaim_debug_error("upnp",
943 "gaim_upnp_get_public_ip(): Failed In Finding <\n\n"); 840 "gaim_upnp_get_public_ip(): Failed In Finding <\n\n");
944 free(httpResponse); 841 g_free(httpResponse);
945 return NULL; 842 return NULL;
946 } 843 }
947 if((extIPAddress = (char*)malloc(temp2-temp)) == NULL) { 844
948 gaim_debug_info("upnp", 845 extIPAddress = g_strndup(&temp[1], (temp2-1)-temp);
949 "gaim_upnp_get_public_ip(): Failed In MALLOC extIPAddress\n\n"); 846
950 free(httpResponse); 847 g_free(httpResponse);
951 return NULL; 848
952 } 849 gaim_debug_info("upnp", "NAT Returned IP: %s\n", extIPAddress);
953 memcpy(extIPAddress, &temp[1], (temp2-1)-temp);
954 extIPAddress[(temp2-1)-temp] = '\0';
955
956 free(httpResponse);
957 gaim_debug_info("upnp",
958 "gaim_upnp_get_public_ip() IP: %s\n\n", extIPAddress);
959 return extIPAddress; 850 return extIPAddress;
960 } 851 }
961 852
962 853 static void
963 854 gaim_upnp_get_local_system_ip(gpointer data,
964 static const char* 855 gint sock,
965 gaim_upnp_get_local_ip_address(const char* address) { 856 GaimInputCondition cond)
966 const char* ip; 857 {
967 int sock; 858 NetResponseData* nrd = data;
968 struct sockaddr_in serv_addr; 859 nrd->recvBuffer = gaim_network_get_local_system_ip(sock);
969 struct hostent *server; 860
970 char* pathOfControl; 861 gaim_timeout_remove(nrd->tima);
971 char* addressOfControl; 862 nrd->done = TRUE;
972 char* portOfControl; 863
973 unsigned short port; 864 close(sock);
974 865 }
975 /* parse the url into address, port, path variables */ 866
976 if(!gaim_upnp_parse_url(address, &pathOfControl, 867 static const gchar*
977 &addressOfControl, &portOfControl)) { 868 gaim_upnp_get_local_ip_address(const gchar* address)
978 gaim_debug_info("upnp", 869 {
870 const gchar* ip;
871 gchar* pathOfControl;
872 gchar* addressOfControl;
873 int port = 0;
874 NetResponseData* nrd = (NetResponseData*)g_malloc0(sizeof(NetResponseData));
875
876 if(!gaim_url_parse(address, &addressOfControl,
877 &port, &pathOfControl, NULL, NULL)) {
878 gaim_debug_error("upnp",
979 "get_local_ip_address(): Failed In Parse URL\n\n"); 879 "get_local_ip_address(): Failed In Parse URL\n\n");
980 return NULL; 880 return NULL;
981 } 881 }
982 if((port = atoi(portOfControl)) == 0) { 882 if(port == 0 || port == -1) {
983 gaim_debug_info("upnp", 883 port = DEFAULT_HTTP_PORT;
984 "get_local_ip_address(): Failed In port = atoi\n\n"); 884 }
985 return NULL; 885
986 } 886 nrd->tima = gaim_timeout_add(RECIEVE_TIMEOUT,
987 887 (GSourceFunc)gaim_upnp_timeout, nrd);
988 sock = socket(AF_INET, SOCK_STREAM, 0); 888
989 if(sock < 0) { 889 if(gaim_proxy_connect(NULL, addressOfControl, port,
990 gaim_debug_info("upnp", 890 gaim_upnp_get_local_system_ip, nrd)) {
991 "get_local_ip_address(): Failed In sock creation\n\n"); 891
992 return NULL; 892 gaim_debug_error("upnp", "Get Local IP Connect Failed: Address: %s @@@ Port %d @@@ Request %s\n\n",
993 } 893 address, port, nrd->sendBuffer);
994 894
995 server = gethostbyname(addressOfControl); 895 gaim_timeout_remove(nrd->tima);
996 if(server == NULL) { 896 } else {
997 gaim_debug_info("upnp", 897 while (!nrd->done) {
998 "get_local_ip_address(): Failed In gethostbyname\n\n"); 898 gtk_main_iteration();
999 close(sock); 899 }
1000 return NULL; 900 }
1001 } 901
1002 memset((char*)&serv_addr, 0, sizeof(serv_addr)); 902 ip = nrd->recvBuffer;
1003 serv_addr.sin_family = AF_INET; 903 g_free(nrd);
1004 memcpy(&serv_addr.sin_addr, 904
1005 server->h_addr_list[0], 905 gaim_debug_info("upnp", "local ip: %s\n", ip);
1006 server->h_length); 906
1007 serv_addr.sin_port = htons(port);
1008
1009 if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) < 0) {
1010 gaim_debug_info("upnp",
1011 "get_local_ip_address(): Failed In connect\n\n");
1012 close(sock);
1013 return NULL;
1014 }
1015
1016 ip = gaim_network_get_local_system_ip(sock);
1017
1018 close(sock);
1019 return ip; 907 return ip;
1020 } 908 }
1021 909
1022 910
1023 911
1024 gboolean 912 gboolean
1025 gaim_upnp_set_port_mapping(const char* controlURL, unsigned short portMap, 913 gaim_upnp_set_port_mapping(const GaimUPnPControlInfo* controlInfo,
1026 const char* protocol) 914 unsigned short portMap,
1027 { 915 const gchar* protocol)
1028 char* httpResponse; 916 {
1029 char actionName[] = "AddPortMapping"; 917 gchar* httpResponse;
1030 char* actionParams; 918 gchar actionName[] = "AddPortMapping";
1031 const char* internalIP; 919 gchar* actionParams;
1032 920 const gchar* internalIP;
1033 /* make sure controlURL is a valid URL */
1034 if(!gaim_upnp_validate_url(controlURL)) {
1035 gaim_debug_info("upnp",
1036 "gaim_upnp_set_port_mapping(): Failed In Validate URL\n\n");
1037 return FALSE;
1038 }
1039 921
1040 /* get the internal IP */ 922 /* get the internal IP */
1041 if((internalIP = gaim_upnp_get_local_ip_address(controlURL)) == NULL) { 923 if((internalIP = gaim_upnp_get_local_ip_address(controlInfo->controlURL))
1042 gaim_debug_info("upnp", 924 == NULL) {
925 gaim_debug_error("upnp",
1043 "gaim_upnp_set_port_mapping(): couldn't get local ip\n\n"); 926 "gaim_upnp_set_port_mapping(): couldn't get local ip\n\n");
1044 return FALSE; 927 return FALSE;
1045 } 928 }
1046 929
1047 /* make the portMappingParams variable */ 930 /* make the portMappingParams variable */
1048 if((actionParams = (char*)malloc(strlen(ADD_PORT_MAPPING_PARAMS) + 931 actionParams = g_strdup_printf(ADD_PORT_MAPPING_PARAMS, portMap,
1049 strlen(internalIP) + 932 protocol, portMap, internalIP);
1050 10 + /* size of port as int * 2 */ 933
1051 strlen(protocol))) == NULL) { 934 httpResponse = gaim_upnp_generate_action_message_and_send(controlInfo,
1052 gaim_debug_info("upnp",
1053 "gaim_upnp_set_port_mapping(): Failed MALLOC portMappingParams\n\n");
1054 return FALSE;
1055 }
1056 sprintf(actionParams, ADD_PORT_MAPPING_PARAMS, portMap,
1057 protocol, portMap, internalIP);
1058
1059 httpResponse = gaim_upnp_generate_action_message_and_send(controlURL,
1060 actionName, 935 actionName,
1061 actionParams); 936 actionParams);
1062
1063 if(httpResponse == NULL) { 937 if(httpResponse == NULL) {
1064 gaim_debug_info("upnp", 938 gaim_debug_error("upnp",
1065 "gaim_upnp_set_port_mapping(): Failed In httpResponse\n\n"); 939 "gaim_upnp_set_port_mapping(): Failed In httpResponse\n\n");
1066 free(actionParams); 940 g_free(actionParams);
1067 return FALSE; 941 return FALSE;
1068 } 942 }
1069 943
1070 /* determine if port mapping was a success */ 944 /* determine if port mapping was a success */
1071 if(strstr(httpResponse, HTTP_OK) == NULL) { 945 if(strstr(httpResponse, HTTP_OK) == NULL) {
1072 gaim_debug_info("upnp", 946 gaim_debug_error("upnp",
1073 "gaim_upnp_set_port_mapping(): Failed HTTP_OK\n\n%s\n\n", httpResponse); 947 "gaim_upnp_set_port_mapping(): Failed HTTP_OK\n\n%s\n\n", httpResponse);
1074 free(actionParams); 948 g_free(actionParams);
1075 free(httpResponse); 949 g_free(httpResponse);
1076 return FALSE; 950 return FALSE;
1077 } 951 }
1078 952
1079 free(actionParams); 953 g_free(actionParams);
1080 free(httpResponse); 954 g_free(httpResponse);
955
956 gaim_debug_info("upnp", "NAT Added Port Forward On Port: %d: To IP: %s\n", portMap, internalIP);
1081 return TRUE; 957 return TRUE;
1082 } 958 }
1083 959
1084 960
1085 gboolean 961 gboolean
1086 gaim_upnp_remove_port_mapping(const char* controlURL, unsigned short portMap, 962 gaim_upnp_remove_port_mapping(const GaimUPnPControlInfo* controlInfo,
1087 const char* protocol) 963 unsigned short portMap,
1088 { 964 const char* protocol)
1089 char* httpResponse; 965 {
1090 char actionName[] = "DeletePortMapping"; 966 gchar* httpResponse;
1091 char* actionParams; 967 gchar actionName[] = "DeletePortMapping";
1092 968 gchar* actionParams;
1093 /* make sure controlURL is a valid URL */
1094 if(!gaim_upnp_validate_url(controlURL)) {
1095 gaim_debug_info("upnp",
1096 "gaim_upnp_set_port_mapping(): Failed In Validate URL\n\n");
1097 return FALSE;
1098 }
1099 969
1100 /* make the portMappingParams variable */ 970 /* make the portMappingParams variable */
1101 if((actionParams = (char*)malloc(strlen(DELETE_PORT_MAPPING_PARAMS) + 971 actionParams = g_strdup_printf(DELETE_PORT_MAPPING_PARAMS,
1102 5 + /* size of port as int */ 972 portMap, protocol);
1103 strlen(protocol))) == NULL) { 973
1104 gaim_debug_info("upnp", 974 httpResponse = gaim_upnp_generate_action_message_and_send(controlInfo,
1105 "gaim_upnp_set_port_mapping(): Failed MALLOC portMappingParams\n\n");
1106 return FALSE;
1107 }
1108 sprintf(actionParams, DELETE_PORT_MAPPING_PARAMS,
1109 portMap, protocol);
1110
1111 httpResponse = gaim_upnp_generate_action_message_and_send(controlURL,
1112 actionName, 975 actionName,
1113 actionParams); 976 actionParams);
1114 977
1115 if(httpResponse == NULL) { 978 if(httpResponse == NULL) {
1116 gaim_debug_info("upnp", 979 gaim_debug_error("upnp",
1117 "gaim_upnp_set_port_mapping(): Failed In httpResponse\n\n"); 980 "gaim_upnp_remove_port_mapping(): Failed In httpResponse\n\n");
1118 free(actionParams); 981 g_free(actionParams);
1119 return FALSE; 982 return FALSE;
1120 } 983 }
1121 984
1122 /* determine if port mapping was a success */ 985 /* determine if port mapping was a success */
1123 if(strstr(httpResponse, HTTP_OK) == NULL) { 986 if(strstr(httpResponse, HTTP_OK) == NULL) {
1124 gaim_debug_info("upnp", 987 gaim_debug_error("upnp",
1125 "gaim_upnp_set_port_mapping(): Failed HTTP_OK\n\n%s\n\n", httpResponse); 988 "gaim_upnp_set_port_mapping(): Failed HTTP_OK\n\n%s\n\n", httpResponse);
1126 free(actionParams); 989 g_free(actionParams);
1127 free(httpResponse); 990 g_free(httpResponse);
1128 return FALSE; 991 return FALSE;
1129 } 992 }
1130 993
1131 free(actionParams); 994 g_free(actionParams);
1132 free(httpResponse); 995 g_free(httpResponse);
996
997 gaim_debug_info("upnp", "NAT Removed Port Forward On Port: %d\n", portMap);
1133 return TRUE; 998 return TRUE;
1134 } 999 }