1 /* $Id: miniupnpc.c,v 1.103 2012/03/05 19:42:46 nanard Exp $ */
3 * Web : http://miniupnp.free.fr/
4 * Author : Thomas BERNARD
5 * copyright (c) 2005-2012 Thomas Bernard
6 * This software is subjet to the conditions detailed in the
7 * provided LICENSE file. */
8 #define __EXTENSIONS__ 1
9 #if !defined(MACOSX) && !defined(__sun)
10 #if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) && !defined(__NetBSD__)
12 #define _XOPEN_SOURCE 600
16 #define __BSD_VISIBLE 1
20 #if !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(MACOSX) && !defined(_WIN32)
21 /* miniupnpc's unmodified source says _BSD_SOURCE or _GNU_SOURCE is needed
22 for struct ip_mreqn... since the above #if chain rules out the former,
23 use the latter here */
32 /* Win32 Specific includes and defines */
37 #define snprintf _snprintf
39 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
40 #define strncasecmp _memicmp
41 #else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
42 #define strncasecmp memicmp
43 #endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
44 #endif /* #ifndef strncasecmp */
45 #define MAXHOSTNAMELEN 64
46 #else /* #ifdef _WIN32 */
47 /* Standard POSIX includes */
49 #if defined(__amigaos__) && !defined(__amigaos4__)
50 /* Amiga OS 3 specific stuff */
53 #include <sys/select.h>
55 #include <sys/socket.h>
56 #include <sys/types.h>
57 #include <sys/param.h>
58 #include <netinet/in.h>
59 #include <arpa/inet.h>
62 #if !defined(__amigaos__) && !defined(__amigaos4__)
67 #define closesocket close
68 #endif /* #else _WIN32 */
69 #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
72 #if defined(__amigaos__) || defined(__amigaos4__)
73 /* Amiga OS specific stuff */
74 #define TIMEVAL struct timeval
77 #include "miniupnpc.h"
78 #include "minissdpc.h"
82 #include "upnpcommands.h"
83 #include "connecthostport.h"
84 #include "receivedata.h"
87 #define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
89 #define PRINT_SOCKET_ERROR(x) perror(x)
92 #define SOAPPREFIX "s"
93 #define SERVICEPREFIX "u"
94 #define SERVICEPREFIX2 'u'
96 /* root description parsing */
97 LIBSPEC
void parserootdesc(const char * buffer
, int bufsize
, struct IGDdatas
* data
)
99 struct xmlparser parser
;
100 /* xmlparser object */
101 parser
.xmlstart
= buffer
;
102 parser
.xmlsize
= bufsize
;
104 parser
.starteltfunc
= IGDstartelt
;
105 parser
.endeltfunc
= IGDendelt
;
106 parser
.datafunc
= IGDdata
;
114 /* simpleUPnPcommand2 :
120 simpleUPnPcommand2(int s
, const char * url
, const char * service
,
121 const char * action
, struct UPNParg
* args
,
122 int * bufsize
, const char * httpversion
)
124 char hostname
[MAXHOSTNAMELEN
+1];
125 unsigned short port
= 0;
133 snprintf(soapact
, sizeof(soapact
), "%s#%s", service
, action
);
136 /*soapbodylen = */snprintf(soapbody
, sizeof(soapbody
),
137 "<?xml version=\"1.0\"?>\r\n"
138 "<" SOAPPREFIX
":Envelope "
139 "xmlns:" SOAPPREFIX
"=\"http://schemas.xmlsoap.org/soap/envelope/\" "
140 SOAPPREFIX
":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
141 "<" SOAPPREFIX
":Body>"
142 "<" SERVICEPREFIX
":%s xmlns:" SERVICEPREFIX
"=\"%s\">"
143 "</" SERVICEPREFIX
":%s>"
144 "</" SOAPPREFIX
":Body></" SOAPPREFIX
":Envelope>"
145 "\r\n", action
, service
, action
);
150 const char * pe
, * pv
;
152 soapbodylen
= snprintf(soapbody
, sizeof(soapbody
),
153 "<?xml version=\"1.0\"?>\r\n"
154 "<" SOAPPREFIX
":Envelope "
155 "xmlns:" SOAPPREFIX
"=\"http://schemas.xmlsoap.org/soap/envelope/\" "
156 SOAPPREFIX
":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
157 "<" SOAPPREFIX
":Body>"
158 "<" SERVICEPREFIX
":%s xmlns:" SERVICEPREFIX
"=\"%s\">",
160 p
= soapbody
+ soapbodylen
;
163 /* check that we are never overflowing the string... */
164 if(soapbody
+ sizeof(soapbody
) <= p
+ 100)
166 /* we keep a margin of at least 100 bytes */
189 *(p
++) = SERVICEPREFIX2
;
194 strncpy(p
, "></" SOAPPREFIX
":Body></" SOAPPREFIX
":Envelope>\r\n",
195 soapbody
+ sizeof(soapbody
) - p
);
197 if(!parseURL(url
, hostname
, &port
, &path
)) return NULL
;
200 s
= connecthostport(hostname
, port
);
207 n
= soapPostSubmit(s
, path
, hostname
, port
, soapact
, soapbody
, httpversion
);
210 printf("Error sending SOAP request\n");
216 buf
= getHTTPResponse(s
, bufsize
);
218 if(*bufsize
> 0 && buf
)
220 printf("SOAP Response :\n%.*s\n", *bufsize
, buf
);
227 /* simpleUPnPcommand :
232 char * simpleUPnPcommand(int s
, const char * url
, const char * service
,
233 const char * action
, struct UPNParg
* args
,
238 buf
= simpleUPnPcommand2(s
, url
, service
, action
, args
, bufsize
, "1.1");
240 buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.0");
241 if (!buf || *bufsize == 0)
244 printf("Error or no result from SOAP request; retrying with HTTP/1.1\n");
246 buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1");
252 /* parseMSEARCHReply()
253 * the last 4 arguments are filled during the parsing :
254 * - location/locationsize : "location:" field of the SSDP reply packet
255 * - st/stsize : "st:" field of the SSDP reply packet.
256 * The strings are NOT null terminated */
258 parseMSEARCHReply(const char * reply
, int size
,
259 const char * * location
, int * locationsize
,
260 const char * * st
, int * stsize
)
264 a
= i
; /* start of the line */
265 b
= 0; /* end of the "header" (position of the colon) */
273 b
= i
; /* end of the "header" */
285 /*for(j=b+1; j<i; j++)
290 /* skip the colon and white spaces */
291 do { b
++; } while(reply
[b
]==' ');
292 if(0==strncasecmp(reply
+a
, "location", 8))
297 else if(0==strncasecmp(reply
+a
, "st", 2))
313 /* port upnp discover : SSDP protocol */
315 #define XSTR(s) STR(s)
317 #define UPNP_MCAST_ADDR "239.255.255.250"
319 #define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */
320 #define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */
323 * return a chained list of all devices found or NULL if
324 * no devices was found.
325 * It is up to the caller to free the chained list
326 * delay is in millisecond (poll) */
327 LIBSPEC
struct UPNPDev
*
328 upnpDiscover(int delay
, const char * multicastif
,
329 const char * minissdpdsock
, int sameport
,
333 struct UPNPDev
* tmp
;
334 struct UPNPDev
* devlist
= 0;
336 static const char MSearchMsgFmt
[] =
337 "M-SEARCH * HTTP/1.1\r\n"
338 "HOST: %s:" XSTR(PORT
) "\r\n"
340 "MAN: \"ssdp:discover\"\r\n"
343 static const char * const deviceList
[] = {
345 "urn:schemas-upnp-org:device:InternetGatewayDevice:2",
346 "urn:schemas-upnp-org:service:WANIPConnection:2",
348 "urn:schemas-upnp-org:device:InternetGatewayDevice:1",
349 "urn:schemas-upnp-org:service:WANIPConnection:1",
350 "urn:schemas-upnp-org:service:WANPPPConnection:1",
355 char bufr
[1536]; /* reception and emission buffer */
358 struct sockaddr_storage sockudp_r
;
360 #ifdef NO_GETADDRINFO
361 struct sockaddr_storage sockudp_w
;
364 struct addrinfo hints
, *servinfo
, *p
;
367 MIB_IPFORWARDROW ip_forward
;
372 *error
= UPNPDISCOVER_UNKNOWN_ERROR
;
373 #if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
374 /* first try to get infos from minissdpd ! */
376 minissdpdsock
= "/var/run/minissdpd.sock";
377 while(!devlist
&& deviceList
[deviceIndex
]) {
378 devlist
= getDevicesFromMiniSSDPD(deviceList
[deviceIndex
],
380 /* We return what we have found if it was not only a rootdevice */
381 if(devlist
&& !strstr(deviceList
[deviceIndex
], "rootdevice")) {
383 *error
= UPNPDISCOVER_SUCCESS
;
390 /* fallback to direct discovery */
392 sudp
= socket(ipv6
? PF_INET6
: PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
394 sudp
= socket(ipv6
? PF_INET6
: PF_INET
, SOCK_DGRAM
, 0);
399 *error
= UPNPDISCOVER_SOCKET_ERROR
;
400 PRINT_SOCKET_ERROR("socket");
404 memset(&sockudp_r
, 0, sizeof(struct sockaddr_storage
));
406 struct sockaddr_in6
* p
= (struct sockaddr_in6
*)&sockudp_r
;
407 p
->sin6_family
= AF_INET6
;
409 p
->sin6_port
= htons(PORT
);
410 p
->sin6_addr
= in6addr_any
; /* in6addr_any is not available with MinGW32 3.4.2 */
412 struct sockaddr_in
* p
= (struct sockaddr_in
*)&sockudp_r
;
413 p
->sin_family
= AF_INET
;
415 p
->sin_port
= htons(PORT
);
416 p
->sin_addr
.s_addr
= INADDR_ANY
;
419 /* This code could help us to use the right Network interface for
420 * SSDP multicast traffic */
421 /* Get IP associated with the index given in the ip_forward struct
422 * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
424 && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward
) == NO_ERROR
)) {
426 PMIB_IPADDRTABLE pIPAddrTable
;
433 printf("ifIndex=%lu nextHop=%lx \n", ip_forward
.dwForwardIfIndex
, ip_forward
.dwForwardNextHop
);
435 pIPAddrTable
= (MIB_IPADDRTABLE
*) malloc(sizeof (MIB_IPADDRTABLE
));
436 if (GetIpAddrTable(pIPAddrTable
, &dwSize
, 0) == ERROR_INSUFFICIENT_BUFFER
) {
438 pIPAddrTable
= (MIB_IPADDRTABLE
*) malloc(dwSize
);
441 dwRetVal
= GetIpAddrTable( pIPAddrTable
, &dwSize
, 0 );
443 printf("\tNum Entries: %ld\n", pIPAddrTable
->dwNumEntries
);
445 for (i
=0; i
< (int) pIPAddrTable
->dwNumEntries
; i
++) {
447 printf("\n\tInterface Index[%d]:\t%ld\n", i
, pIPAddrTable
->table
[i
].dwIndex
);
448 IPAddr
.S_un
.S_addr
= (u_long
) pIPAddrTable
->table
[i
].dwAddr
;
449 printf("\tIP Address[%d]: \t%s\n", i
, inet_ntoa(IPAddr
) );
450 IPAddr
.S_un
.S_addr
= (u_long
) pIPAddrTable
->table
[i
].dwMask
;
451 printf("\tSubnet Mask[%d]: \t%s\n", i
, inet_ntoa(IPAddr
) );
452 IPAddr
.S_un
.S_addr
= (u_long
) pIPAddrTable
->table
[i
].dwBCastAddr
;
453 printf("\tBroadCast[%d]: \t%s (%ld)\n", i
, inet_ntoa(IPAddr
), pIPAddrTable
->table
[i
].dwBCastAddr
);
454 printf("\tReassembly size[%d]:\t%ld\n", i
, pIPAddrTable
->table
[i
].dwReasmSize
);
455 printf("\tType and State[%d]:", i
);
458 if (pIPAddrTable
->table
[i
].dwIndex
== ip_forward
.dwForwardIfIndex
) {
459 /* Set the address of this interface to be used */
460 struct in_addr mc_if
;
461 memset(&mc_if
, 0, sizeof(mc_if
));
462 mc_if
.s_addr
= pIPAddrTable
->table
[i
].dwAddr
;
463 if(setsockopt(sudp
, IPPROTO_IP
, IP_MULTICAST_IF
, (const char *)&mc_if
, sizeof(mc_if
)) < 0) {
464 PRINT_SOCKET_ERROR("setsockopt");
466 ((struct sockaddr_in
*)&sockudp_r
)->sin_addr
.s_addr
= pIPAddrTable
->table
[i
].dwAddr
;
479 if (setsockopt(sudp
, SOL_SOCKET
, SO_REUSEADDR
, (const char *)&opt
, sizeof (opt
)) < 0)
481 if (setsockopt(sudp
, SOL_SOCKET
, SO_REUSEADDR
, &opt
, sizeof (opt
)) < 0)
485 *error
= UPNPDISCOVER_SOCKET_ERROR
;
486 PRINT_SOCKET_ERROR("setsockopt");
494 /* according to MSDN, if_nametoindex() is supported since
495 * MS Windows Vista and MS Windows Server 2008.
496 * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */
497 unsigned int ifindex
= if_nametoindex(multicastif
); /* eth0, etc. */
498 if(setsockopt(sudp
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &ifindex
, sizeof(&ifindex
)) < 0)
500 PRINT_SOCKET_ERROR("setsockopt");
504 printf("Setting of multicast interface not supported in IPv6 under Windows.\n");
508 struct in_addr mc_if
;
509 mc_if
.s_addr
= inet_addr(multicastif
); /* ex: 192.168.x.x */
510 if(mc_if
.s_addr
!= INADDR_NONE
)
512 ((struct sockaddr_in
*)&sockudp_r
)->sin_addr
.s_addr
= mc_if
.s_addr
;
513 if(setsockopt(sudp
, IPPROTO_IP
, IP_MULTICAST_IF
, (const char *)&mc_if
, sizeof(mc_if
)) < 0)
515 PRINT_SOCKET_ERROR("setsockopt");
519 /* was not an ip address, try with an interface name */
520 struct ip_mreqn reqn
; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */
521 memset(&reqn
, 0, sizeof(struct ip_mreqn
));
522 reqn
.imr_ifindex
= if_nametoindex(multicastif
);
523 if(setsockopt(sudp
, IPPROTO_IP
, IP_MULTICAST_IF
, (const char *)&reqn
, sizeof(reqn
)) < 0)
525 PRINT_SOCKET_ERROR("setsockopt");
529 printf("Setting of multicast interface not supported with interface name.\n");
536 /* Avant d'envoyer le paquet on bind pour recevoir la reponse */
537 if (bind(sudp
, (const struct sockaddr
*)&sockudp_r
,
538 ipv6
? sizeof(struct sockaddr_in6
) : sizeof(struct sockaddr_in
)) != 0)
541 *error
= UPNPDISCOVER_SOCKET_ERROR
;
542 PRINT_SOCKET_ERROR("bind");
548 *error
= UPNPDISCOVER_SUCCESS
;
549 /* Calculating maximum response time in seconds */
550 mx
= ((unsigned int)delay
) / 1000u;
551 /* receiving SSDP response packet */
552 for(n
= 0; deviceList
[deviceIndex
]; deviceIndex
++)
556 /* sending the SSDP M-SEARCH packet */
557 n
= snprintf(bufr
, sizeof(bufr
),
560 (linklocal
? "[" UPNP_MCAST_LL_ADDR
"]" : "[" UPNP_MCAST_SL_ADDR
"]")
562 deviceList
[deviceIndex
], mx
);
564 printf("Sending %s", bufr
);
566 #ifdef NO_GETADDRINFO
567 /* the following code is not using getaddrinfo */
569 memset(&sockudp_w
, 0, sizeof(struct sockaddr_storage
));
571 struct sockaddr_in6
* p
= (struct sockaddr_in6
*)&sockudp_w
;
572 p
->sin6_family
= AF_INET6
;
573 p
->sin6_port
= htons(PORT
);
575 linklocal
? UPNP_MCAST_LL_ADDR
: UPNP_MCAST_SL_ADDR
,
578 struct sockaddr_in
* p
= (struct sockaddr_in
*)&sockudp_w
;
579 p
->sin_family
= AF_INET
;
580 p
->sin_port
= htons(PORT
);
581 p
->sin_addr
.s_addr
= inet_addr(UPNP_MCAST_ADDR
);
583 n
= sendto(sudp
, bufr
, n
, 0,
585 ipv6
? sizeof(struct sockaddr_in6
) : sizeof(struct sockaddr_in
));
588 *error
= UPNPDISCOVER_SOCKET_ERROR
;
589 PRINT_SOCKET_ERROR("sendto");
592 #else /* #ifdef NO_GETADDRINFO */
593 memset(&hints
, 0, sizeof(hints
));
594 hints
.ai_family
= AF_UNSPEC
; // AF_INET6 or AF_INET
595 hints
.ai_socktype
= SOCK_DGRAM
;
596 /*hints.ai_flags = */
597 if ((rv
= getaddrinfo(ipv6
598 ? (linklocal
? UPNP_MCAST_LL_ADDR
: UPNP_MCAST_SL_ADDR
)
600 XSTR(PORT
), &hints
, &servinfo
)) != 0) {
602 *error
= UPNPDISCOVER_SOCKET_ERROR
;
604 fprintf(stderr
, "getaddrinfo() failed: %d\n", rv
);
606 fprintf(stderr
, "getaddrinfo: %s\n", gai_strerror(rv
));
610 for(p
= servinfo
; p
; p
= p
->ai_next
) {
611 n
= sendto(sudp
, bufr
, n
, 0, p
->ai_addr
, p
->ai_addrlen
);
613 PRINT_SOCKET_ERROR("sendto");
617 freeaddrinfo(servinfo
);
620 *error
= UPNPDISCOVER_SOCKET_ERROR
;
623 #endif /* #ifdef NO_GETADDRINFO */
625 /* Waiting for SSDP REPLY packet to M-SEARCH */
626 n
= receivedata(sudp
, bufr
, sizeof(bufr
), delay
);
630 *error
= UPNPDISCOVER_SOCKET_ERROR
;
633 /* no data or Time Out */
635 /* no more device type to look for... */
637 *error
= UPNPDISCOVER_SUCCESS
;
649 const char * descURL
=NULL
;
651 const char * st
=NULL
;
653 /*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */
654 parseMSEARCHReply(bufr
, n
, &descURL
, &urlsize
, &st
, &stsize
);
658 printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n",
659 stsize
, st
, urlsize
, descURL
);
661 for(tmp
=devlist
; tmp
; tmp
= tmp
->pNext
) {
662 if(memcmp(tmp
->descURL
, descURL
, urlsize
) == 0 &&
663 tmp
->descURL
[urlsize
] == '\0' &&
664 memcmp(tmp
->st
, st
, stsize
) == 0 &&
665 tmp
->st
[stsize
] == '\0')
668 /* at the exit of the loop above, tmp is null if
669 * no duplicate device was found */
672 tmp
= (struct UPNPDev
*)malloc(sizeof(struct UPNPDev
)+urlsize
+stsize
);
674 /* memory allocation error */
676 *error
= UPNPDISCOVER_MEMORY_ERROR
;
679 tmp
->pNext
= devlist
;
680 tmp
->descURL
= tmp
->buffer
;
681 tmp
->st
= tmp
->buffer
+ 1 + urlsize
;
682 memcpy(tmp
->buffer
, descURL
, urlsize
);
683 tmp
->buffer
[urlsize
] = '\0';
684 memcpy(tmp
->buffer
+ urlsize
+ 1, st
, stsize
);
685 tmp
->buffer
[urlsize
+1+stsize
] = '\0';
694 /* freeUPNPDevlist() should be used to
695 * free the chained list returned by upnpDiscover() */
696 LIBSPEC
void freeUPNPDevlist(struct UPNPDev
* devlist
)
698 struct UPNPDev
* next
;
701 next
= devlist
->pNext
;
708 url_cpy_or_cat(char * dst
, const char * src
, int n
)
718 strncpy(dst
, src
, n
);
726 strncpy(dst
+ l
, src
, n
- l
);
730 /* Prepare the Urls for usage...
732 LIBSPEC
void GetUPNPUrls(struct UPNPUrls
* urls
, struct IGDdatas
* data
,
733 const char * descURL
)
738 n1
= strlen(data
->urlbase
);
740 n1
= strlen(descURL
);
741 n1
+= 2; /* 1 byte more for Null terminator, 1 byte for '/' if needed */
742 n2
= n1
; n3
= n1
; n4
= n1
;
743 n1
+= strlen(data
->first
.scpdurl
);
744 n2
+= strlen(data
->first
.controlurl
);
745 n3
+= strlen(data
->CIF
.controlurl
);
746 n4
+= strlen(data
->IPv6FC
.controlurl
);
748 /* allocate memory to store URLs */
749 urls
->ipcondescURL
= (char *)malloc(n1
);
750 urls
->controlURL
= (char *)malloc(n2
);
751 urls
->controlURL_CIF
= (char *)malloc(n3
);
752 urls
->controlURL_6FC
= (char *)malloc(n4
);
755 urls
->rootdescURL
= strdup(descURL
);
757 /* get description of WANIPConnection */
758 if(data
->urlbase
[0] != '\0')
759 strncpy(urls
->ipcondescURL
, data
->urlbase
, n1
);
761 strncpy(urls
->ipcondescURL
, descURL
, n1
);
762 p
= strchr(urls
->ipcondescURL
+7, '/');
764 strncpy(urls
->controlURL
, urls
->ipcondescURL
, n2
);
765 strncpy(urls
->controlURL_CIF
, urls
->ipcondescURL
, n3
);
766 strncpy(urls
->controlURL_6FC
, urls
->ipcondescURL
, n4
);
768 url_cpy_or_cat(urls
->ipcondescURL
, data
->first
.scpdurl
, n1
);
770 url_cpy_or_cat(urls
->controlURL
, data
->first
.controlurl
, n2
);
772 url_cpy_or_cat(urls
->controlURL_CIF
, data
->CIF
.controlurl
, n3
);
774 url_cpy_or_cat(urls
->controlURL_6FC
, data
->IPv6FC
.controlurl
, n4
);
777 printf("urls->ipcondescURL='%s' %u n1=%d\n", urls
->ipcondescURL
,
778 (unsigned)strlen(urls
->ipcondescURL
), n1
);
779 printf("urls->controlURL='%s' %u n2=%d\n", urls
->controlURL
,
780 (unsigned)strlen(urls
->controlURL
), n2
);
781 printf("urls->controlURL_CIF='%s' %u n3=%d\n", urls
->controlURL_CIF
,
782 (unsigned)strlen(urls
->controlURL_CIF
), n3
);
783 printf("urls->controlURL_6FC='%s' %u n4=%d\n", urls
->controlURL_6FC
,
784 (unsigned)strlen(urls
->controlURL_6FC
), n4
);
789 FreeUPNPUrls(struct UPNPUrls
* urls
)
793 free(urls
->controlURL
);
794 urls
->controlURL
= 0;
795 free(urls
->ipcondescURL
);
796 urls
->ipcondescURL
= 0;
797 free(urls
->controlURL_CIF
);
798 urls
->controlURL_CIF
= 0;
799 free(urls
->controlURL_6FC
);
800 urls
->controlURL_6FC
= 0;
801 free(urls
->rootdescURL
);
802 urls
->rootdescURL
= 0;
806 UPNPIGD_IsConnected(struct UPNPUrls
* urls
, struct IGDdatas
* data
)
811 UPNP_GetStatusInfo(urls
->controlURL
, data
->first
.servicetype
,
812 status
, &uptime
, NULL
);
813 if(0 == strcmp("Connected", status
))
822 /* UPNP_GetValidIGD() :
825 * 1 = A valid connected IGD has been found
826 * 2 = A valid IGD has been found but it reported as
828 * 3 = an UPnP device has been found but was not recognized as an IGD
830 * In any non zero return case, the urls and data structures
831 * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
832 * free allocated memory.
835 UPNP_GetValidIGD(struct UPNPDev
* devlist
,
836 struct UPNPUrls
* urls
,
837 struct IGDdatas
* data
,
838 char * lanaddr
, int lanaddrlen
)
842 struct UPNPDev
* dev
;
844 int state
; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */
848 printf("Empty devlist\n");
852 for(state
= 1; state
<= 3; state
++)
854 for(dev
= devlist
; dev
; dev
= dev
->pNext
)
856 /* we should choose an internet gateway device.
857 * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
858 descXML
= miniwget_getaddr(dev
->descURL
, &descXMLsize
,
859 lanaddr
, lanaddrlen
);
863 memset(data
, 0, sizeof(struct IGDdatas
));
864 memset(urls
, 0, sizeof(struct UPNPUrls
));
865 parserootdesc(descXML
, descXMLsize
, data
);
868 if(0==strcmp(data
->CIF
.servicetype
,
869 "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")
872 GetUPNPUrls(urls
, data
, dev
->descURL
);
875 printf("UPNPIGD_IsConnected(%s) = %d\n",
877 UPNPIGD_IsConnected(urls
, data
));
879 if((state
>= 2) || UPNPIGD_IsConnected(urls
, data
))
882 if(data
->second
.servicetype
[0] != '\0') {
884 printf("We tried %s, now we try %s !\n",
885 data
->first
.servicetype
, data
->second
.servicetype
);
887 /* swaping WANPPPConnection and WANIPConnection ! */
888 memcpy(&data
->tmp
, &data
->first
, sizeof(struct IGDdatas_service
));
889 memcpy(&data
->first
, &data
->second
, sizeof(struct IGDdatas_service
));
890 memcpy(&data
->second
, &data
->tmp
, sizeof(struct IGDdatas_service
));
891 GetUPNPUrls(urls
, data
, dev
->descURL
);
893 printf("UPNPIGD_IsConnected(%s) = %d\n",
895 UPNPIGD_IsConnected(urls
, data
));
897 if((state
>= 2) || UPNPIGD_IsConnected(urls
, data
))
902 memset(data
, 0, sizeof(struct IGDdatas
));
907 printf("error getting XML description %s\n", dev
->descURL
);
915 /* UPNP_GetIGDFromUrl()
916 * Used when skipping the discovery process.
921 UPNP_GetIGDFromUrl(const char * rootdescurl
,
922 struct UPNPUrls
* urls
,
923 struct IGDdatas
* data
,
924 char * lanaddr
, int lanaddrlen
)
928 descXML
= miniwget_getaddr(rootdescurl
, &descXMLsize
,
929 lanaddr
, lanaddrlen
);
931 memset(data
, 0, sizeof(struct IGDdatas
));
932 memset(urls
, 0, sizeof(struct UPNPUrls
));
933 parserootdesc(descXML
, descXMLsize
, data
);
936 GetUPNPUrls(urls
, data
, rootdescurl
);