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

Last change on this file since 10285 was 10285, checked in by livings124, 11 years ago

update miniupnp to 1.4

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