File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / miniupnpc / miniupnpc.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:16:22 2012 UTC (12 years, 8 months ago) by misho
Branches: miniupnpc, elwix, MAIN
CVS tags: v1_6, HEAD
miniupnpc

    1: /* $Id: miniupnpc.c,v 1.1.1.1 2012/02/21 23:16:22 misho 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>