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

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

(trunk third-party) get miniupnpc building again. the breakage has been reported upstream @ http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1452#1452

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