source: trunk/third-party/miniupnp/miniupnpc.c @ 8862

Last change on this file since 8862 was 8862, checked in by livings124, 13 years ago

update miniupnpc to miniupnpc-20090729

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