File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / miniupnpd / minissdp.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:55:57 2012 UTC (12 years, 2 months ago) by misho
Branches: miniupnpd, elwix, MAIN
CVS tags: v1_6elwix, HEAD
miniupnpd 1.6+patches

    1: /* $Id: minissdp.c,v 1.1.1.2 2012/05/29 12:55:57 misho Exp $ */
    2: /* MiniUPnP project
    3:  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
    4:  * (c) 2006-2011 Thomas Bernard
    5:  * This software is subject to the conditions detailed
    6:  * in the LICENCE file provided within the distribution */
    7: 
    8: #include <stdio.h>
    9: #include <string.h>
   10: #include <unistd.h>
   11: #include <sys/socket.h>
   12: #include <sys/un.h>
   13: #include <netinet/in.h>
   14: #include <arpa/inet.h>
   15: #include <syslog.h>
   16: #include "config.h"
   17: #include "upnpdescstrings.h"
   18: #include "miniupnpdpath.h"
   19: #include "upnphttp.h"
   20: #include "upnpglobalvars.h"
   21: #include "minissdp.h"
   22: #include "upnputils.h"
   23: #include "codelength.h"
   24: 
   25: /* SSDP ip/port */
   26: #define SSDP_PORT (1900)
   27: #define SSDP_MCAST_ADDR ("239.255.255.250")
   28: #define LL_SSDP_MCAST_ADDR ("FF02::C")
   29: #define SL_SSDP_MCAST_ADDR ("FF05::C")
   30: 
   31: /* AddMulticastMembership()
   32:  * param s		socket
   33:  * param ifaddr	ip v4 address
   34:  */
   35: static int
   36: AddMulticastMembership(int s, in_addr_t ifaddr)
   37: {
   38: 	struct ip_mreq imr;	/* Ip multicast membership */
   39: 
   40:     /* setting up imr structure */
   41:     imr.imr_multiaddr.s_addr = inet_addr(SSDP_MCAST_ADDR);
   42:     /*imr.imr_interface.s_addr = htonl(INADDR_ANY);*/
   43:     imr.imr_interface.s_addr = ifaddr;	/*inet_addr(ifaddr);*/
   44: 	
   45: 	if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&imr, sizeof(struct ip_mreq)) < 0)
   46: 	{
   47:         syslog(LOG_ERR, "setsockopt(udp, IP_ADD_MEMBERSHIP): %m");
   48: 		return -1;
   49:     }
   50: 
   51: 	return 0;
   52: }
   53: 
   54: /* AddMulticastMembershipIPv6()
   55:  * param s	socket (IPv6)
   56:  * To be improved to target specific network interfaces */
   57: #ifdef ENABLE_IPV6
   58: static int
   59: AddMulticastMembershipIPv6(int s)
   60: {
   61: 	struct ipv6_mreq mr;
   62: 	/*unsigned int ifindex;*/
   63: 
   64: 	memset(&mr, 0, sizeof(mr));
   65: 	inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
   66: 	/*mr.ipv6mr_interface = ifindex;*/
   67: 	mr.ipv6mr_interface = 0; /* 0 : all interfaces */
   68: #ifndef IPV6_ADD_MEMBERSHIP
   69: #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
   70: #endif
   71: 	if(setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mr, sizeof(struct ipv6_mreq)) < 0)
   72: 	{
   73: 		syslog(LOG_ERR, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
   74: 		return -1;
   75: 	}
   76: 	inet_pton(AF_INET6, SL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
   77: 	if(setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mr, sizeof(struct ipv6_mreq)) < 0)
   78: 	{
   79: 		syslog(LOG_ERR, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
   80: 		return -1;
   81: 	}
   82: 	return 0;
   83: }
   84: #endif
   85: 
   86: /* Open and configure the socket listening for 
   87:  * SSDP udp packets sent on 239.255.255.250 port 1900
   88:  * SSDP v6 udp packets sent on FF02::C, or FF05::C, port 1900 */
   89: int
   90: OpenAndConfSSDPReceiveSocket(int ipv6)
   91: {
   92: 	int s;
   93: 	struct sockaddr_storage sockname;
   94: 	socklen_t sockname_len;
   95: 	struct lan_addr_s * lan_addr;
   96: 	int j = 1;
   97: 
   98: 	if( (s = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0)) < 0)
   99: 	{
  100: 		syslog(LOG_ERR, "socket(udp): %m");
  101: 		return -1;
  102: 	}
  103: 
  104: 	memset(&sockname, 0, sizeof(struct sockaddr_storage));
  105: 	if(ipv6) {
  106: 		struct sockaddr_in6 * saddr = (struct sockaddr_in6 *)&sockname;
  107: 		saddr->sin6_family = AF_INET6;
  108: 		saddr->sin6_port = htons(SSDP_PORT);
  109: 		saddr->sin6_addr = in6addr_any;
  110: 		sockname_len = sizeof(struct sockaddr_in6);
  111: 	} else {
  112: 		struct sockaddr_in * saddr = (struct sockaddr_in *)&sockname;
  113: 		saddr->sin_family = AF_INET;
  114: 		saddr->sin_port = htons(SSDP_PORT);
  115: 		/* NOTE : it seems it doesnt work when binding on the specific address */
  116: 		/*saddr->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);*/
  117: 		saddr->sin_addr.s_addr = htonl(INADDR_ANY);
  118: 		/*saddr->sin_addr.s_addr = inet_addr(ifaddr);*/
  119: 		sockname_len = sizeof(struct sockaddr_in);
  120: 	}
  121: 
  122: 	if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &j, sizeof(j)) < 0)
  123: 	{
  124: 		syslog(LOG_WARNING, "setsockopt(udp, SO_REUSEADDR): %m");
  125: 	}
  126: 
  127: 
  128: 	if(bind(s, (struct sockaddr *)&sockname, sockname_len) < 0)
  129: 	{
  130: 		syslog(LOG_ERR, "bind(udp%s): %m", ipv6 ? "6" : "");
  131: 		close(s);
  132: 		return -1;
  133: 	}
  134: 
  135: #ifdef ENABLE_IPV6
  136: 	if(ipv6)
  137: 	{
  138: 		AddMulticastMembershipIPv6(s);
  139: 	}
  140: 	else
  141: #endif
  142: 	{
  143: 		for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
  144: 		{
  145: 			if(AddMulticastMembership(s, lan_addr->addr.s_addr) < 0)
  146: 			{
  147: 				syslog(LOG_WARNING,
  148: 				       "Failed to add multicast membership for interface %s", 
  149: 				       lan_addr->str);
  150: 			}
  151: 		}
  152: 	}
  153: 
  154: 	return s;
  155: }
  156: 
  157: /* open the UDP socket used to send SSDP notifications to
  158:  * the multicast group reserved for them */
  159: static int
  160: OpenAndConfSSDPNotifySocket(in_addr_t addr)
  161: {
  162: 	int s;
  163: 	unsigned char loopchar = 0;
  164: 	int bcast = 1;
  165: 	struct in_addr mc_if;
  166: 	struct sockaddr_in sockname;
  167: 	
  168: 	if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
  169: 	{
  170: 		syslog(LOG_ERR, "socket(udp_notify): %m");
  171: 		return -1;
  172: 	}
  173: 
  174: 	mc_if.s_addr = addr;	/*inet_addr(addr);*/
  175: 
  176: 	if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopchar, sizeof(loopchar)) < 0)
  177: 	{
  178: 		syslog(LOG_ERR, "setsockopt(udp_notify, IP_MULTICAST_LOOP): %m");
  179: 		close(s);
  180: 		return -1;
  181: 	}
  182: 
  183: 	if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char *)&mc_if, sizeof(mc_if)) < 0)
  184: 	{
  185: 		syslog(LOG_ERR, "setsockopt(udp_notify, IP_MULTICAST_IF): %m");
  186: 		close(s);
  187: 		return -1;
  188: 	}
  189: 	
  190: 	if(setsockopt(s, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast)) < 0)
  191: 	{
  192: 		syslog(LOG_ERR, "setsockopt(udp_notify, SO_BROADCAST): %m");
  193: 		close(s);
  194: 		return -1;
  195: 	}
  196: 
  197: 	memset(&sockname, 0, sizeof(struct sockaddr_in));
  198:     sockname.sin_family = AF_INET;
  199:     sockname.sin_addr.s_addr = addr;	/*inet_addr(addr);*/
  200: 
  201:     if (bind(s, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in)) < 0)
  202: 	{
  203: 		syslog(LOG_ERR, "bind(udp_notify): %m");
  204: 		close(s);
  205: 		return -1;
  206:     }
  207: 
  208: 	return s;
  209: }
  210: 
  211: int
  212: OpenAndConfSSDPNotifySockets(int * sockets)
  213: /*OpenAndConfSSDPNotifySockets(int * sockets,
  214:                              struct lan_addr_s * lan_addr, int n_lan_addr)*/
  215: {
  216: 	int i, j;
  217: 	struct lan_addr_s * lan_addr;
  218: 
  219: 	for(i=0, lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next, i++)
  220: 	{
  221: 		sockets[i] = OpenAndConfSSDPNotifySocket(lan_addr->addr.s_addr);
  222: 		if(sockets[i] < 0)
  223: 		{
  224: 			for(j=0; j<i; j++)
  225: 			{
  226: 				close(sockets[j]);
  227: 				sockets[j] = -1;
  228: 			}
  229: 			return -1;
  230: 		}
  231: 	}
  232: 	return 0;
  233: }
  234: 
  235: /*
  236:  * response from a LiveBox (Wanadoo)
  237: HTTP/1.1 200 OK
  238: CACHE-CONTROL: max-age=1800
  239: DATE: Thu, 01 Jan 1970 04:03:23 GMT
  240: EXT:
  241: LOCATION: http://192.168.0.1:49152/gatedesc.xml
  242: SERVER: Linux/2.4.17, UPnP/1.0, Intel SDK for UPnP devices /1.2
  243: ST: upnp:rootdevice
  244: USN: uuid:75802409-bccb-40e7-8e6c-fa095ecce13e::upnp:rootdevice
  245: 
  246:  * response from a Linksys 802.11b :
  247: HTTP/1.1 200 OK
  248: Cache-Control:max-age=120
  249: Location:http://192.168.5.1:5678/rootDesc.xml
  250: Server:NT/5.0 UPnP/1.0
  251: ST:upnp:rootdevice
  252: USN:uuid:upnp-InternetGatewayDevice-1_0-0090a2777777::upnp:rootdevice
  253: EXT:
  254:  */
  255: 
  256: /* not really an SSDP "announce" as it is the response
  257:  * to a SSDP "M-SEARCH" */
  258: static void
  259: SendSSDPAnnounce2(int s, const struct sockaddr * addr,
  260:                   const char * st, int st_len, const char * suffix,
  261:                   const char * host, unsigned short port)
  262: {
  263: 	int l, n;
  264: 	char buf[512];
  265: 	socklen_t addrlen;
  266: 	/* 
  267: 	 * follow guideline from document "UPnP Device Architecture 1.0"
  268: 	 * uppercase is recommended.
  269: 	 * DATE: is recommended
  270: 	 * SERVER: OS/ver UPnP/1.0 miniupnpd/1.0
  271: 	 * - check what to put in the 'Cache-Control' header 
  272: 	 *
  273: 	 * have a look at the document "UPnP Device Architecture v1.1 */
  274: 	l = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\n"
  275: 		"CACHE-CONTROL: max-age=120\r\n"
  276: 		/*"DATE: ...\r\n"*/
  277: 		"ST: %.*s%s\r\n"
  278: 		"USN: %s::%.*s%s\r\n"
  279: 		"EXT:\r\n"
  280: 		"SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
  281: 		"LOCATION: http://%s:%u" ROOTDESC_PATH "\r\n"
  282: 		"OPT: \"http://schemas.upnp.org/upnp/1/0/\";\r\n" /* UDA v1.1 */
  283: 		"01-NLS: %u\r\n" /* same as BOOTID. UDA v1.1 */
  284: 		"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
  285: 		"CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
  286: 		"\r\n",
  287: 		st_len, st, suffix,
  288: 		uuidvalue, st_len, st, suffix,
  289: 		host, (unsigned int)port,
  290: 		upnp_bootid, upnp_bootid, upnp_configid);
  291: 	addrlen = (addr->sa_family == AF_INET6)
  292: 	          ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
  293: 	n = sendto(s, buf, l, 0,
  294: 	           addr, addrlen);
  295: 	syslog(LOG_INFO, "SSDP Announce %d bytes to %s:%d ST: %.*s",n,
  296:        		inet_ntoa(((const struct sockaddr_in *)addr)->sin_addr),
  297:           	ntohs(((const struct sockaddr_in *)addr)->sin_port),
  298: 		l, buf);
  299: 	if(n < 0)
  300: 	{
  301: 		syslog(LOG_ERR, "sendto(udp): %m");
  302: 	}
  303: }
  304: 
  305: static const char * const known_service_types[] =
  306: {
  307: 	"upnp:rootdevice",
  308: 	"urn:schemas-upnp-org:device:InternetGatewayDevice:",
  309: 	"urn:schemas-upnp-org:device:WANConnectionDevice:",
  310: 	"urn:schemas-upnp-org:device:WANDevice:",
  311: 	"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:",
  312: 	"urn:schemas-upnp-org:service:WANIPConnection:",
  313: 	"urn:schemas-upnp-org:service:WANPPPConnection:",
  314: #ifdef ENABLE_L3F_SERVICE
  315: 	"urn:schemas-upnp-org:service:Layer3Forwarding:",
  316: #endif
  317: #ifdef ENABLE_6FC_SERVICE
  318: 	"url:schemas-upnp-org:service:WANIPv6FirewallControl:",
  319: #endif
  320: 	0
  321: };
  322: 
  323: static void
  324: SendSSDPNotifies(int s, const char * host, unsigned short port,
  325:                  unsigned int lifetime)
  326: {
  327: 	struct sockaddr_in sockname;
  328: 	int l, n, i=0;
  329: 	char bufr[512];
  330: 
  331: 	memset(&sockname, 0, sizeof(struct sockaddr_in));
  332: 	sockname.sin_family = AF_INET;
  333: 	sockname.sin_port = htons(SSDP_PORT);
  334: 	sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
  335: 
  336: 	while(known_service_types[i])
  337: 	{
  338: 		l = snprintf(bufr, sizeof(bufr), 
  339: 			"NOTIFY * HTTP/1.1\r\n"
  340: 			"HOST: %s:%d\r\n"
  341: 			"CACHE-CONTROL: max-age=%u\r\n"
  342: 			"lOCATION: http://%s:%d" ROOTDESC_PATH"\r\n"
  343: 			"SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
  344: 			"NT: %s%s\r\n"
  345: 			"USN: %s::%s%s\r\n"
  346: 			"NTS: ssdp:alive\r\n"
  347: 			"OPT: \"http://schemas.upnp.org/upnp/1/0/\";\r\n" /* UDA v1.1 */
  348: 			"01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */
  349: 			"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
  350: 			"CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
  351: 			"\r\n",
  352: 			SSDP_MCAST_ADDR, SSDP_PORT,
  353: 			lifetime,
  354: 			host, port,
  355: 			known_service_types[i], (i==0?"":"1"),
  356: 			uuidvalue, known_service_types[i], (i==0?"":"1"),
  357: 			upnp_bootid, upnp_bootid, upnp_configid );
  358: 		if(l>=sizeof(bufr))
  359: 		{
  360: 			syslog(LOG_WARNING, "SendSSDPNotifies(): truncated output");
  361: 			l = sizeof(bufr);
  362: 		}
  363: 		n = sendto(s, bufr, l, 0,
  364: 			(struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );
  365: 		if(n < 0)
  366: 		{
  367: 			syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s, host);
  368: 		}
  369: 		i++;
  370: 	}
  371: }
  372: 
  373: void
  374: SendSSDPNotifies2(int * sockets,
  375:                   unsigned short port,
  376:                   unsigned int lifetime)
  377: {
  378: 	int i;
  379: 	struct lan_addr_s * lan_addr;
  380: 	for(i=0, lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next, i++)
  381: 	{
  382: 		SendSSDPNotifies(sockets[i], lan_addr->str, port, lifetime);
  383: 	}
  384: }
  385: 
  386: /* ProcessSSDPRequest()
  387:  * process SSDP M-SEARCH requests and responds to them */
  388: void
  389: ProcessSSDPRequest(int s, unsigned short port)
  390: {
  391: 	int n;
  392: 	char bufr[1500];
  393: 	socklen_t len_r;
  394: #ifdef ENABLE_IPV6
  395: 	struct sockaddr_storage sendername;
  396: 	len_r = sizeof(struct sockaddr_storage);
  397: #else
  398: 	struct sockaddr_in sendername;
  399: 	len_r = sizeof(struct sockaddr_in);
  400: #endif
  401: 
  402: 	n = recvfrom(s, bufr, sizeof(bufr), 0,
  403: 	             (struct sockaddr *)&sendername, &len_r);
  404: 	if(n < 0)
  405: 	{
  406: 		syslog(LOG_ERR, "recvfrom(udp): %m");
  407: 		return;
  408: 	}
  409: 	ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername, port);
  410: 
  411: }
  412: 
  413: void
  414: ProcessSSDPData(int s, const char *bufr, int n,
  415:                 const struct sockaddr * sender, unsigned short port) {
  416: 	int i, l;
  417: 	struct lan_addr_s * lan_addr = NULL;
  418: 	const char * st = NULL;
  419: 	int st_len = 0;
  420: 	char sender_str[64];
  421: 	const char * announced_host = NULL;
  422: 
  423: 	/* get the string representation of the sender address */
  424: 	sockaddr_to_string(sender, sender_str, sizeof(sender_str));
  425: 
  426: 	if(memcmp(bufr, "NOTIFY", 6) == 0)
  427: 	{
  428: 		/* ignore NOTIFY packets. We could log the sender and device type */
  429: 		return;
  430: 	}
  431: 	else if(memcmp(bufr, "M-SEARCH", 8) == 0)
  432: 	{
  433: 		i = 0;
  434: 		while(i < n)
  435: 		{
  436: 			while((i < n - 1) && (bufr[i] != '\r' || bufr[i+1] != '\n'))
  437: 				i++;
  438: 			i += 2;
  439: 			if((i < n - 3) && (strncasecmp(bufr+i, "st:", 3) == 0))
  440: 			{
  441: 				st = bufr+i+3;
  442: 				st_len = 0;
  443: 				while((*st == ' ' || *st == '\t') && (st < bufr + n))
  444: 					st++;
  445: 				while(st[st_len]!='\r' && st[st_len]!='\n'
  446: 				     && (st + st_len < bufr + n))
  447: 					st_len++;
  448: 				/*syslog(LOG_INFO, "ST: %.*s", st_len, st);*/
  449: 				/*j = 0;*/
  450: 				/*while(bufr[i+j]!='\r') j++;*/
  451: 				/*syslog(LOG_INFO, "%.*s", j, bufr+i);*/
  452: 			}
  453: 		}
  454: 		/*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s",
  455: 	           sender_str );*/
  456: 		if(st && (st_len > 0))
  457: 		{
  458: 			/* TODO : doesnt answer at once but wait for a random time */
  459: 			syslog(LOG_INFO, "SSDP M-SEARCH from %s ST: %.*s",
  460: 			       sender_str, st_len, st);
  461: 			/* find in which sub network the client is */
  462: 			if(sender->sa_family == AF_INET)
  463: 			{
  464: 				for(lan_addr = lan_addrs.lh_first;
  465: 				    lan_addr != NULL;
  466: 				    lan_addr = lan_addr->list.le_next)
  467: 				{
  468: 					if( (((const struct sockaddr_in *)sender)->sin_addr.s_addr & lan_addr->mask.s_addr)
  469: 				   == (lan_addr->addr.s_addr & lan_addr->mask.s_addr))
  470: 						break;
  471: 				}
  472: 				if (lan_addr == NULL)
  473: 				{
  474: 					syslog(LOG_ERR, "Can't find in which sub network the client is");
  475: 					return;
  476: 				}
  477: 				announced_host = lan_addr->str;
  478: 			}
  479: #ifdef ENABLE_IPV6
  480: 			else
  481: 			{
  482: 				/* IPv6 address with brackets */
  483: 				announced_host = ipv6_addr_for_http_with_brackets;
  484: 			}
  485: #endif
  486: 			/* Responds to request with a device as ST header */
  487: 			for(i = 0; known_service_types[i]; i++)
  488: 			{
  489: 				l = (int)strlen(known_service_types[i]);
  490: 				if(l<=st_len && (0 == memcmp(st, known_service_types[i], l)))
  491: 				{
  492: 					syslog(LOG_INFO, "Single search found");
  493: 					SendSSDPAnnounce2(s, sender,
  494: 					                  st, st_len, "",
  495: 					                  announced_host, port);
  496: 					break;
  497: 				}
  498: 			}
  499: 			/* Responds to request with ST: ssdp:all */
  500: 			/* strlen("ssdp:all") == 8 */
  501: 			if(st_len==8 && (0 == memcmp(st, "ssdp:all", 8)))
  502: 			{
  503: 				syslog(LOG_INFO, "ssdp:all found");
  504: 				for(i=0; known_service_types[i]; i++)
  505: 				{
  506: 					l = (int)strlen(known_service_types[i]);
  507: 					SendSSDPAnnounce2(s, sender,
  508: 					                  known_service_types[i], l, i==0?"":"1",
  509: 					                  announced_host, port);
  510: 				}
  511: 			}
  512: 			/* responds to request by UUID value */
  513: 			l = (int)strlen(uuidvalue);
  514: 			if(l==st_len && (0 == memcmp(st, uuidvalue, l)))
  515: 			{
  516: 				syslog(LOG_INFO, "ssdp:uuid found");
  517: 				SendSSDPAnnounce2(s, sender, st, st_len, "",
  518: 				                  announced_host, port);
  519: 			}
  520: 		}
  521: 		else
  522: 		{
  523: 			syslog(LOG_INFO, "Invalid SSDP M-SEARCH from %s", sender_str);
  524: 		}
  525: 	}
  526: 	else
  527: 	{
  528: 		syslog(LOG_NOTICE, "Unknown udp packet received from %s", sender_str);
  529: 	}
  530: }
  531: 
  532: /* This will broadcast ssdp:byebye notifications to inform 
  533:  * the network that UPnP is going down. */
  534: int
  535: SendSSDPGoodbye(int * sockets, int n_sockets)
  536: {
  537: 	struct sockaddr_in sockname;
  538: 	int n, l;
  539: 	int i, j;
  540: 	char bufr[512];
  541: 
  542:     memset(&sockname, 0, sizeof(struct sockaddr_in));
  543:     sockname.sin_family = AF_INET;
  544:     sockname.sin_port = htons(SSDP_PORT);
  545:     sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
  546: 
  547: 	for(j=0; j<n_sockets; j++)
  548: 	{
  549: 	    for(i=0; known_service_types[i]; i++)
  550: 	    {
  551: 	        l = snprintf(bufr, sizeof(bufr),
  552:                  "NOTIFY * HTTP/1.1\r\n"
  553:                  "HOST: %s:%d\r\n"
  554:                  "NT: %s%s\r\n"
  555:                  "USN: %s::%s%s\r\n"
  556:                  "NTS: ssdp:byebye\r\n"
  557: 				 "OPT: \"http://schemas.upnp.org/upnp/1/0/\";\r\n" /* UDA v1.1 */
  558: 				 "01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */
  559: 				 "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
  560: 				 "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
  561:                  "\r\n",
  562:                  SSDP_MCAST_ADDR, SSDP_PORT,
  563: 				 known_service_types[i], (i==0?"":"1"),
  564:                  uuidvalue, known_service_types[i], (i==0?"":"1"),
  565:                  upnp_bootid, upnp_bootid, upnp_configid);
  566: 	        n = sendto(sockets[j], bufr, l, 0,
  567: 	                   (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );
  568: 			if(n < 0)
  569: 			{
  570: 				syslog(LOG_ERR, "SendSSDPGoodbye: sendto(udp_shutdown=%d): %m",
  571: 				       sockets[j]);
  572: 				return -1;
  573: 			}
  574:     	}
  575: 	}
  576: 	return 0;
  577: }
  578: 
  579: /* SubmitServicesToMiniSSDPD() :
  580:  * register services offered by MiniUPnPd to a running instance of
  581:  * MiniSSDPd */
  582: int
  583: SubmitServicesToMiniSSDPD(const char * host, unsigned short port) {
  584: 	struct sockaddr_un addr;
  585: 	int s;
  586: 	unsigned char buffer[2048];
  587: 	char strbuf[256];
  588: 	unsigned char * p;
  589: 	int i, l;
  590: 
  591: 	s = socket(AF_UNIX, SOCK_STREAM, 0);
  592: 	if(s < 0) {
  593: 		syslog(LOG_ERR, "socket(unix): %m");
  594: 		return -1;
  595: 	}
  596: 	addr.sun_family = AF_UNIX;
  597: 	strncpy(addr.sun_path, minissdpdsocketpath, sizeof(addr.sun_path));
  598: 	if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
  599: 		syslog(LOG_ERR, "connect(\"%s\"): %m", minissdpdsocketpath);
  600: 		return -1;
  601: 	}
  602: 	for(i = 0; known_service_types[i]; i++) {
  603: 		buffer[0] = 4;
  604: 		p = buffer + 1;
  605: 		l = (int)strlen(known_service_types[i]);
  606: 		if(i > 0)
  607: 			l++;
  608: 		CODELENGTH(l, p);
  609: 		memcpy(p, known_service_types[i], l);
  610: 		if(i > 0)
  611: 			p[l-1] = '1';
  612: 		p += l;
  613: 		l = snprintf(strbuf, sizeof(strbuf), "%s::%s%s", 
  614: 		             uuidvalue, known_service_types[i], (i==0)?"":"1");
  615: 		CODELENGTH(l, p);
  616: 		memcpy(p, strbuf, l);
  617: 		p += l;
  618: 		l = (int)strlen(MINIUPNPD_SERVER_STRING);
  619: 		CODELENGTH(l, p);
  620: 		memcpy(p, MINIUPNPD_SERVER_STRING, l);
  621: 		p += l;
  622: 		l = snprintf(strbuf, sizeof(strbuf), "http://%s:%u" ROOTDESC_PATH,
  623: 		             host, (unsigned int)port);
  624: 		CODELENGTH(l, p);
  625: 		memcpy(p, strbuf, l);
  626: 		p += l;
  627: 		if(write(s, buffer, p - buffer) < 0) {
  628: 			syslog(LOG_ERR, "write(): %m");
  629: 			return -1;
  630: 		}
  631: 	}
  632:  	close(s);
  633: 	return 0;
  634: }
  635: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>