~ubuntu-branches/ubuntu/trusty/tomahawk/trusty-proposed

« back to all changes in this revision

Viewing changes to thirdparty/libportfwd/third-party/miniupnpc-1.6/miniupnpc.c

  • Committer: Package Import Robot
  • Author(s): Harald Sitter
  • Date: 2013-03-07 21:50:13 UTC
  • Revision ID: package-import@ubuntu.com-20130307215013-6gdjkdds7i9uenvs
Tags: upstream-0.6.0+dfsg
ImportĀ upstreamĀ versionĀ 0.6.0+dfsg

Show diffs side-by-side

added added

removed removed

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