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