1/* $Id: miniupnpc.c,v 1.123 2014/11/27 12:02:25 nanard Exp $ */ 2/* Project : miniupnp 3 * Web : http://miniupnp.free.fr/ 4 * Author : Thomas BERNARD 5 * copyright (c) 2005-2014 Thomas Bernard 6 * This software is subjet to the conditions detailed in the 7 * provided LICENSE file. */ 8#define __EXTENSIONS__ 1 9#if !defined(__APPLE__) && !defined(__sun) 10#if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) && !defined(__NetBSD__) 11#ifndef __cplusplus 12#define _XOPEN_SOURCE 600 13#endif 14#endif 15#ifndef __BSD_VISIBLE 16#define __BSD_VISIBLE 1 17#endif 18#endif 19 20#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) && !defined(__GNU__) && !defined(__FreeBSD_kernel__) 21#define HAS_IP_MREQN 22#endif 23 24#include <stdlib.h> 25#include <stdio.h> 26#include <string.h> 27#ifdef _WIN32 28/* Win32 Specific includes and defines */ 29#include <winsock2.h> 30#include <ws2tcpip.h> 31#include <io.h> 32#include <iphlpapi.h> 33#define snprintf _snprintf 34#define strdup _strdup 35#ifndef strncasecmp 36#if defined(_MSC_VER) && (_MSC_VER >= 1400) 37#define strncasecmp _memicmp 38#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ 39#define strncasecmp memicmp 40#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ 41#endif /* #ifndef strncasecmp */ 42#define MAXHOSTNAMELEN 64 43#else /* #ifdef _WIN32 */ 44/* Standard POSIX includes */ 45#include <unistd.h> 46#if defined(__amigaos__) && !defined(__amigaos4__) 47/* Amiga OS 3 specific stuff */ 48#define socklen_t int 49#else 50#include <sys/select.h> 51#endif 52#include <syslog.h> 53#include <sys/ioctl.h> 54#include <sys/socket.h> 55#include <sys/types.h> 56#include <sys/param.h> 57#include <netinet/in.h> 58#include <arpa/inet.h> 59#include <netdb.h> 60#include <net/if.h> 61#if !defined(__amigaos__) && !defined(__amigaos4__) 62#include <poll.h> 63#endif 64#include <strings.h> 65#include <errno.h> 66#define closesocket close 67#endif /* #else _WIN32 */ 68#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT 69#include <sys/time.h> 70#endif 71#if defined(__amigaos__) || defined(__amigaos4__) 72/* Amiga OS specific stuff */ 73#define TIMEVAL struct timeval 74#endif 75#ifdef __GNU__ 76#define MAXHOSTNAMELEN 64 77#endif 78 79#include <shared.h> 80 81#if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN) 82/* Several versions of glibc don't define this structure, define it here and compile with CFLAGS NEED_STRUCT_IP_MREQN */ 83struct ip_mreqn 84{ 85 struct in_addr imr_multiaddr; /* IP multicast address of group */ 86 struct in_addr imr_address; /* local IP address of interface */ 87 int imr_ifindex; /* Interface index */ 88}; 89#endif 90 91#include "miniupnpc.h" 92#include "minissdpc.h" 93#include "miniwget.h" 94#include "minisoap.h" 95#include "minixml.h" 96#include "upnpcommands.h" 97#include "connecthostport.h" 98#include "receivedata.h" 99 100/* compare the begining of a string with a constant string */ 101#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1)) 102 103#ifdef _WIN32 104#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); 105#else 106#define PRINT_SOCKET_ERROR(x) perror(x) 107#endif 108 109#ifndef MAXHOSTNAMELEN 110#define MAXHOSTNAMELEN 64 111#endif 112 113#define SOAPPREFIX "s" 114#define SERVICEPREFIX "u" 115#define SERVICEPREFIX2 'u' 116 117 118/* root description parsing */ 119MINIUPNP_LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data) 120{ 121 struct xmlparser parser; 122 /* xmlparser object */ 123 parser.xmlstart = buffer; 124 parser.xmlsize = bufsize; 125 parser.data = data; 126 parser.starteltfunc = IGDstartelt; 127 parser.endeltfunc = IGDendelt; 128 parser.datafunc = IGDdata; 129 parser.attfunc = 0; 130 parsexml(&parser); 131#ifdef DEBUG 132/* 133 printIGD(data); 134*/ 135#endif 136} 137 138/* simpleUPnPcommand2 : 139 * not so simple ! 140 * return values : 141 * pointer - OK 142 * NULL - error */ 143char * simpleUPnPcommand2(int s, const char * url, const char * service, 144 const char * action, struct UPNParg * args, 145 int * bufsize, const char * httpversion) 146{ 147 char hostname[MAXHOSTNAMELEN+1]; 148 unsigned short port = 0; 149 char * path; 150 char soapact[128]; 151 char soapbody[2048]; 152 char * buf; 153 int n; 154 155 *bufsize = 0; 156 snprintf(soapact, sizeof(soapact), "%s#%s", service, action); 157 if(args==NULL) 158 { 159 /*soapbodylen = */snprintf(soapbody, sizeof(soapbody), 160 "<?xml version=\"1.0\"?>\r\n" 161 "<" SOAPPREFIX ":Envelope " 162 "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " 163 SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" 164 "<" SOAPPREFIX ":Body>" 165 "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">" 166 "</" SERVICEPREFIX ":%s>" 167 "</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>" 168 "\r\n", action, service, action); 169 } 170 else 171 { 172 char * p; 173 const char * pe, * pv; 174 int soapbodylen; 175 soapbodylen = snprintf(soapbody, sizeof(soapbody), 176 "<?xml version=\"1.0\"?>\r\n" 177 "<" SOAPPREFIX ":Envelope " 178 "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " 179 SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" 180 "<" SOAPPREFIX ":Body>" 181 "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">", 182 action, service); 183 p = soapbody + soapbodylen; 184 while(args->elt) 185 { 186 /* check that we are never overflowing the string... */ 187 if(soapbody + sizeof(soapbody) <= p + 100) 188 { 189 /* we keep a margin of at least 100 bytes */ 190 return NULL; 191 } 192 *(p++) = '<'; 193 pe = args->elt; 194 while(*pe) 195 *(p++) = *(pe++); 196 *(p++) = '>'; 197 if((pv = args->val)) 198 { 199 while(*pv) 200 *(p++) = *(pv++); 201 } 202 *(p++) = '<'; 203 *(p++) = '/'; 204 pe = args->elt; 205 while(*pe) 206 *(p++) = *(pe++); 207 *(p++) = '>'; 208 args++; 209 } 210 *(p++) = '<'; 211 *(p++) = '/'; 212 *(p++) = SERVICEPREFIX2; 213 *(p++) = ':'; 214 pe = action; 215 while(*pe) 216 *(p++) = *(pe++); 217 strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n", 218 soapbody + sizeof(soapbody) - p); 219 } 220 if(!parseURL(url, hostname, &port, &path, NULL)) return NULL; 221 if(s < 0) { 222 s = connecthostport(hostname, port, 0); 223 if(s < 0) { 224 /* failed to connect */ 225 return NULL; 226 } 227 } 228 229 n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion); 230 if(n<=0) { 231#ifdef DEBUG 232 printf("Error sending SOAP request\n"); 233#endif 234 closesocket(s); 235 return NULL; 236 } 237 238 buf = getHTTPResponse(s, bufsize, NULL); 239#ifdef DEBUG 240 if(*bufsize > 0 && buf) 241 { 242 printf("SOAP Response :\n%.*s\n", *bufsize, buf); 243 } 244#endif 245 closesocket(s); 246 return buf; 247} 248 249/* simpleUPnPcommand : 250 * not so simple ! 251 * return values : 252 * pointer - OK 253 * NULL - error */ 254char * simpleUPnPcommand(int s, const char * url, const char * service, 255 const char * action, struct UPNParg * args, 256 int * bufsize) 257{ 258 char * buf; 259 260#if 1 261 buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); 262#else 263 buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.0"); 264 if (!buf || *bufsize == 0) 265 { 266#if DEBUG 267 printf("Error or no result from SOAP request; retrying with HTTP/1.1\n"); 268#endif 269 buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); 270 } 271#endif 272 return buf; 273} 274 275/* parseMSEARCHReply() 276 * the last 4 arguments are filled during the parsing : 277 * - location/locationsize : "location:" field of the SSDP reply packet 278 * - st/stsize : "st:" field of the SSDP reply packet. 279 * The strings are NOT null terminated */ 280static void 281parseMSEARCHReply(const char * reply, int size, 282 const char * * location, int * locationsize, 283 const char * * st, int * stsize) 284{ 285 int a, b, i; 286 i = 0; 287 a = i; /* start of the line */ 288 b = 0; /* end of the "header" (position of the colon) */ 289 while(i<size) 290 { 291 switch(reply[i]) 292 { 293 case ':': 294 if(b==0) 295 { 296 b = i; /* end of the "header" */ 297 /*for(j=a; j<b; j++) 298 { 299 putchar(reply[j]); 300 } 301 */ 302 } 303 break; 304 case '\x0a': 305 case '\x0d': 306 if(b!=0) 307 { 308 /*for(j=b+1; j<i; j++) 309 { 310 putchar(reply[j]); 311 } 312 putchar('\n');*/ 313 /* skip the colon and white spaces */ 314 do { b++; } while(reply[b]==' '); 315 if(0==strncasecmp(reply+a, "location", 8)) 316 { 317 *location = reply+b; 318 *locationsize = i-b; 319 } 320 else if(0==strncasecmp(reply+a, "st", 2)) 321 { 322 *st = reply+b; 323 *stsize = i-b; 324 } 325 b = 0; 326 } 327 a = i+1; 328 break; 329 default: 330 break; 331 } 332 i++; 333 } 334} 335 336/* port upnp discover : SSDP protocol */ 337#define PORT 1900 338#define XSTR(s) STR(s) 339#define STR(s) #s 340#define UPNP_MCAST_ADDR "239.255.255.250" 341/* for IPv6 */ 342#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */ 343#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */ 344 345/* upnpDiscoverDevices() : 346 * return a chained list of all devices found or NULL if 347 * no devices was found. 348 * It is up to the caller to free the chained list 349 * delay is in millisecond (poll) */ 350MINIUPNP_LIBSPEC struct UPNPDev * 351upnpDiscoverDevices(const char * const deviceTypes[], 352 int delay, const char * multicastif, 353 const char * minissdpdsock, int sameport, 354 int ipv6, 355 int * error) 356{ 357 struct UPNPDev * tmp; 358 struct UPNPDev * devlist = 0; 359 unsigned int scope_id = 0; 360 int opt = 1; 361 static const char MSearchMsgFmt[] = 362 "M-SEARCH * HTTP/1.1\r\n" 363 "HOST: %s:" XSTR(PORT) "\r\n" 364 "ST: %s\r\n" 365 "MAN: \"ssdp:discover\"\r\n" 366 "MX: %u\r\n" 367 "\r\n"; 368 int deviceIndex; 369 char bufr[1536]; /* reception and emission buffer */ 370 int sudp; 371 int n; 372 struct sockaddr_storage sockudp_r; 373 unsigned int mx; 374#ifdef NO_GETADDRINFO 375 struct sockaddr_storage sockudp_w; 376#else 377 int rv; 378 struct addrinfo hints, *servinfo, *p; 379#endif 380#ifdef _WIN32 381 MIB_IPFORWARDROW ip_forward; 382#endif 383 int linklocal = 1; 384 385 if(error) 386 *error = UPNPDISCOVER_UNKNOWN_ERROR; 387#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) 388 /* first try to get infos from minissdpd ! */ 389 if(!minissdpdsock) 390 minissdpdsock = "/var/run/minissdpd.sock"; 391 for(deviceIndex = 0; !devlist && deviceTypes[deviceIndex]; deviceIndex++) { 392 devlist = getDevicesFromMiniSSDPD(deviceTypes[deviceIndex], 393 minissdpdsock); 394 /* We return what we have found if it was not only a rootdevice */ 395 if(devlist && !strstr(deviceTypes[deviceIndex], "rootdevice")) { 396 if(error) 397 *error = UPNPDISCOVER_SUCCESS; 398 return devlist; 399 } 400 } 401#endif 402 /* fallback to direct discovery */ 403#ifdef _WIN32 404 sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP); 405#else 406 sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0); 407#endif 408 if(sudp < 0) 409 { 410 if(error) 411 *error = UPNPDISCOVER_SOCKET_ERROR; 412 PRINT_SOCKET_ERROR("socket"); 413 return NULL; 414 } 415 416 /* reception */ 417 memset(&sockudp_r, 0, sizeof(struct sockaddr_storage)); 418 if(ipv6) { 419 struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r; 420 p->sin6_family = AF_INET6; 421 if(sameport) 422 p->sin6_port = htons(PORT); 423 p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */ 424 } else { 425 struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r; 426 p->sin_family = AF_INET; 427 if(sameport) 428 p->sin_port = htons(PORT); 429 p->sin_addr.s_addr = INADDR_ANY; 430 } 431#ifdef _WIN32 432/* This code could help us to use the right Network interface for 433 * SSDP multicast traffic */ 434/* Get IP associated with the index given in the ip_forward struct 435 * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */ 436 if(!ipv6 437 && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) { 438 DWORD dwRetVal = 0; 439 PMIB_IPADDRTABLE pIPAddrTable; 440 DWORD dwSize = 0; 441#ifdef DEBUG 442 IN_ADDR IPAddr; 443#endif 444 int i; 445#ifdef DEBUG 446 printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop); 447#endif 448 pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE)); 449 if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { 450 free(pIPAddrTable); 451 pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize); 452 } 453 if(pIPAddrTable) { 454 dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 ); 455#ifdef DEBUG 456 printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries); 457#endif 458 for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) { 459#ifdef DEBUG 460 printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex); 461 IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr; 462 printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); 463 IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask; 464 printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); 465 IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr; 466 printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr); 467 printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize); 468 printf("\tType and State[%d]:", i); 469 printf("\n"); 470#endif 471 if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) { 472 /* Set the address of this interface to be used */ 473 struct in_addr mc_if; 474 memset(&mc_if, 0, sizeof(mc_if)); 475 mc_if.s_addr = pIPAddrTable->table[i].dwAddr; 476 if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { 477 PRINT_SOCKET_ERROR("setsockopt"); 478 } 479 ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr; 480#ifndef DEBUG 481 break; 482#endif 483 } 484 } 485 free(pIPAddrTable); 486 pIPAddrTable = NULL; 487 } 488 } 489#endif 490 491#ifdef _WIN32 492 if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0) 493#else 494 if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0) 495#endif 496 { 497 if(error) 498 *error = UPNPDISCOVER_SOCKET_ERROR; 499 PRINT_SOCKET_ERROR("setsockopt"); 500 return NULL; 501 } 502 503 if(multicastif) 504 { 505 if(ipv6) { 506#if !defined(_WIN32) 507 /* according to MSDN, if_nametoindex() is supported since 508 * MS Windows Vista and MS Windows Server 2008. 509 * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */ 510 unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */ 511 if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(&ifindex)) < 0) 512 { 513 PRINT_SOCKET_ERROR("setsockopt"); 514 } 515#else 516#ifdef DEBUG 517 printf("Setting of multicast interface not supported in IPv6 under Windows.\n"); 518#endif 519#endif 520 } else { 521 struct in_addr mc_if; 522 mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */ 523 if(mc_if.s_addr != INADDR_NONE) 524 { 525 ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; 526 if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) 527 { 528 PRINT_SOCKET_ERROR("setsockopt"); 529 } 530 } else { 531#ifdef HAS_IP_MREQN 532 /* was not an ip address, try with an interface name */ 533 struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */ 534 memset(&reqn, 0, sizeof(struct ip_mreqn)); 535 reqn.imr_ifindex = if_nametoindex(multicastif); 536 if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0) 537 { 538 PRINT_SOCKET_ERROR("setsockopt"); 539 } 540#else 541#ifdef DEBUG 542 printf("Setting of multicast interface not supported with interface name.\n"); 543#endif 544#endif 545 } 546 } 547 } 548 549 /* Before sending the packed, we first "bind" in order to be able 550 * to receive the response */ 551 if (bind(sudp, (const struct sockaddr *)&sockudp_r, 552 ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0) 553 { 554 if(error) 555 *error = UPNPDISCOVER_SOCKET_ERROR; 556 PRINT_SOCKET_ERROR("bind"); 557 closesocket(sudp); 558 return NULL; 559 } 560 561 if(error) 562 *error = UPNPDISCOVER_SUCCESS; 563 /* Calculating maximum response time in seconds */ 564 mx = ((unsigned int)delay) / 1000u; 565 if(mx == 0) { 566 mx = 1; 567 delay = 1000; 568 } 569 /* receiving SSDP response packet */ 570 for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) { 571 /* sending the SSDP M-SEARCH packet */ 572 n = snprintf(bufr, sizeof(bufr), 573 MSearchMsgFmt, 574 ipv6 ? 575 (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") 576 : UPNP_MCAST_ADDR, 577 deviceTypes[deviceIndex], mx); 578#ifdef DEBUG 579 /*printf("Sending %s", bufr);*/ 580 printf("Sending M-SEARCH request to %s with ST: %s\n", 581 ipv6 ? 582 (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") 583 : UPNP_MCAST_ADDR, 584 deviceTypes[deviceIndex]); 585#endif 586#ifdef NO_GETADDRINFO 587 /* the following code is not using getaddrinfo */ 588 /* emission */ 589 memset(&sockudp_w, 0, sizeof(struct sockaddr_storage)); 590 if(ipv6) { 591 struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w; 592 p->sin6_family = AF_INET6; 593 p->sin6_port = htons(PORT); 594 inet_pton(AF_INET6, 595 linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR, 596 &(p->sin6_addr)); 597 } else { 598 struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w; 599 p->sin_family = AF_INET; 600 p->sin_port = htons(PORT); 601 p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR); 602 } 603 n = sendto(sudp, bufr, n, 0, &sockudp_w, 604 ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); 605 if (n < 0) { 606 if(error) 607 *error = UPNPDISCOVER_SOCKET_ERROR; 608 PRINT_SOCKET_ERROR("sendto"); 609 break; 610 } 611#else /* #ifdef NO_GETADDRINFO */ 612 memset(&hints, 0, sizeof(hints)); 613 hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */ 614 hints.ai_socktype = SOCK_DGRAM; 615 /*hints.ai_flags = */ 616 if ((rv = getaddrinfo(ipv6 617 ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR) 618 : UPNP_MCAST_ADDR, 619 XSTR(PORT), &hints, &servinfo)) != 0) { 620 if(error) 621 *error = UPNPDISCOVER_SOCKET_ERROR; 622#ifdef _WIN32 623 fprintf(stderr, "getaddrinfo() failed: %d\n", rv); 624#else 625 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 626#endif 627 break; 628 } 629 for(p = servinfo; p; p = p->ai_next) { 630 n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen); 631 if (n < 0) { 632#ifdef DEBUG 633 char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; 634 if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf, 635 sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { 636 fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf); 637 } 638#endif 639 PRINT_SOCKET_ERROR("sendto"); 640 continue; 641 } 642 } 643 freeaddrinfo(servinfo); 644 if(n < 0) { 645 if(error) 646 *error = UPNPDISCOVER_SOCKET_ERROR; 647 break; 648 } 649#endif /* #ifdef NO_GETADDRINFO */ 650 /* Waiting for SSDP REPLY packet to M-SEARCH */ 651 do { 652 n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id); 653 if (n < 0) { 654 /* error */ 655 if(error) 656 *error = UPNPDISCOVER_SOCKET_ERROR; 657 goto error; 658 } else if (n == 0) { 659 /* no data or Time Out */ 660 if (devlist) { 661 /* found some devices, stop now*/ 662 if(error) 663 *error = UPNPDISCOVER_SUCCESS; 664 goto error; 665 } 666 if(ipv6) { 667 /* switch linklocal flag */ 668 if(linklocal) { 669 linklocal = 0; 670 --deviceIndex; 671 } else { 672 linklocal = 1; 673 } 674 } 675 } else { 676 const char * descURL=NULL; 677 int urlsize=0; 678 const char * st=NULL; 679 int stsize=0; 680 parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize); 681 if(st&&descURL) { 682#ifdef DEBUG 683 printf("M-SEARCH Reply:\n ST: %.*s\n Location: %.*s\n", 684 stsize, st, urlsize, descURL); 685#endif 686 for(tmp=devlist; tmp; tmp = tmp->pNext) { 687 if(memcmp(tmp->descURL, descURL, urlsize) == 0 && 688 tmp->descURL[urlsize] == '\0' && 689 memcmp(tmp->st, st, stsize) == 0 && 690 tmp->st[stsize] == '\0') 691 break; 692 } 693 /* at the exit of the loop above, tmp is null if 694 * no duplicate device was found */ 695 if(tmp) 696 continue; 697 tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize); 698 if(!tmp) { 699 /* memory allocation error */ 700 if(error) 701 *error = UPNPDISCOVER_MEMORY_ERROR; 702 goto error; 703 } 704 tmp->pNext = devlist; 705 tmp->descURL = tmp->buffer; 706 tmp->st = tmp->buffer + 1 + urlsize; 707 memcpy(tmp->buffer, descURL, urlsize); 708 tmp->buffer[urlsize] = '\0'; 709 memcpy(tmp->buffer + urlsize + 1, st, stsize); 710 tmp->buffer[urlsize+1+stsize] = '\0'; 711 tmp->scope_id = scope_id; 712 devlist = tmp; 713 } 714 } 715 } while(n > 0); 716 } 717error: 718 closesocket(sudp); 719 return devlist; 720} 721 722/* upnpDiscover() Discover IGD device */ 723MINIUPNP_LIBSPEC struct UPNPDev * 724upnpDiscover(int delay, const char * multicastif, 725 const char * minissdpdsock, int sameport, 726 int ipv6, 727 int * error) 728{ 729 static const char * const deviceList[] = { 730#if 0 731 "urn:schemas-upnp-org:device:InternetGatewayDevice:2", 732 "urn:schemas-upnp-org:service:WANIPConnection:2", 733#endif 734 "urn:schemas-upnp-org:device:InternetGatewayDevice:1", 735 //"urn:schemas-upnp-org:service:WANIPConnection:1", 736 //"urn:schemas-upnp-org:service:WANPPPConnection:1", 737 "upnp:rootdevice", 738 /*"ssdp:all",*/ 739 0 740 }; 741 return upnpDiscoverDevices(deviceList, 742 delay, multicastif, minissdpdsock, sameport, 743 ipv6, error); 744} 745 746/* upnpDiscoverAll() Discover all UPnP devices */ 747MINIUPNP_LIBSPEC struct UPNPDev * 748upnpDiscoverAll(int delay, const char * multicastif, 749 const char * minissdpdsock, int sameport, 750 int ipv6, 751 int * error) 752{ 753 static const char * const deviceList[] = { 754 /*"upnp:rootdevice",*/ 755 "ssdp:all", 756 0 757 }; 758 return upnpDiscoverDevices(deviceList, 759 delay, multicastif, minissdpdsock, sameport, 760 ipv6, error); 761} 762 763/* upnpDiscoverDevice() Discover a specific device */ 764MINIUPNP_LIBSPEC struct UPNPDev * 765upnpDiscoverDevice(const char * device, int delay, const char * multicastif, 766 const char * minissdpdsock, int sameport, 767 int ipv6, 768 int * error) 769{ 770 const char * const deviceList[] = { 771 device, 772 0 773 }; 774 return upnpDiscoverDevices(deviceList, 775 delay, multicastif, minissdpdsock, sameport, 776 ipv6, error); 777} 778 779/* freeUPNPDevlist() should be used to 780 * free the chained list returned by upnpDiscover() */ 781MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist) 782{ 783 struct UPNPDev * next; 784 while(devlist) 785 { 786 next = devlist->pNext; 787 free(devlist); 788 devlist = next; 789 } 790} 791 792static char * 793build_absolute_url(const char * baseurl, const char * descURL, 794 const char * url, unsigned int scope_id) 795{ 796 int l, n; 797 char * s; 798 const char * base; 799 char * p; 800#if defined(IF_NAMESIZE) && !defined(_WIN32) 801 char ifname[IF_NAMESIZE]; 802#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */ 803 char scope_str[8]; 804#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */ 805 806 if( (url[0] == 'h') 807 &&(url[1] == 't') 808 &&(url[2] == 't') 809 &&(url[3] == 'p') 810 &&(url[4] == ':') 811 &&(url[5] == '/') 812 &&(url[6] == '/')) 813 return strdup(url); 814 base = (baseurl[0] == '\0') ? descURL : baseurl; 815 n = strlen(base); 816 if(n > 7) { 817 p = strchr(base + 7, '/'); 818 if(p) 819 n = p - base; 820 } 821 l = n + strlen(url) + 1; 822 if(url[0] != '/') 823 l++; 824 if(scope_id != 0) { 825#if defined(IF_NAMESIZE) && !defined(_WIN32) 826 if(if_indextoname(scope_id, ifname)) { 827 l += 3 + strlen(ifname); /* 3 == strlen(%25) */ 828 } 829#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */ 830 /* under windows, scope is numerical */ 831 l += 3 + snprintf(scope_str, sizeof(scope_str), "%u", scope_id); 832#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */ 833 } 834 s = malloc(l); 835 if(s == NULL) return NULL; 836 memcpy(s, base, n); 837 if(scope_id != 0) { 838 s[n] = '\0'; 839 if(0 == memcmp(s, "http://[fe80:", 13)) { 840 /* this is a linklocal IPv6 address */ 841 p = strchr(s, ']'); 842 if(p) { 843 /* insert %25<scope> into URL */ 844#ifdef IF_NAMESIZE 845 memmove(p + 3 + strlen(ifname), p, strlen(p) + 1); 846 memcpy(p, "%25", 3); 847 memcpy(p + 3, ifname, strlen(ifname)); 848 n += 3 + strlen(ifname); 849#else 850 memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1); 851 memcpy(p, "%25", 3); 852 memcpy(p + 3, scope_str, strlen(scope_str)); 853 n += 3 + strlen(scope_str); 854#endif 855 } 856 } 857 } 858 if(url[0] != '/') 859 s[n++] = '/'; 860 memcpy(s + n, url, l - n); 861 return s; 862} 863 864/* Prepare the Urls for usage... 865 */ 866MINIUPNP_LIBSPEC void 867GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data, 868 const char * descURL, unsigned int scope_id) 869{ 870 /* strdup descURL */ 871 urls->rootdescURL = strdup(descURL); 872 873 /* get description of WANIPConnection */ 874 urls->ipcondescURL = build_absolute_url(data->urlbase, descURL, 875 data->first.scpdurl, scope_id); 876 urls->controlURL = build_absolute_url(data->urlbase, descURL, 877 data->first.controlurl, scope_id); 878 urls->controlURL_CIF = build_absolute_url(data->urlbase, descURL, 879 data->CIF.controlurl, scope_id); 880 urls->controlURL_6FC = build_absolute_url(data->urlbase, descURL, 881 data->IPv6FC.controlurl, scope_id); 882 883#ifdef DEBUG 884 printf("urls->ipcondescURL='%s'\n", urls->ipcondescURL); 885 printf("urls->controlURL='%s'\n", urls->controlURL); 886 printf("urls->controlURL_CIF='%s'\n", urls->controlURL_CIF); 887 printf("urls->controlURL_6FC='%s'\n", urls->controlURL_6FC); 888#endif 889} 890 891MINIUPNP_LIBSPEC void 892FreeUPNPUrls(struct UPNPUrls * urls) 893{ 894 if(!urls) 895 return; 896 free(urls->controlURL); 897 urls->controlURL = 0; 898 free(urls->ipcondescURL); 899 urls->ipcondescURL = 0; 900 free(urls->controlURL_CIF); 901 urls->controlURL_CIF = 0; 902 free(urls->controlURL_6FC); 903 urls->controlURL_6FC = 0; 904 free(urls->rootdescURL); 905 urls->rootdescURL = 0; 906} 907 908int 909UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data) 910{ 911 char status[64]; 912 unsigned int uptime; 913 status[0] = '\0'; 914 UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, 915 status, &uptime, NULL); 916 if(0 == strcmp("Connected", status)) 917 { 918 return 1; 919 } 920 else 921 return 0; 922} 923 924void parsedescxml(char *msg, char *friendly_name, char *icon_url) 925{ 926 char line[200], *body, *p, *mxend; 927 char tmp[200]; 928 int i, j; 929 int s_num = 0; 930 int type = 0; 931 char *head, *end; 932 char *opts[] = {"<friendlyName>","<manufacturer>", "<presentationURL>", 933 "<modelDescription>", "<modelName>", "<modelNumber>", 934 "<serviceType>", "<SCPDURL>", "<icon>" 935 }; 936 937 char *icon_desc_end, *url_ptr; 938 int get_icon_url = 0; 939 940 /* pointer to the head of msg */ 941 p = strstr(msg, "<?xml"); 942 /* pointer to the end of msg */ 943 body = strstr(msg, "</root>"); 944 945 while( p!= NULL && p < body) 946 { 947 /* get rid of 'TAB' or 'Space' in the start of a line. */ 948 while((*p == '\r' || *p == '\n' || *p == '\t' || *p == ' ') && p < body) 949 p ++; 950 951 /* get a line. */ 952 i = 0; 953 while(*p != '>' && p < body) 954 { 955 if(i<199) 956 line[i++] = *p++; 957 else 958 *p++; 959 } 960 if(p == body) 961 { 962 break; 963 } 964 965 line[i++] = *p++; 966 line[i] ='\0'; 967 968 if(p == body) 969 break; 970 971 /* judge whether this line is useful. */ 972 for(type = 0; type< sizeof(opts)/sizeof(*opts); type++) 973 if(strncmp(line, opts[type], strlen(opts[type])) == 0) 974 break; 975 976 if(type == sizeof(opts)/sizeof(*opts)) 977 continue; 978 979 980 /* get the information. 981 * eg. <manufacturer> information </manufacturer> 982 */ 983 984 if((type == 8) && (!get_icon_url)) { 985 icon_desc_end = strstr(p, "</icon>"); 986 987 i = 0; 988 while(p < icon_desc_end) { 989 if(i<199) 990 line[i++] = *p++; 991 else 992 *p++; 993 } 994 line[i++] = *p++; 995 line[i] ='\0'; 996 p = icon_desc_end + 7; 997 } 998 else { 999 1000 i = 0; 1001 while(*p != '>' && p < body) 1002 { 1003 if(i<199) 1004 line[i++] = *p++; 1005 else 1006 *p++; 1007 } 1008 line[i++] = *p++; 1009 line[i] ='\0'; 1010 for(j =0; line[j] != '<'; j++) 1011 tmp[j] = line[j]; 1012 tmp[j] = '\0'; 1013 } 1014 1015 switch(type) 1016 { 1017 case 0: 1018#ifdef DEBUG 1019 printf( "friendlyname = %s\n", tmp); 1020#endif 1021 if(strstr(tmp,"WPS Router") || strstr(tmp,"Device")) 1022 break; 1023 1024 if( (end = strchr(tmp, '(')) != NULL ) 1025 { 1026 *end = '\0'; 1027 strcpy(friendly_name, tmp); 1028 } 1029 else if( (end = strchr(tmp, ':')) != NULL ) 1030 { 1031 *end = '\0'; 1032 strcpy(friendly_name, tmp); 1033 } 1034 else if( (head = strchr(tmp,'['))!=NULL && (end = strchr(tmp,']'))!=NULL ) 1035 { 1036 if( head < end ) 1037 { 1038 *end = '\0'; 1039 strcpy(friendly_name, head+1); 1040 } 1041 } 1042 else 1043 { 1044 if(tmp!=NULL) 1045 strcpy(friendly_name, tmp); 1046 } 1047 break; 1048#ifdef DEBUG 1049 case 1: 1050 printf("manufacturer = %s\n", tmp); 1051 break; 1052 case 2: 1053 printf("presentation = %s\n", tmp); 1054 break; 1055 case 3: 1056 printf("description = %s\n", tmp); 1057 1058 break; 1059 case 4: 1060 printf("modelname = %s\n", tmp); 1061 break; 1062 case 5: 1063 printf("modelnumber = %s\n", tmp); 1064 break; 1065#endif 1066 case 6: /* tmp="urn:schemas-upnp-org:service:serviceType:v" */ 1067 mxend = tmp; 1068 i = 0; j = 0; 1069 while(i != 4) 1070 { 1071 if(i == 3) 1072 tmp[j++] = *mxend; 1073 if(*mxend == ':') 1074 i++; 1075 mxend++; 1076 } 1077 tmp[j-1] = '\0'; 1078#ifdef DEBUG 1079 printf("service name = %s\n", tmp); 1080#endif 1081 break; 1082 case 7: 1083#ifdef DEBUG 1084 printf("service url = %s\n", tmp); 1085#endif 1086 break; 1087 case 8: 1088 if(strstr(line, "jpeg")||strstr(line, "png")) { 1089 if( url_ptr = strstr(line,"<url>")) { 1090 url_ptr = url_ptr + 5; 1091 i = 0; 1092 while(*url_ptr != '<') 1093 tmp[i++] = *url_ptr++; 1094 tmp[i] = '\0'; 1095 strcpy(icon_url, tmp); 1096#ifdef DEBUG 1097 printf("icon url =%s\n", tmp); 1098#endif 1099 get_icon_url = 1; 1100 } 1101 } 1102 break; 1103 } 1104 } 1105 1106} 1107 1108char * 1109get_lan_ipaddr() 1110{ 1111 int s; 1112 struct ifreq ifr; 1113 struct sockaddr_in *inaddr; 1114 struct in_addr ip_addr; 1115 1116 /* Retrieve IP info */ 1117 if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) 1118#if 0 1119 return strdup("0.0.0.0"); 1120#else 1121 { 1122 memset(&ip_addr, 0x0, sizeof(ip_addr)); 1123 return inet_ntoa(ip_addr); 1124 } 1125#endif 1126 1127 strncpy(ifr.ifr_name, "br0", IFNAMSIZ); 1128 inaddr = (struct sockaddr_in *)&ifr.ifr_addr; 1129 inet_aton("0.0.0.0", &inaddr->sin_addr); 1130 1131 /* Get IP address */ 1132 ioctl(s, SIOCGIFADDR, &ifr); 1133 close(s); 1134 1135 ip_addr = ((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr; 1136 return inet_ntoa(ip_addr); 1137} 1138 1139/* UPNP_GetValidIGDe) : 1140 * return values : 1141 * -1 = Internal error 1142 * 0 = NO IGD found 1143 * 1 = A valid connected IGD has been found 1144 * 2 = A valid IGD has been found but it reported as 1145 * not connected 1146 * 3 = an UPnP device has been found but was not recognized as an IGD 1147 * 1148 * In any positive non zero return case, the urls and data structures 1149 * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to 1150 * free allocated memory. 1151 */ 1152MINIUPNP_LIBSPEC int 1153UPNP_GetValidIGD(struct UPNPDev * devlist, 1154 struct UPNPUrls * urls, 1155 struct IGDdatas * data, 1156 char * lanaddr, int lanaddrlen) 1157{ 1158 struct xml_desc { 1159 char * xml; 1160 int size; 1161 int is_igd; 1162 } * desc = NULL; 1163 struct UPNPDev * dev; 1164 int ndev = 0; 1165 int i; 1166 int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ 1167 int n_igd = 0; 1168 char extIpAddr[16]; 1169 struct UPNPDevInfo IGDInfo; 1170 char *dut_lanaddr; 1171 char IGDDescURL[256]; 1172 1173 if(!devlist) 1174 { 1175#ifdef DEBUG 1176 printf("Empty devlist\n"); 1177#endif 1178 return 0; 1179 } 1180 /* counting total number of devices in the list */ 1181 for(dev = devlist; dev; dev = dev->pNext) 1182 ndev++; 1183 if(ndev > 0) 1184 { 1185 desc = calloc(ndev, sizeof(struct xml_desc)); 1186 if(!desc) 1187 return -1; /* memory allocation error */ 1188 } 1189 1190 dut_lanaddr = get_lan_ipaddr(); 1191 1192 /* Step 1 : downloading descriptions and testing type */ 1193 for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) 1194 { 1195 memset(&IGDInfo, 0, sizeof(struct UPNPDevInfo)); 1196 /* we should choose an internet gateway device. 1197 * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */ 1198 strcpy(IGDDescURL, dev->descURL); 1199 desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size), 1200 lanaddr, lanaddrlen, 1201 dev->scope_id, &IGDInfo, dut_lanaddr); 1202 1203#ifdef DEBUG 1204 if(!desc[i].xml) 1205 { 1206 printf("error getting XML description %s\n", dev->descURL); 1207 } 1208#endif 1209 if(desc[i].xml) 1210 { 1211 memset(data, 0, sizeof(struct IGDdatas)); 1212 memset(urls, 0, sizeof(struct UPNPUrls)); 1213 /* parserootdesc(desc[i].xml, desc[i].size, data); */ 1214 1215#ifdef DEBUG 1216 FILE *xml_fd; 1217 xml_fd = fopen("/tmp/upnpc_xml.log", "a"); 1218 fprintf(xml_fd, "============= XML ==============\n"); 1219 fprintf(xml_fd, "%s\n", desc[i].xml); 1220 parsedescxml(desc[i].xml, &IGDInfo.friendlyName, &IGDInfo.iconUrl); 1221 fprintf(xml_fd, " HostName: %s\n", IGDInfo.hostname); 1222 fprintf(xml_fd, " type: %s\n", IGDInfo.type); 1223 fprintf(xml_fd, " F Name: %s\n", IGDInfo.friendlyName); 1224 fprintf(xml_fd, " Icon URL: %s\n", IGDInfo.iconUrl); 1225 fprintf(xml_fd, "================================\n\n"); 1226 syslog(LOG_NOTICE, "parse icon url: %s", IGDInfo.iconUrl); 1227#endif 1228 1229 strcpy(dev->DevInfo.hostname, IGDInfo.hostname); 1230 strcpy(dev->DevInfo.type, IGDInfo.type); 1231 strcpy(dev->DevInfo.friendlyName, IGDInfo.friendlyName); 1232 strcpy(dev->DevInfo.iconUrl, IGDInfo.iconUrl); 1233 1234#ifdef RTCONFIG_JFFS2USERICON 1235 if(strcmp(IGDInfo.iconUrl, "") != NULL) { 1236 char realIconUrl[158], iconFile[32], iconBuf[512]; 1237 char *ico_head, *ico_end; 1238 char *icon, *p, *q; 1239 int iconSize, i = 0, iconCheck = 0; 1240 FILE *ico_fd; 1241 1242 memset(realIconUrl, 0, 158); 1243 if(strstr(IGDInfo.iconUrl, "http://")) { 1244 strcpy(realIconUrl, IGDInfo.iconUrl); 1245 } 1246 else { 1247 q = IGDDescURL; 1248 while(q = strchr(q, '/')) { 1249 i++; 1250 if(i == 3) { 1251 p = IGDDescURL; 1252 i = 0; 1253 while ( p < q ) { 1254 realIconUrl[i++] = *p++; 1255 } 1256 strcat(realIconUrl, IGDInfo.iconUrl); 1257 #ifdef DEBUG 1258 printf("\n*** Real URL=%s=\n\n", realIconUrl); 1259 #endif 1260 break; 1261 } 1262 q++; 1263 } 1264 } 1265 get_icon: 1266#ifdef DEBUG 1267 syslog(LOG_NOTICE, "Real icon url: %s", realIconUrl); 1268 fprintf(xml_fd, "Real icon url: %s\n", realIconUrl); 1269#endif 1270 sprintf(iconFile, "/tmp/upnpicon/%s.ico", IGDInfo.hostname); 1271 1272 icon = miniwget_getaddr(realIconUrl, &iconSize, 1273 lanaddr, lanaddrlen, 1274 0, &IGDInfo, dut_lanaddr); 1275 1276 if( iconSize > 512 ) { 1277 ico_fd = fopen(iconFile, "w"); 1278 if(ico_fd) { 1279 fwrite(icon, sizeof(char), iconSize, ico_fd); 1280 fclose(ico_fd); 1281 } 1282 } 1283 else if(iconSize > 0) { 1284 ico_head = strstr(icon, "<a href="); 1285 if(ico_head) { 1286 ico_head = ico_head+9; 1287 ico_end = strstr(icon, "\">"); 1288 if(ico_end) { 1289 *ico_end = '\0'; 1290 strcpy(realIconUrl, ico_head); 1291 goto get_icon; 1292 } 1293 } 1294 } 1295 } 1296#endif 1297 1298 if(COMPARE(data->CIF.servicetype, 1299 "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) 1300 { 1301 desc[i].is_igd = 1; 1302 n_igd++; 1303 } 1304#ifdef DEBUG 1305 fclose(xml_fd); 1306#endif 1307 } 1308 else 1309 memset(dev->DevInfo.hostname, 0, 65); 1310 } 1311 1312 /* iterate the list to find a device depending on state */ 1313 for(state = 1; state <= 3; state++) 1314 /*if(0)*/ 1315 { 1316 for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) 1317 { 1318 if(desc[i].xml) 1319 { 1320 memset(data, 0, sizeof(struct IGDdatas)); 1321 memset(urls, 0, sizeof(struct UPNPUrls)); 1322 parserootdesc(desc[i].xml, desc[i].size, data); 1323 if(desc[i].is_igd || state >= 3 ) 1324 { 1325 GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); 1326 1327 /* in state 2 and 3 we dont test if device is connected ! */ 1328 if(state >= 2) 1329 goto free_and_return; 1330#ifdef DEBUG 1331 printf("UPNPIGD_IsConnected(%s) = %d\n", 1332 urls->controlURL, 1333 UPNPIGD_IsConnected(urls, data)); 1334#endif 1335 /* checks that status is connected AND there is a external IP address assigned */ 1336 if(UPNPIGD_IsConnected(urls, data) 1337 && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) 1338 goto free_and_return; 1339 FreeUPNPUrls(urls); 1340 if(data->second.servicetype[0] != '\0') { 1341#ifdef DEBUG 1342 printf("We tried %s, now we try %s !\n", 1343 data->first.servicetype, data->second.servicetype); 1344#endif 1345 /* swaping WANPPPConnection and WANIPConnection ! */ 1346 memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service)); 1347 memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service)); 1348 memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service)); 1349 GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); 1350#ifdef DEBUG 1351 printf("UPNPIGD_IsConnected(%s) = %d\n", 1352 urls->controlURL, 1353 UPNPIGD_IsConnected(urls, data)); 1354#endif 1355 if(UPNPIGD_IsConnected(urls, data) 1356 && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) 1357 goto free_and_return; 1358 FreeUPNPUrls(urls); 1359 } 1360 } 1361 memset(data, 0, sizeof(struct IGDdatas)); 1362 } 1363 } 1364 } 1365 state = 0; 1366free_and_return: 1367 if(desc) { 1368 for(i = 0; i < ndev; i++) { 1369 if(desc[i].xml) { 1370 free(desc[i].xml); 1371 } 1372 } 1373 free(desc); 1374 } 1375 return state; 1376} 1377 1378/* UPNP_GetIGDFromUrl() 1379 * Used when skipping the discovery process. 1380 * return value : 1381 * 0 - Not ok 1382 * 1 - OK */ 1383int 1384UPNP_GetIGDFromUrl(const char * rootdescurl, 1385 struct UPNPUrls * urls, 1386 struct IGDdatas * data, 1387 char * lanaddr, int lanaddrlen) 1388{ 1389 char * descXML; 1390 int descXMLsize = 0; 1391 1392 descXML = miniwget_getaddr(rootdescurl, &descXMLsize, 1393 lanaddr, lanaddrlen, 0, NULL, NULL); 1394 if(descXML) { 1395 memset(data, 0, sizeof(struct IGDdatas)); 1396 memset(urls, 0, sizeof(struct UPNPUrls)); 1397 parserootdesc(descXML, descXMLsize, data); 1398 free(descXML); 1399 descXML = NULL; 1400 GetUPNPUrls(urls, data, rootdescurl, 0); 1401 return 1; 1402 } else { 1403 return 0; 1404 } 1405} 1406 1407