source: branches/1.5x/third-party/miniupnp/miniupnpc.c @ 7869

Last change on this file since 7869 was 7869, checked in by charles, 13 years ago

(1.5x) update to Jan 2009 versions of libnatpmp and miniupnpc

File size: 17.7 KB
Line 
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#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 */
52void 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) */
343struct 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: 3\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
369#ifndef WIN32
370        /* first try to get infos from minissdpd ! */
371        if(!minissdpdsock)
372                minissdpdsock = "/var/run/minissdpd.sock";
373        while(!devlist && deviceList[deviceIndex]) {
374                devlist = getDevicesFromMiniSSDPD(deviceList[deviceIndex],
375                                                  minissdpdsock);
376                /* We return what we have found if it was not only a rootdevice */
377                if(devlist && !strstr(deviceList[deviceIndex], "rootdevice"))
378                        return devlist;
379                deviceIndex++;
380        }
381        deviceIndex = 0;
382#endif
383        /* fallback to direct discovery */
384#ifdef WIN32
385        sudp = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
386#else
387        sudp = socket(PF_INET, SOCK_DGRAM, 0);
388#endif
389        if(sudp < 0)
390        {
391                PRINT_SOCKET_ERROR("socket");
392                return NULL;
393        }
394    /* reception */
395    memset(&sockudp_r, 0, sizeof(struct sockaddr_in));
396    sockudp_r.sin_family = AF_INET;
397        if(sameport)
398        sockudp_r.sin_port = htons(PORT);
399    sockudp_r.sin_addr.s_addr = INADDR_ANY;
400    /* emission */
401    memset(&sockudp_w, 0, sizeof(struct sockaddr_in));
402    sockudp_w.sin_family = AF_INET;
403    sockudp_w.sin_port = htons(PORT);
404    sockudp_w.sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
405
406#ifdef WIN32
407        if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
408#else
409        if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
410#endif
411        {
412                PRINT_SOCKET_ERROR("setsockopt");
413                return NULL;
414        }
415
416        if(multicastif)
417        {
418                struct in_addr mc_if;
419                mc_if.s_addr = inet_addr(multicastif);
420        sockudp_r.sin_addr.s_addr = mc_if.s_addr;
421                if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
422                {
423                        PRINT_SOCKET_ERROR("setsockopt");
424                }
425        }
426
427        /* Avant d'envoyer le paquet on bind pour recevoir la reponse */
428    if (bind(sudp, (struct sockaddr *)&sockudp_r, sizeof(struct sockaddr_in)) != 0)
429        {
430        PRINT_SOCKET_ERROR("bind");
431                closesocket(sudp);
432                return NULL;
433    }
434
435        /* receiving SSDP response packet */
436        for(n = 0;;)
437        {
438        if(n == 0)
439        {
440                /* sending the SSDP M-SEARCH packet */
441                n = snprintf(bufr, sizeof(bufr),
442                             MSearchMsgFmt, deviceList[deviceIndex++]);
443                /*printf("Sending %s", bufr);*/
444                n = sendto(sudp, bufr, n, 0,
445                           (struct sockaddr *)&sockudp_w, sizeof(struct sockaddr_in));
446                if (n < 0) {
447                        PRINT_SOCKET_ERROR("sendto");
448                        closesocket(sudp);
449                        return devlist;
450                }
451        }
452        /* Waiting for SSDP REPLY packet to M-SEARCH */
453        n = ReceiveData(sudp, bufr, sizeof(bufr), delay);
454        if (n < 0) {
455                /* error */
456                closesocket(sudp);
457                return devlist;
458        } else if (n == 0) {
459                /* no data or Time Out */
460                if (devlist || (deviceList[deviceIndex] == 0)) {
461                        /* no more device type to look for... */
462                        closesocket(sudp);
463                        return devlist;
464                }
465        } else {
466                const char * descURL=NULL;
467                int urlsize=0;
468                const char * st=NULL;
469                int stsize=0;
470        /*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */
471                parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize);
472                if(st&&descURL)
473                {
474                        /*printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n",
475                               stsize, st, urlsize, descURL); */
476                        tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize);
477                        tmp->pNext = devlist;
478                        tmp->descURL = tmp->buffer;
479                        tmp->st = tmp->buffer + 1 + urlsize;
480                        memcpy(tmp->buffer, descURL, urlsize);
481                        tmp->buffer[urlsize] = '\0';
482                        memcpy(tmp->buffer + urlsize + 1, st, stsize);
483                        tmp->buffer[urlsize+1+stsize] = '\0';
484                        devlist = tmp;
485                }
486        }
487        }
488}
489
490/* freeUPNPDevlist() should be used to
491 * free the chained list returned by upnpDiscover() */
492void freeUPNPDevlist(struct UPNPDev * devlist)
493{
494        struct UPNPDev * next;
495        while(devlist)
496        {
497                next = devlist->pNext;
498                free(devlist);
499                devlist = next;
500        }
501}
502
503static void
504url_cpy_or_cat(char * dst, const char * src, int n)
505{
506        if(  (src[0] == 'h')
507           &&(src[1] == 't')
508           &&(src[2] == 't')
509           &&(src[3] == 'p')
510           &&(src[4] == ':')
511           &&(src[5] == '/')
512           &&(src[6] == '/'))
513        {
514                strncpy(dst, src, n);
515        }
516        else
517        {
518                int l = strlen(dst);
519                if(src[0] != '/')
520                        dst[l++] = '/';
521                if(l<=n)
522                        strncpy(dst + l, src, n - l);
523        }
524}
525
526/* Prepare the Urls for usage...
527 */
528void GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
529                 const char * descURL)
530{
531        char * p;
532        int n1, n2, n3;
533        n1 = strlen(data->urlbase);
534        if(n1==0)
535                n1 = strlen(descURL);
536        n1 += 2;        /* 1 byte more for Null terminator, 1 byte for '/' if needed */
537        n2 = n1; n3 = n1;
538        n1 += strlen(data->scpdurl);
539        n2 += strlen(data->controlurl);
540        n3 += strlen(data->controlurl_CIF);
541
542        urls->ipcondescURL = (char *)malloc(n1);
543        urls->controlURL = (char *)malloc(n2);
544        urls->controlURL_CIF = (char *)malloc(n3);
545        /* maintenant on chope la desc du WANIPConnection */
546        if(data->urlbase[0] != '\0')
547                strncpy(urls->ipcondescURL, data->urlbase, n1);
548        else
549                strncpy(urls->ipcondescURL, descURL, n1);
550        p = strchr(urls->ipcondescURL+7, '/');
551        if(p) p[0] = '\0';
552        strncpy(urls->controlURL, urls->ipcondescURL, n2);
553        strncpy(urls->controlURL_CIF, urls->ipcondescURL, n3);
554       
555        url_cpy_or_cat(urls->ipcondescURL, data->scpdurl, n1);
556
557        url_cpy_or_cat(urls->controlURL, data->controlurl, n2);
558
559        url_cpy_or_cat(urls->controlURL_CIF, data->controlurl_CIF, n3);
560
561#ifdef DEBUG
562        printf("urls->ipcondescURL='%s' %d n1=%d\n", urls->ipcondescURL,
563               strlen(urls->ipcondescURL), n1);
564        printf("urls->controlURL='%s' %d n2=%d\n", urls->controlURL,
565               strlen(urls->controlURL), n2);
566        printf("urls->controlURL_CIF='%s' %d n3=%d\n", urls->controlURL_CIF,
567               strlen(urls->controlURL_CIF), n3);
568#endif
569}
570
571void
572FreeUPNPUrls(struct UPNPUrls * urls)
573{
574        if(!urls)
575                return;
576        free(urls->controlURL);
577        urls->controlURL = 0;
578        free(urls->ipcondescURL);
579        urls->ipcondescURL = 0;
580        free(urls->controlURL_CIF);
581        urls->controlURL_CIF = 0;
582}
583
584
585int ReceiveData(int socket, char * data, int length, int timeout)
586{
587    int n;
588#ifndef WIN32
589    struct pollfd fds[1]; /* for the poll */
590    fds[0].fd = socket;
591    fds[0].events = POLLIN;
592    n = poll(fds, 1, timeout);
593    if(n < 0)
594    {
595        PRINT_SOCKET_ERROR("poll");
596        return -1;
597    }
598    else if(n == 0)
599    {
600        return 0;
601    }
602#else
603    fd_set socketSet;
604    TIMEVAL timeval;
605    FD_ZERO(&socketSet);
606    FD_SET(socket, &socketSet);
607    timeval.tv_sec = timeout / 1000;
608    timeval.tv_usec = (timeout % 1000) * 1000;
609    /*n = select(0, &socketSet, NULL, NULL, &timeval);*/
610    n = select(FD_SETSIZE, &socketSet, NULL, NULL, &timeval);
611    if(n < 0)
612    {
613        PRINT_SOCKET_ERROR("select");
614        return -1;
615    }
616    else if(n == 0)
617    {
618        return 0;
619    }   
620#endif
621        n = recv(socket, data, length, 0);
622        if(n<0)
623        {
624                PRINT_SOCKET_ERROR("recv");
625        }
626        return n;
627}
628
629int
630UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
631{
632        char status[64];
633        unsigned int uptime;
634        status[0] = '\0';
635        UPNP_GetStatusInfo(urls->controlURL, data->servicetype,
636                           status, &uptime, NULL);
637        if(0 == strcmp("Connected", status))
638        {
639                return 1;
640        }
641        else
642                return 0;
643}
644
645
646/* UPNP_GetValidIGD() :
647 * return values :
648 *     0 = NO IGD found
649 *     1 = A valid connected IGD has been found
650 *     2 = A valid IGD has been found but it reported as
651 *         not connected
652 *     3 = an UPnP device has been found but was not recognized as an IGD
653 *
654 * In any non zero return case, the urls and data structures
655 * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
656 * free allocated memory.
657 */
658int
659UPNP_GetValidIGD(struct UPNPDev * devlist,
660                 struct UPNPUrls * urls,
661                                 struct IGDdatas * data,
662                                 char * lanaddr, int lanaddrlen)
663{
664        char * descXML;
665        int descXMLsize = 0;
666        struct UPNPDev * dev;
667        int ndev = 0;
668        int state; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */
669        if(!devlist)
670        {
671#ifdef DEBUG
672                printf("Empty devlist\n");
673#endif
674                return 0;
675        }
676        for(state = 1; state <= 3; state++)
677        {
678                for(dev = devlist; dev; dev = dev->pNext)
679                {
680                        /* we should choose an internet gateway device.
681                        * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
682                        descXML = miniwget_getaddr(dev->descURL, &descXMLsize,
683                                                        lanaddr, lanaddrlen);
684                        if(descXML)
685                        {
686                                ndev++;
687                                memset(data, 0, sizeof(struct IGDdatas));
688                                memset(urls, 0, sizeof(struct UPNPUrls));
689                                parserootdesc(descXML, descXMLsize, data);
690                                free(descXML);
691                                descXML = NULL;
692                                if(0==strcmp(data->servicetype_CIF,
693                                   "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")
694                                   || state >= 3 )
695                                {
696                                  GetUPNPUrls(urls, data, dev->descURL);
697
698#ifdef DEBUG
699                                  printf("UPNPIGD_IsConnected(%s) = %d\n",
700                                     urls->controlURL,
701                                 UPNPIGD_IsConnected(urls, data));
702#endif
703                                  if((state >= 2) || UPNPIGD_IsConnected(urls, data))
704                                        return state;
705                                  FreeUPNPUrls(urls);
706                                }
707                                memset(data, 0, sizeof(struct IGDdatas));
708                        }
709#ifdef DEBUG
710                        else
711                        {
712                                printf("error getting XML description %s\n", dev->descURL);
713                        }
714#endif
715                }
716        }
717        return 0;
718}
719
720/* UPNP_GetIGDFromUrl()
721 * Used when skipping the discovery process.
722 * return value :
723 *   0 - Not ok
724 *   1 - OK */
725int
726UPNP_GetIGDFromUrl(const char * rootdescurl,
727                   struct UPNPUrls * urls,
728                   struct IGDdatas * data,
729                   char * lanaddr, int lanaddrlen)
730{
731        char * descXML;
732        int descXMLsize = 0;
733        descXML = miniwget_getaddr(rootdescurl, &descXMLsize,
734                                       lanaddr, lanaddrlen);
735        if(descXML) {
736                memset(data, 0, sizeof(struct IGDdatas));
737                memset(urls, 0, sizeof(struct UPNPUrls));
738                parserootdesc(descXML, descXMLsize, data);
739                free(descXML);
740                descXML = NULL;
741                GetUPNPUrls(urls, data, rootdescurl);
742                return 1;
743        } else {
744                return 0;
745        }
746}
747
Note: See TracBrowser for help on using the repository browser.