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