]> git.ipfire.org Git - thirdparty/freeswitch.git/blob - libs/miniupnpc/miniupnpc.c
[core,miniupnpc,modules] Fix not used variables
[thirdparty/freeswitch.git] / libs / miniupnpc / miniupnpc.c
1 /* $Id: miniupnpc.c,v 1.57 2008/12/18 17:46:36 nanard Exp $ */
2 /* Project : miniupnp
3 * Author : Thomas BERNARD
4 * copyright (c) 2005-2007 Thomas Bernard
5 * This software is subjet to the conditions detailed in the
6 * provided LICENCE file. */
7 #define __EXTENSIONS__ 1
8
9 #ifndef MACOSX
10 #if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) && !defined(__NetBSD__)
11 #ifndef __cplusplus
12 #define _XOPEN_SOURCE 600
13 #endif
14 #endif
15 #ifndef __BSD_VISIBLE
16 #define __BSD_VISIBLE 1
17 #endif
18 #endif
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #ifdef WIN32
23 /* Win32 Specific includes and defines */
24 #include <winsock2.h>
25 #include <Ws2tcpip.h>
26 #include <io.h>
27 #if _MSC_VER < 1900
28 #define snprintf _snprintf
29 #endif
30 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
31 #define strncasecmp _memicmp
32 #else
33 #define strncasecmp memicmp
34 #endif
35 #define MAXHOSTNAMELEN 64
36 #else
37 /* Standard POSIX includes */
38 #include <unistd.h>
39 #include <sys/socket.h>
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <poll.h>
45 #include <netdb.h>
46 #include <strings.h>
47 #define closesocket close
48 #endif
49 #include "miniupnpc.h"
50 #include "minissdpc.h"
51 #include "miniwget.h"
52 #include "minisoap.h"
53 #include "minixml.h"
54 #include "upnpcommands.h"
55
56 #ifdef WIN32
57 #define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
58 #else
59 #define PRINT_SOCKET_ERROR(x) perror(x)
60 #endif
61
62 #define SOAPPREFIX "s"
63 #define SERVICEPREFIX "u"
64 #define SERVICEPREFIX2 'u'
65
66 /* root description parsing */
67 void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data)
68 {
69 struct xmlparser parser;
70 /* xmlparser object */
71 parser.xmlstart = buffer;
72 parser.xmlsize = bufsize;
73 parser.data = data;
74 parser.starteltfunc = IGDstartelt;
75 parser.endeltfunc = IGDendelt;
76 parser.datafunc = IGDdata;
77 parser.attfunc = 0;
78 parsexml(&parser);
79 #ifdef DEBUG
80 printIGD(data);
81 #endif
82 }
83
84 /* Content-length: nnn */
85 static int getcontentlenfromline(const char * p, int n)
86 {
87 static const char contlenstr[] = "content-length";
88 const char * p2 = contlenstr;
89 int a = 0;
90 while(*p2)
91 {
92 if(n==0)
93 return -1;
94 if(*p2 != *p && *p2 != (*p + 32))
95 return -1;
96 p++; p2++; n--;
97 }
98 if(n==0)
99 return -1;
100 if(*p != ':')
101 return -1;
102 p++; n--;
103 while(*p == ' ')
104 {
105 if(n==0)
106 return -1;
107 p++; n--;
108 }
109 while(*p >= '0' && *p <= '9')
110 {
111 if(n==0)
112 return -1;
113 a = (a * 10) + (*p - '0');
114 p++; n--;
115 }
116 return a;
117 }
118
119 static void
120 getContentLengthAndHeaderLength(char * p, int n,
121 int * contentlen, int * headerlen)
122 {
123 char * line;
124 int linelen;
125 int r;
126 line = p;
127 while(line < p + n)
128 {
129 linelen = 0;
130 while(line[linelen] != '\r' && line[linelen] != '\r')
131 {
132 if(line+linelen >= p+n)
133 return;
134 linelen++;
135 }
136 r = getcontentlenfromline(line, linelen);
137 if(r>0)
138 *contentlen = r;
139 line = line + linelen + 2;
140 if(line[0] == '\r' && line[1] == '\n')
141 {
142 *headerlen = (line - p) + 2;
143 return;
144 }
145 }
146 }
147
148 /* simpleUPnPcommand :
149 * not so simple !
150 * return values :
151 * 0 - OK
152 * -1 - error */
153 int simpleUPnPcommand(int s, const char * url, const char * service,
154 const char * action, struct UPNParg * args,
155 char * buffer, int * bufsize)
156 {
157 struct sockaddr_in dest;
158 char hostname[MAXHOSTNAMELEN+1];
159 unsigned short port = 0;
160 char * path;
161 char soapact[128];
162 char soapbody[2048];
163 char * buf;
164 int buffree;
165 int n;
166 int contentlen, headerlen; /* for the response */
167 snprintf(soapact, sizeof(soapact), "%s#%s", service, action);
168 if(args==NULL)
169 {
170 /*soapbodylen = */snprintf(soapbody, sizeof(soapbody),
171 "<?xml version=\"1.0\"?>\r\n"
172 "<" SOAPPREFIX ":Envelope "
173 "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
174 SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
175 "<" SOAPPREFIX ":Body>"
176 "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">"
177 "</" SERVICEPREFIX ":%s>"
178 "</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>"
179 "\r\n", action, service, action);
180 }
181 else
182 {
183 char * p;
184 const char * pe, * pv;
185 int soapbodylen;
186 soapbodylen = snprintf(soapbody, sizeof(soapbody),
187 "<?xml version=\"1.0\"?>\r\n"
188 "<" SOAPPREFIX ":Envelope "
189 "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
190 SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
191 "<" SOAPPREFIX ":Body>"
192 "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">",
193 action, service);
194 p = soapbody + soapbodylen;
195 while(args->elt)
196 {
197 /* check that we are never overflowing the string... */
198 if(soapbody + sizeof(soapbody) <= p + 100)
199 {
200 /* we keep a margin of at least 100 bytes */
201 *bufsize = 0;
202 return -1;
203 }
204 *(p++) = '<';
205 pe = args->elt;
206 while(*pe)
207 *(p++) = *(pe++);
208 *(p++) = '>';
209 if((pv = args->val))
210 {
211 while(*pv)
212 *(p++) = *(pv++);
213 }
214 *(p++) = '<';
215 *(p++) = '/';
216 pe = args->elt;
217 while(*pe)
218 *(p++) = *(pe++);
219 *(p++) = '>';
220 args++;
221 }
222 *(p++) = '<';
223 *(p++) = '/';
224 *(p++) = SERVICEPREFIX2;
225 *(p++) = ':';
226 pe = action;
227 while(*pe)
228 *(p++) = *(pe++);
229 strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n",
230 soapbody + sizeof(soapbody) - p);
231 }
232 if(!parseURL(url, hostname, &port, &path)) return -1;
233 if(s<0)
234 {
235 s = socket(PF_INET, SOCK_STREAM, 0);
236 if(s<0)
237 {
238 PRINT_SOCKET_ERROR("socket");
239 *bufsize = 0;
240 return -1;
241 }
242 dest.sin_family = AF_INET;
243 dest.sin_port = htons(port);
244 dest.sin_addr.s_addr = inet_addr(hostname);
245 if(connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr))<0)
246 {
247 PRINT_SOCKET_ERROR("connect");
248 closesocket(s);
249 *bufsize = 0;
250 return -1;
251 }
252 }
253
254 n = soapPostSubmit(s, path, hostname, port, soapact, soapbody);
255 if(n<=0) {
256 #ifdef DEBUG
257 printf("Error sending SOAP request\n");
258 #endif
259 closesocket(s);
260 return -1;
261 }
262
263 contentlen = -1;
264 headerlen = -1;
265 buf = buffer;
266 buffree = *bufsize;
267 *bufsize = 0;
268 while ((n = ReceiveData(s, buf, buffree, 5000)) > 0) {
269 buffree -= n;
270 buf += n;
271 *bufsize += n;
272 getContentLengthAndHeaderLength(buffer, *bufsize,
273 &contentlen, &headerlen);
274 #ifdef DEBUG
275 printf("received n=%dbytes bufsize=%d ContLen=%d HeadLen=%d\n",
276 n, *bufsize, contentlen, headerlen);
277 #endif
278 /* break if we received everything */
279 if(contentlen > 0 && headerlen > 0 && *bufsize >= contentlen+headerlen)
280 break;
281 }
282
283 closesocket(s);
284 return 0;
285 }
286
287 /* parseMSEARCHReply()
288 * the last 4 arguments are filled during the parsing :
289 * - location/locationsize : "location:" field of the SSDP reply packet
290 * - st/stsize : "st:" field of the SSDP reply packet.
291 * The strings are NOT null terminated */
292 static void
293 parseMSEARCHReply(const char * reply, int size,
294 const char * * location, int * locationsize,
295 const char * * st, int * stsize)
296 {
297 int a, b, i;
298 i = 0;
299 a = i; /* start of the line */
300 b = 0;
301 while(i<size)
302 {
303 switch(reply[i])
304 {
305 case ':':
306 if(b==0)
307 {
308 b = i; /* end of the "header" */
309 /*for(j=a; j<b; j++)
310 {
311 putchar(reply[j]);
312 }
313 */
314 }
315 break;
316 case '\x0a':
317 case '\x0d':
318 if(b!=0)
319 {
320 /*for(j=b+1; j<i; j++)
321 {
322 putchar(reply[j]);
323 }
324 putchar('\n');*/
325 do { b++; } while(reply[b]==' ');
326 if(0==strncasecmp(reply+a, "location", 8))
327 {
328 *location = reply+b;
329 *locationsize = i-b;
330 }
331 else if(0==strncasecmp(reply+a, "st", 2))
332 {
333 *st = reply+b;
334 *stsize = i-b;
335 }
336 b = 0;
337 }
338 a = i+1;
339 break;
340 default:
341 break;
342 }
343 i++;
344 }
345 }
346
347 /* port upnp discover : SSDP protocol */
348 #define PORT 1900
349 #define XSTR(s) STR(s)
350 #define STR(s) #s
351 #define UPNP_MCAST_ADDR "239.255.255.250"
352
353 /* upnpDiscover() :
354 * return a chained list of all devices found or NULL if
355 * no devices was found.
356 * It is up to the caller to free the chained list
357 * delay is in millisecond (poll) */
358 struct UPNPDev * upnpDiscover(int delay, const char * multicastif,
359 const char * minissdpdsock, int sameport)
360 {
361 struct UPNPDev * tmp;
362 struct UPNPDev * devlist = 0;
363 int opt = 1;
364 static const char MSearchMsgFmt[] =
365 "M-SEARCH * HTTP/1.1\r\n"
366 "HOST: " UPNP_MCAST_ADDR ":" XSTR(PORT) "\r\n"
367 "ST: %s\r\n"
368 "MAN: \"ssdp:discover\"\r\n"
369 "MX: 3\r\n"
370 "\r\n";
371 static const char * const deviceList[] = {
372 "urn:schemas-upnp-org:device:InternetGatewayDevice:1",
373 "urn:schemas-upnp-org:service:WANIPConnection:1",
374 "urn:schemas-upnp-org:service:WANPPPConnection:1",
375 "upnp:rootdevice",
376 0
377 };
378 int deviceIndex = 0;
379 char bufr[1536]; /* reception and emission buffer */
380 int sudp;
381 int n;
382 struct sockaddr_in sockudp_r, sockudp_w;
383
384 #ifndef WIN32
385 /* first try to get infos from minissdpd ! */
386 if(!minissdpdsock)
387 minissdpdsock = "/var/run/minissdpd.sock";
388 while(!devlist && deviceList[deviceIndex]) {
389 devlist = getDevicesFromMiniSSDPD(deviceList[deviceIndex],
390 minissdpdsock);
391 /* We return what we have found if it was not only a rootdevice */
392 if(devlist && !strstr(deviceList[deviceIndex], "rootdevice"))
393 return devlist;
394 deviceIndex++;
395 }
396 deviceIndex = 0;
397 #endif
398 /* fallback to direct discovery */
399 #ifdef WIN32
400 sudp = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
401 #else
402 sudp = socket(PF_INET, SOCK_DGRAM, 0);
403 #endif
404 if(sudp < 0)
405 {
406 PRINT_SOCKET_ERROR("socket");
407 return NULL;
408 }
409 /* reception */
410 memset(&sockudp_r, 0, sizeof(struct sockaddr_in));
411 sockudp_r.sin_family = AF_INET;
412 if(sameport)
413 sockudp_r.sin_port = htons(PORT);
414 sockudp_r.sin_addr.s_addr = INADDR_ANY;
415 /* emission */
416 memset(&sockudp_w, 0, sizeof(struct sockaddr_in));
417 sockudp_w.sin_family = AF_INET;
418 sockudp_w.sin_port = htons(PORT);
419 sockudp_w.sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
420
421 #ifdef WIN32
422 if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
423 #else
424 if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
425 #endif
426 {
427 PRINT_SOCKET_ERROR("setsockopt");
428 return NULL;
429 }
430
431 if(multicastif)
432 {
433 struct in_addr mc_if;
434 mc_if.s_addr = inet_addr(multicastif);
435 sockudp_r.sin_addr.s_addr = mc_if.s_addr;
436 if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
437 {
438 PRINT_SOCKET_ERROR("setsockopt");
439 }
440 }
441
442 /* Avant d'envoyer le paquet on bind pour recevoir la reponse */
443 if (bind(sudp, (struct sockaddr *)&sockudp_r, sizeof(struct sockaddr_in)) != 0)
444 {
445 PRINT_SOCKET_ERROR("bind");
446 closesocket(sudp);
447 return NULL;
448 }
449
450 /* receiving SSDP response packet */
451 for(n = 0;;)
452 {
453 if(n == 0)
454 {
455 /* sending the SSDP M-SEARCH packet */
456 n = snprintf(bufr, sizeof(bufr),
457 MSearchMsgFmt, deviceList[deviceIndex++]);
458 /*printf("Sending %s", bufr);*/
459 n = sendto(sudp, bufr, n, 0,
460 (struct sockaddr *)&sockudp_w, sizeof(struct sockaddr_in));
461 if (n < 0) {
462 PRINT_SOCKET_ERROR("sendto");
463 closesocket(sudp);
464 return devlist;
465 }
466 }
467 /* Waiting for SSDP REPLY packet to M-SEARCH */
468 n = ReceiveData(sudp, bufr, sizeof(bufr), delay);
469 if (n < 0) {
470 /* error */
471 closesocket(sudp);
472 return devlist;
473 } else if (n == 0) {
474 /* no data or Time Out */
475 if (devlist || (deviceList[deviceIndex] == 0)) {
476 /* no more device type to look for... */
477 closesocket(sudp);
478 return devlist;
479 }
480 } else {
481 const char * descURL=NULL;
482 int urlsize=0;
483 const char * st=NULL;
484 int stsize=0;
485 /*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */
486 parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize);
487 if(st&&descURL)
488 {
489 /*printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n",
490 stsize, st, urlsize, descURL); */
491 tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize);
492 tmp->pNext = devlist;
493 tmp->descURL = tmp->buffer;
494 tmp->st = tmp->buffer + 1 + urlsize;
495 memcpy(tmp->buffer, descURL, urlsize);
496 tmp->buffer[urlsize] = '\0';
497 memcpy(tmp->buffer + urlsize + 1, st, stsize);
498 tmp->buffer[urlsize+1+stsize] = '\0';
499 devlist = tmp;
500 }
501 }
502 }
503 }
504
505 /* freeUPNPDevlist() should be used to
506 * free the chained list returned by upnpDiscover() */
507 void freeUPNPDevlist(struct UPNPDev * devlist)
508 {
509 struct UPNPDev * next;
510 while(devlist)
511 {
512 next = devlist->pNext;
513 free(devlist);
514 devlist = next;
515 }
516 }
517
518 static void
519 url_cpy_or_cat(char * dst, const char * src, int n)
520 {
521 if( (src[0] == 'h')
522 &&(src[1] == 't')
523 &&(src[2] == 't')
524 &&(src[3] == 'p')
525 &&(src[4] == ':')
526 &&(src[5] == '/')
527 &&(src[6] == '/'))
528 {
529 strncpy(dst, src, n);
530 }
531 else
532 {
533 int l = strlen(dst);
534 if(src[0] != '/')
535 dst[l++] = '/';
536 if(l<=n)
537 strncpy(dst + l, src, n - l);
538 }
539 }
540
541 /* Prepare the Urls for usage...
542 */
543 void GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
544 const char * descURL)
545 {
546 char * p;
547 int n1, n2, n3;
548 n1 = strlen(data->urlbase);
549 if(n1==0)
550 n1 = strlen(descURL);
551 n1 += 2; /* 1 byte more for Null terminator, 1 byte for '/' if needed */
552 n2 = n1; n3 = n1;
553 n1 += strlen(data->scpdurl);
554 n2 += strlen(data->controlurl);
555 n3 += strlen(data->controlurl_CIF);
556
557 urls->ipcondescURL = (char *)malloc(n1);
558 urls->controlURL = (char *)malloc(n2);
559 urls->controlURL_CIF = (char *)malloc(n3);
560 /* maintenant on chope la desc du WANIPConnection */
561 if(data->urlbase[0] != '\0')
562 strncpy(urls->ipcondescURL, data->urlbase, n1);
563 else
564 strncpy(urls->ipcondescURL, descURL, n1);
565 p = strchr(urls->ipcondescURL+7, '/');
566 if(p) p[0] = '\0';
567 strncpy(urls->controlURL, urls->ipcondescURL, n2);
568 strncpy(urls->controlURL_CIF, urls->ipcondescURL, n3);
569
570 url_cpy_or_cat(urls->ipcondescURL, data->scpdurl, n1);
571
572 url_cpy_or_cat(urls->controlURL, data->controlurl, n2);
573
574 url_cpy_or_cat(urls->controlURL_CIF, data->controlurl_CIF, n3);
575
576 #ifdef DEBUG
577 printf("urls->ipcondescURL='%s' %d n1=%d\n", urls->ipcondescURL,
578 strlen(urls->ipcondescURL), n1);
579 printf("urls->controlURL='%s' %d n2=%d\n", urls->controlURL,
580 strlen(urls->controlURL), n2);
581 printf("urls->controlURL_CIF='%s' %d n3=%d\n", urls->controlURL_CIF,
582 strlen(urls->controlURL_CIF), n3);
583 #endif
584 }
585
586 void
587 FreeUPNPUrls(struct UPNPUrls * urls)
588 {
589 if(!urls)
590 return;
591 free(urls->controlURL);
592 urls->controlURL = 0;
593 free(urls->ipcondescURL);
594 urls->ipcondescURL = 0;
595 free(urls->controlURL_CIF);
596 urls->controlURL_CIF = 0;
597 }
598
599
600 int ReceiveData(int socket, char * data, int length, int timeout)
601 {
602 int n;
603 #ifndef WIN32
604 struct pollfd fds[1]; /* for the poll */
605 fds[0].fd = socket;
606 fds[0].events = POLLIN;
607 n = poll(fds, 1, timeout);
608 if(n < 0)
609 {
610 PRINT_SOCKET_ERROR("poll");
611 return -1;
612 }
613 else if(n == 0)
614 {
615 return 0;
616 }
617 #else
618 fd_set socketSet;
619 TIMEVAL timeval;
620 FD_ZERO(&socketSet);
621 FD_SET(socket, &socketSet);
622 timeval.tv_sec = timeout / 1000;
623 timeval.tv_usec = (timeout % 1000) * 1000;
624 /*n = select(0, &socketSet, NULL, NULL, &timeval);*/
625 n = select(FD_SETSIZE, &socketSet, NULL, NULL, &timeval);
626 if(n < 0)
627 {
628 PRINT_SOCKET_ERROR("select");
629 return -1;
630 }
631 else if(n == 0)
632 {
633 return 0;
634 }
635 #endif
636 n = recv(socket, data, length, 0);
637 if(n<0)
638 {
639 PRINT_SOCKET_ERROR("recv");
640 }
641 return n;
642 }
643
644 int
645 UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
646 {
647 char status[64];
648 unsigned int uptime;
649 status[0] = '\0';
650 UPNP_GetStatusInfo(urls->controlURL, data->servicetype,
651 status, &uptime, NULL);
652 if(0 == strcmp("Connected", status))
653 {
654 return 1;
655 }
656 else
657 return 0;
658 }
659
660
661 /* UPNP_GetValidIGD() :
662 * return values :
663 * 0 = NO IGD found
664 * 1 = A valid connected IGD has been found
665 * 2 = A valid IGD has been found but it reported as
666 * not connected
667 * 3 = an UPnP device has been found but was not recognized as an IGD
668 *
669 * In any non zero return case, the urls and data structures
670 * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
671 * free allocated memory.
672 */
673 int
674 UPNP_GetValidIGD(struct UPNPDev * devlist,
675 struct UPNPUrls * urls,
676 struct IGDdatas * data,
677 char * lanaddr, int lanaddrlen)
678 {
679 char * descXML;
680 int descXMLsize = 0;
681 struct UPNPDev * dev;
682 int state; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */
683 if(!devlist)
684 {
685 #ifdef DEBUG
686 printf("Empty devlist\n");
687 #endif
688 return 0;
689 }
690 for(state = 1; state <= 3; state++)
691 {
692 for(dev = devlist; dev; dev = dev->pNext)
693 {
694 /* we should choose an internet gateway device.
695 * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
696 descXML = miniwget_getaddr(dev->descURL, &descXMLsize,
697 lanaddr, lanaddrlen);
698 if(descXML)
699 {
700 memset(data, 0, sizeof(struct IGDdatas));
701 memset(urls, 0, sizeof(struct UPNPUrls));
702 parserootdesc(descXML, descXMLsize, data);
703 free(descXML);
704 descXML = NULL;
705 if(0==strcmp(data->servicetype_CIF,
706 "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")
707 || state >= 3 )
708 {
709 GetUPNPUrls(urls, data, dev->descURL);
710
711 #ifdef DEBUG
712 printf("UPNPIGD_IsConnected(%s) = %d\n",
713 urls->controlURL,
714 UPNPIGD_IsConnected(urls, data));
715 #endif
716 if((state >= 2) || UPNPIGD_IsConnected(urls, data))
717 return state;
718 FreeUPNPUrls(urls);
719 }
720 memset(data, 0, sizeof(struct IGDdatas));
721 }
722 #ifdef DEBUG
723 else
724 {
725 printf("error getting XML description %s\n", dev->descURL);
726 }
727 #endif
728 }
729 }
730 return 0;
731 }
732
733 /* UPNP_GetIGDFromUrl()
734 * Used when skipping the discovery process.
735 * return value :
736 * 0 - Not ok
737 * 1 - OK */
738 int
739 UPNP_GetIGDFromUrl(const char * rootdescurl,
740 struct UPNPUrls * urls,
741 struct IGDdatas * data,
742 char * lanaddr, int lanaddrlen)
743 {
744 char * descXML;
745 int descXMLsize = 0;
746 descXML = miniwget_getaddr(rootdescurl, &descXMLsize,
747 lanaddr, lanaddrlen);
748 if(descXML) {
749 memset(data, 0, sizeof(struct IGDdatas));
750 memset(urls, 0, sizeof(struct UPNPUrls));
751 parserootdesc(descXML, descXMLsize, data);
752 free(descXML);
753 descXML = NULL;
754 GetUPNPUrls(urls, data, rootdescurl);
755 return 1;
756 } else {
757 return 0;
758 }
759 }
760