Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/miniupnpc/src/miniupnpc.c
9904 views
1
/* $Id: miniupnpc.c,v 1.165 2025/01/10 22:57:21 nanard Exp $ */
2
/* vim: tabstop=4 shiftwidth=4 noexpandtab
3
* Project : miniupnp
4
* Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
5
* Author : Thomas BERNARD
6
* copyright (c) 2005-2025 Thomas Bernard
7
* This software is subjet to the conditions detailed in the
8
* provided LICENSE file. */
9
#include <stdlib.h>
10
#include <stdio.h>
11
#include <string.h>
12
#ifdef _WIN32
13
/* Win32 Specific includes and defines */
14
#define WIN32_LEAN_AND_MEAN
15
#include <winsock2.h>
16
#include <ws2tcpip.h>
17
#include <io.h>
18
#include <iphlpapi.h>
19
#include "win32_snprintf.h"
20
#define strdup _strdup
21
#ifndef strncasecmp
22
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
23
#define strncasecmp _memicmp
24
#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
25
#define strncasecmp memicmp
26
#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
27
#endif /* #ifndef strncasecmp */
28
#define MAXHOSTNAMELEN 64
29
#else /* #ifdef _WIN32 */
30
/* Standard POSIX includes */
31
#include <unistd.h>
32
#if defined(__amigaos__) && !defined(__amigaos4__)
33
/* Amiga OS 3 specific stuff */
34
#define socklen_t int
35
#else
36
#include <sys/select.h>
37
#endif
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 <netdb.h>
44
#include <net/if.h>
45
#if !defined(__amigaos__) && !defined(__amigaos4__)
46
#include <poll.h>
47
#endif
48
#include <strings.h>
49
#include <errno.h>
50
#define closesocket close
51
#endif /* #else _WIN32 */
52
#ifdef __GNU__
53
#define MAXHOSTNAMELEN 64
54
#endif
55
56
57
#include "miniupnpc.h"
58
#include "minissdpc.h"
59
#include "miniwget.h"
60
#include "miniwget_private.h"
61
#include "minisoap.h"
62
#include "minixml.h"
63
#include "upnpcommands.h"
64
#include "connecthostport.h"
65
#include "addr_is_reserved.h"
66
67
/* compare the beginning of a string with a constant string */
68
#define COMPARE(str, cstr) (0==strncmp(str, cstr, sizeof(cstr) - 1))
69
70
#ifndef MAXHOSTNAMELEN
71
#define MAXHOSTNAMELEN 64
72
#endif
73
74
#define SOAPPREFIX "s"
75
#define SERVICEPREFIX "u"
76
#define SERVICEPREFIX2 'u'
77
78
/* root description parsing */
79
MINIUPNP_LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data)
80
{
81
struct xmlparser parser;
82
/* xmlparser object */
83
parser.xmlstart = buffer;
84
parser.xmlsize = bufsize;
85
parser.data = data;
86
parser.starteltfunc = IGDstartelt;
87
parser.endeltfunc = IGDendelt;
88
parser.datafunc = IGDdata;
89
parser.attfunc = 0;
90
parsexml(&parser);
91
#ifdef DEBUG
92
printIGD(data);
93
#endif
94
}
95
96
/* simpleUPnPcommand :
97
* not so simple !
98
* return values :
99
* pointer - OK
100
* NULL - error */
101
char *
102
simpleUPnPcommand(const char * url, const char * service,
103
const char * action, const struct UPNParg * args,
104
int * bufsize)
105
{
106
char hostname[MAXHOSTNAMELEN+1];
107
unsigned short port = 0;
108
char * path;
109
char soapact[128];
110
char soapbody[2048];
111
int soapbodylen;
112
char * buf;
113
int n;
114
int status_code;
115
SOCKET s;
116
117
*bufsize = 0;
118
snprintf(soapact, sizeof(soapact), "%s#%s", service, action);
119
if(args==NULL)
120
{
121
soapbodylen = snprintf(soapbody, sizeof(soapbody),
122
"<?xml version=\"1.0\"?>\r\n"
123
"<" SOAPPREFIX ":Envelope "
124
"xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
125
SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
126
"<" SOAPPREFIX ":Body>"
127
"<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">"
128
"</" SERVICEPREFIX ":%s>"
129
"</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>"
130
"\r\n", action, service, action);
131
if ((unsigned int)soapbodylen >= sizeof(soapbody))
132
return NULL;
133
}
134
else
135
{
136
char * p;
137
const char * pe, * pv;
138
const char * const pend = soapbody + sizeof(soapbody);
139
soapbodylen = snprintf(soapbody, sizeof(soapbody),
140
"<?xml version=\"1.0\"?>\r\n"
141
"<" SOAPPREFIX ":Envelope "
142
"xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
143
SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
144
"<" SOAPPREFIX ":Body>"
145
"<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">",
146
action, service);
147
if ((unsigned int)soapbodylen >= sizeof(soapbody))
148
return NULL;
149
p = soapbody + soapbodylen;
150
while(args->elt)
151
{
152
if(p >= pend) /* check for space to write next byte */
153
return NULL;
154
*(p++) = '<';
155
156
pe = args->elt;
157
while(p < pend && *pe)
158
*(p++) = *(pe++);
159
160
if(p >= pend) /* check for space to write next byte */
161
return NULL;
162
*(p++) = '>';
163
164
if((pv = args->val))
165
{
166
while(p < pend && *pv)
167
*(p++) = *(pv++);
168
}
169
170
if((p+2) > pend) /* check for space to write next 2 bytes */
171
return NULL;
172
*(p++) = '<';
173
*(p++) = '/';
174
175
pe = args->elt;
176
while(p < pend && *pe)
177
*(p++) = *(pe++);
178
179
if(p >= pend) /* check for space to write next byte */
180
return NULL;
181
*(p++) = '>';
182
183
args++;
184
}
185
if((p+4) > pend) /* check for space to write next 4 bytes */
186
return NULL;
187
*(p++) = '<';
188
*(p++) = '/';
189
*(p++) = SERVICEPREFIX2;
190
*(p++) = ':';
191
192
pe = action;
193
while(p < pend && *pe)
194
*(p++) = *(pe++);
195
196
strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n",
197
pend - p);
198
if(soapbody[sizeof(soapbody)-1]) /* strncpy pads buffer with 0s, so if it doesn't end in 0, could not fit full string */
199
return NULL;
200
}
201
if(!parseURL(url, hostname, &port, &path, NULL)) return NULL;
202
s = connecthostport(hostname, port, 0);
203
if(ISINVALID(s)) {
204
/* failed to connect */
205
return NULL;
206
}
207
208
n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, "1.1");
209
if(n<=0) {
210
#ifdef DEBUG
211
printf("Error sending SOAP request\n");
212
#endif
213
closesocket(s);
214
return NULL;
215
}
216
217
buf = getHTTPResponse(s, bufsize, &status_code);
218
#ifdef DEBUG
219
if(*bufsize > 0 && buf)
220
{
221
printf("HTTP %d SOAP Response :\n%.*s\n", status_code, *bufsize, buf);
222
}
223
else
224
{
225
printf("HTTP %d, empty SOAP response. size=%d\n", status_code, *bufsize);
226
}
227
#endif
228
closesocket(s);
229
return buf;
230
}
231
232
/* upnpDiscoverDevices() :
233
* return a chained list of all devices found or NULL if
234
* no devices was found.
235
* It is up to the caller to free the chained list
236
* delay is in millisecond (poll).
237
* UDA v1.1 says :
238
* The TTL for the IP packet SHOULD default to 2 and
239
* SHOULD be configurable. */
240
MINIUPNP_LIBSPEC struct UPNPDev *
241
upnpDiscoverDevices(const char * const deviceTypes[],
242
int delay, const char * multicastif,
243
const char * minissdpdsock, int localport,
244
int ipv6, unsigned char ttl,
245
int * error,
246
int searchalltypes)
247
{
248
struct UPNPDev * tmp;
249
struct UPNPDev * devlist = 0;
250
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
251
int deviceIndex;
252
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
253
254
if(error)
255
*error = UPNPDISCOVER_UNKNOWN_ERROR;
256
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
257
/* first try to get infos from minissdpd ! */
258
if(!minissdpdsock)
259
minissdpdsock = "/var/run/minissdpd.sock";
260
if(minissdpdsock[0] != '\0') {
261
for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
262
struct UPNPDev * minissdpd_devlist;
263
int only_rootdevice = 1;
264
minissdpd_devlist = getDevicesFromMiniSSDPD(deviceTypes[deviceIndex],
265
minissdpdsock, 0);
266
if(minissdpd_devlist) {
267
#ifdef DEBUG
268
printf("returned by MiniSSDPD: %s\t%s\n",
269
minissdpd_devlist->st, minissdpd_devlist->descURL);
270
#endif /* DEBUG */
271
if(!strstr(minissdpd_devlist->st, "rootdevice"))
272
only_rootdevice = 0;
273
for(tmp = minissdpd_devlist; tmp->pNext != NULL; tmp = tmp->pNext) {
274
#ifdef DEBUG
275
printf("returned by MiniSSDPD: %s\t%s\n",
276
tmp->pNext->st, tmp->pNext->descURL);
277
#endif /* DEBUG */
278
if(!strstr(tmp->st, "rootdevice"))
279
only_rootdevice = 0;
280
}
281
tmp->pNext = devlist;
282
devlist = minissdpd_devlist;
283
if(!searchalltypes && !only_rootdevice)
284
break;
285
}
286
}
287
}
288
for(tmp = devlist; tmp != NULL; tmp = tmp->pNext) {
289
/* We return what we have found if it was not only a rootdevice */
290
if(!strstr(tmp->st, "rootdevice")) {
291
if(error)
292
*error = UPNPDISCOVER_SUCCESS;
293
return devlist;
294
}
295
}
296
#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
297
(void)minissdpdsock; /* unused */
298
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
299
300
/* direct discovery if minissdpd responses are not sufficient */
301
{
302
struct UPNPDev * discovered_devlist;
303
discovered_devlist = ssdpDiscoverDevices(deviceTypes, delay, multicastif, localport,
304
ipv6, ttl, error, searchalltypes);
305
if(devlist == NULL)
306
devlist = discovered_devlist;
307
else {
308
for(tmp = devlist; tmp->pNext != NULL; tmp = tmp->pNext);
309
tmp->pNext = discovered_devlist;
310
}
311
}
312
return devlist;
313
}
314
315
/* upnpDiscover() Discover IGD device */
316
MINIUPNP_LIBSPEC struct UPNPDev *
317
upnpDiscover(int delay, const char * multicastif,
318
const char * minissdpdsock, int localport,
319
int ipv6, unsigned char ttl,
320
int * error)
321
{
322
static const char * const deviceList[] = {
323
#if 0
324
"urn:schemas-upnp-org:device:InternetGatewayDevice:2",
325
"urn:schemas-upnp-org:service:WANIPConnection:2",
326
#endif
327
"urn:schemas-upnp-org:device:InternetGatewayDevice:1",
328
"urn:schemas-upnp-org:service:WANIPConnection:1",
329
"urn:schemas-upnp-org:service:WANPPPConnection:1",
330
"upnp:rootdevice",
331
/*"ssdp:all",*/
332
0
333
};
334
return upnpDiscoverDevices(deviceList,
335
delay, multicastif, minissdpdsock, localport,
336
ipv6, ttl, error, 0);
337
}
338
339
/* upnpDiscoverAll() Discover all UPnP devices */
340
MINIUPNP_LIBSPEC struct UPNPDev *
341
upnpDiscoverAll(int delay, const char * multicastif,
342
const char * minissdpdsock, int localport,
343
int ipv6, unsigned char ttl,
344
int * error)
345
{
346
static const char * const deviceList[] = {
347
/*"upnp:rootdevice",*/
348
"ssdp:all",
349
0
350
};
351
return upnpDiscoverDevices(deviceList,
352
delay, multicastif, minissdpdsock, localport,
353
ipv6, ttl, error, 0);
354
}
355
356
/* upnpDiscoverDevice() Discover a specific device */
357
MINIUPNP_LIBSPEC struct UPNPDev *
358
upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
359
const char * minissdpdsock, int localport,
360
int ipv6, unsigned char ttl,
361
int * error)
362
{
363
const char * const deviceList[] = {
364
device,
365
0
366
};
367
return upnpDiscoverDevices(deviceList,
368
delay, multicastif, minissdpdsock, localport,
369
ipv6, ttl, error, 0);
370
}
371
372
static char *
373
build_absolute_url(const char * baseurl, const char * descURL,
374
const char * url, unsigned int scope_id)
375
{
376
size_t l, n;
377
char * s;
378
const char * base;
379
char * p;
380
#if defined(IF_NAMESIZE) && !defined(_WIN32)
381
char ifname[IF_NAMESIZE];
382
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
383
char scope_str[8];
384
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
385
386
if( (url[0] == 'h')
387
&&(url[1] == 't')
388
&&(url[2] == 't')
389
&&(url[3] == 'p')
390
&&(url[4] == ':')
391
&&(url[5] == '/')
392
&&(url[6] == '/'))
393
return strdup(url);
394
base = (baseurl[0] == '\0') ? descURL : baseurl;
395
n = strlen(base);
396
if(n > 7) {
397
p = strchr(base + 7, '/');
398
if(p)
399
n = p - base;
400
}
401
l = n + strlen(url) + 1;
402
if(url[0] != '/')
403
l++;
404
if(scope_id != 0) {
405
#if defined(IF_NAMESIZE) && !defined(_WIN32)
406
if(if_indextoname(scope_id, ifname)) {
407
l += 3 + strlen(ifname); /* 3 == strlen(%25) */
408
}
409
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
410
/* under windows, scope is numerical */
411
l += 3 + snprintf(scope_str, sizeof(scope_str), "%u", scope_id);
412
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
413
}
414
s = malloc(l);
415
if(s == NULL) return NULL;
416
memcpy(s, base, n);
417
if(scope_id != 0) {
418
s[n] = '\0';
419
if(n > 13 && 0 == memcmp(s, "http://[fe80:", 13)) {
420
/* this is a linklocal IPv6 address */
421
p = strchr(s, ']');
422
if(p) {
423
/* insert %25<scope> into URL */
424
#if defined(IF_NAMESIZE) && !defined(_WIN32)
425
memmove(p + 3 + strlen(ifname), p, strlen(p) + 1);
426
memcpy(p, "%25", 3);
427
memcpy(p + 3, ifname, strlen(ifname));
428
n += 3 + strlen(ifname);
429
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
430
memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1);
431
memcpy(p, "%25", 3);
432
memcpy(p + 3, scope_str, strlen(scope_str));
433
n += 3 + strlen(scope_str);
434
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
435
}
436
}
437
}
438
if(url[0] != '/')
439
s[n++] = '/';
440
memcpy(s + n, url, l - n);
441
return s;
442
}
443
444
/* Prepare the Urls for usage...
445
*/
446
MINIUPNP_LIBSPEC void
447
GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
448
const char * descURL, unsigned int scope_id)
449
{
450
/* strdup descURL */
451
urls->rootdescURL = strdup(descURL);
452
453
/* get description of WANIPConnection */
454
urls->ipcondescURL = build_absolute_url(data->urlbase, descURL,
455
data->first.scpdurl, scope_id);
456
urls->controlURL = build_absolute_url(data->urlbase, descURL,
457
data->first.controlurl, scope_id);
458
urls->controlURL_CIF = build_absolute_url(data->urlbase, descURL,
459
data->CIF.controlurl, scope_id);
460
urls->controlURL_6FC = build_absolute_url(data->urlbase, descURL,
461
data->IPv6FC.controlurl, scope_id);
462
463
#ifdef DEBUG
464
printf("urls->ipcondescURL='%s'\n", urls->ipcondescURL);
465
printf("urls->controlURL='%s'\n", urls->controlURL);
466
printf("urls->controlURL_CIF='%s'\n", urls->controlURL_CIF);
467
printf("urls->controlURL_6FC='%s'\n", urls->controlURL_6FC);
468
#endif
469
}
470
471
MINIUPNP_LIBSPEC void
472
FreeUPNPUrls(struct UPNPUrls * urls)
473
{
474
if(!urls)
475
return;
476
free(urls->controlURL);
477
urls->controlURL = 0;
478
free(urls->ipcondescURL);
479
urls->ipcondescURL = 0;
480
free(urls->controlURL_CIF);
481
urls->controlURL_CIF = 0;
482
free(urls->controlURL_6FC);
483
urls->controlURL_6FC = 0;
484
free(urls->rootdescURL);
485
urls->rootdescURL = 0;
486
}
487
488
int
489
UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
490
{
491
char status[64];
492
unsigned int uptime;
493
status[0] = '\0';
494
UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
495
status, &uptime, NULL);
496
if(0 == strcmp("Connected", status))
497
return 1;
498
else if(0 == strcmp("Up", status)) /* Also accept "Up" */
499
return 1;
500
else
501
return 0;
502
}
503
504
505
/* UPNP_GetValidIGD() :
506
* return values :
507
* -1 = Internal error
508
* 0 = NO IGD found (UPNP_NO_IGD)
509
* 1 = A valid connected IGD has been found (UPNP_CONNECTED_IGD)
510
* 2 = A valid connected IGD has been found but its
511
* IP address is reserved (non routable) (UPNP_PRIVATEIP_IGD)
512
* 3 = A valid IGD has been found but it reported as
513
* not connected (UPNP_DISCONNECTED_IGD)
514
* 4 = an UPnP device has been found but was not recognized as an IGD
515
* (UPNP_UNKNOWN_DEVICE)
516
*
517
* In any positive non zero return case, the urls and data structures
518
* passed as parameters are set. Don't forget to call FreeUPNPUrls(urls) to
519
* free allocated memory.
520
*/
521
MINIUPNP_LIBSPEC int
522
UPNP_GetValidIGD(struct UPNPDev * devlist,
523
struct UPNPUrls * urls,
524
struct IGDdatas * data,
525
char * lanaddr, int lanaddrlen,
526
char * wanaddr, int wanaddrlen)
527
{
528
struct xml_desc {
529
char lanaddr[40];
530
char wanaddr[40];
531
char * xml;
532
int size;
533
int is_igd;
534
} * desc = NULL;
535
struct UPNPDev * dev;
536
int ndev = 0;
537
int i;
538
int state = -1; /* state 1 : IGD connected. State 2 : connected with reserved IP.
539
* State 3 : IGD. State 4 : anything */
540
int status_code = -1;
541
542
if(!devlist)
543
{
544
#ifdef DEBUG
545
printf("Empty devlist\n");
546
#endif
547
return 0;
548
}
549
/* counting total number of devices in the list */
550
for(dev = devlist; dev; dev = dev->pNext)
551
ndev++;
552
/* ndev is always > 0 */
553
desc = calloc(ndev, sizeof(struct xml_desc));
554
if(!desc)
555
return -1; /* memory allocation error */
556
/* Step 1 : downloading descriptions and testing type */
557
for(dev = devlist, i = 0; dev; dev = dev->pNext, i++)
558
{
559
/* we should choose an internet gateway device.
560
* with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
561
desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size),
562
desc[i].lanaddr, sizeof(desc[i].lanaddr),
563
dev->scope_id, &status_code);
564
#ifdef DEBUG
565
if(!desc[i].xml)
566
{
567
printf("error getting XML description %s\n", dev->descURL);
568
}
569
#endif
570
if(desc[i].xml)
571
{
572
memset(data, 0, sizeof(struct IGDdatas));
573
memset(urls, 0, sizeof(struct UPNPUrls));
574
parserootdesc(desc[i].xml, desc[i].size, data);
575
if(COMPARE(data->CIF.servicetype,
576
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:"))
577
{
578
desc[i].is_igd = 1;
579
}
580
}
581
}
582
/* iterate the list to find a device depending on state */
583
for(state = 1; state <= 4; state++)
584
{
585
for(dev = devlist, i = 0; dev; dev = dev->pNext, i++)
586
{
587
if(desc[i].xml)
588
{
589
memset(data, 0, sizeof(struct IGDdatas));
590
memset(urls, 0, sizeof(struct UPNPUrls));
591
parserootdesc(desc[i].xml, desc[i].size, data);
592
if(desc[i].is_igd || state >= 4 )
593
{
594
int is_connected;
595
596
GetUPNPUrls(urls, data, dev->descURL, dev->scope_id);
597
598
/* in state 3 and 4 we don't test if device is connected ! */
599
if(state >= 3)
600
goto free_and_return;
601
is_connected = UPNPIGD_IsConnected(urls, data);
602
#ifdef DEBUG
603
printf("UPNPIGD_IsConnected(%s) = %d\n",
604
urls->controlURL, is_connected);
605
#endif
606
/* checks that status is connected AND there is a external IP address assigned */
607
if(is_connected) {
608
if(state >= 2)
609
goto free_and_return;
610
if(UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, desc[i].wanaddr) == 0
611
&& !addr_is_reserved(desc[i].wanaddr))
612
goto free_and_return;
613
}
614
FreeUPNPUrls(urls);
615
if(data->second.servicetype[0] != '\0') {
616
#ifdef DEBUG
617
printf("We tried %s, now we try %s !\n",
618
data->first.servicetype, data->second.servicetype);
619
#endif
620
/* swaping WANPPPConnection and WANIPConnection ! */
621
memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service));
622
memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service));
623
memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service));
624
GetUPNPUrls(urls, data, dev->descURL, dev->scope_id);
625
is_connected = UPNPIGD_IsConnected(urls, data);
626
#ifdef DEBUG
627
printf("UPNPIGD_IsConnected(%s) = %d\n",
628
urls->controlURL, is_connected);
629
#endif
630
if(is_connected) {
631
if(state >= 2)
632
goto free_and_return;
633
if(UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, desc[i].wanaddr) == 0
634
&& !addr_is_reserved(desc[i].wanaddr))
635
goto free_and_return;
636
}
637
FreeUPNPUrls(urls);
638
}
639
}
640
memset(data, 0, sizeof(struct IGDdatas));
641
}
642
}
643
}
644
state = 0;
645
free_and_return:
646
if (state >= 1 && state <= 4 && i < ndev) {
647
if (lanaddr != NULL)
648
strncpy(lanaddr, desc[i].lanaddr, lanaddrlen);
649
if (wanaddr != NULL)
650
strncpy(wanaddr, desc[i].wanaddr, wanaddrlen);
651
}
652
for(i = 0; i < ndev; i++)
653
free(desc[i].xml);
654
free(desc);
655
return state;
656
}
657
658
/* UPNP_GetIGDFromUrl()
659
* Used when skipping the discovery process.
660
* return value :
661
* 0 - Not ok
662
* 1 - OK */
663
int
664
UPNP_GetIGDFromUrl(const char * rootdescurl,
665
struct UPNPUrls * urls,
666
struct IGDdatas * data,
667
char * lanaddr, int lanaddrlen)
668
{
669
char * descXML;
670
int descXMLsize = 0;
671
672
descXML = miniwget_getaddr(rootdescurl, &descXMLsize,
673
lanaddr, lanaddrlen, 0, NULL);
674
if(descXML) {
675
memset(data, 0, sizeof(struct IGDdatas));
676
memset(urls, 0, sizeof(struct UPNPUrls));
677
parserootdesc(descXML, descXMLsize, data);
678
free(descXML);
679
GetUPNPUrls(urls, data, rootdescurl, 0);
680
return 1;
681
} else {
682
return 0;
683
}
684
}
685
686