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