File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / miniupnpd / minissdpd / minissdpd.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:25:11 2023 UTC (14 months, 4 weeks ago) by misho
Branches: miniupnpd, MAIN
CVS tags: v2_3_3p0, HEAD
Version 2.3.3p0

    1: /* $Id: minissdpd.c,v 1.1.1.1 2023/09/27 11:25:11 misho Exp $ */
    2: /* vim: tabstop=4 shiftwidth=4 noexpandtab
    3:  * MiniUPnP project
    4:  * (c) 2007-2022 Thomas Bernard
    5:  * website : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
    6:  * This software is subject to the conditions detailed
    7:  * in the LICENCE file provided within the distribution */
    8: 
    9: #include "config.h"
   10: 
   11: #include <stdlib.h>
   12: #include <stdio.h>
   13: #include <string.h>
   14: #include <signal.h>
   15: #include <errno.h>
   16: #include <sys/time.h>
   17: #include <sys/types.h>
   18: #include <sys/socket.h>
   19: #include <unistd.h>
   20: #include <netinet/in.h>
   21: #include <arpa/inet.h>
   22: #include <syslog.h>
   23: #include <ctype.h>
   24: #include <time.h>
   25: #include <sys/queue.h>
   26: /* for chmod : */
   27: #include <sys/stat.h>
   28: /* unix sockets */
   29: #include <sys/un.h>
   30: /* for getpwnam() and getgrnam() */
   31: #if 0
   32: #include <pwd.h>
   33: #include <grp.h>
   34: #endif
   35: 
   36: /* LOG_PERROR does not exist on Solaris */
   37: #ifndef LOG_PERROR
   38: #define LOG_PERROR 0
   39: #endif /* LOG_PERROR */
   40: 
   41: #include "getifaddr.h"
   42: #include "upnputils.h"
   43: #include "openssdpsocket.h"
   44: #include "daemonize.h"
   45: #include "codelength.h"
   46: #include "ifacewatch.h"
   47: #include "minissdpdtypes.h"
   48: #include "asyncsendto.h"
   49: 
   50: #define SET_MAX(max, x)	if((x) > (max)) (max) = (x)
   51: #ifndef MIN
   52: #define MIN(x,y) (((x)<(y))?(x):(y))
   53: #endif
   54: 
   55: /* current request management structure */
   56: struct reqelem {
   57: 	int socket;
   58: 	int is_notify;	/* has subscribed to notifications */
   59: 	LIST_ENTRY(reqelem) entries;
   60: 	unsigned char * output_buffer;
   61: 	int output_buffer_offset;
   62: 	int output_buffer_len;
   63: };
   64: 
   65: /* device data structures */
   66: struct header {
   67: 	const char * p; /* string pointer */
   68: 	int l;          /* string length */
   69: };
   70: 
   71: #define HEADER_NT	0
   72: #define HEADER_USN	1
   73: #define HEADER_LOCATION	2
   74: 
   75: struct device {
   76: 	struct device * next;
   77: 	time_t t;                 /* validity time */
   78: 	struct header headers[3]; /* NT, USN and LOCATION headers */
   79: 	char data[];
   80: };
   81: 
   82: /* Services stored for answering to M-SEARCH */
   83: struct service {
   84: 	char * st;	/* Service type */
   85: 	char * usn;	/* Unique identifier */
   86: 	char * server;	/* Server string */
   87: 	char * location;	/* URL */
   88: 	LIST_ENTRY(service) entries;
   89: };
   90: LIST_HEAD(servicehead, service) servicelisthead;
   91: 
   92: #define NTS_SSDP_ALIVE	1
   93: #define NTS_SSDP_BYEBYE	2
   94: #define NTS_SSDP_UPDATE	3
   95: 
   96: /* request types */
   97: enum request_type {
   98: 	MINISSDPD_GET_VERSION = 0,
   99: 	MINISSDPD_SEARCH_TYPE = 1,
  100: 	MINISSDPD_SEARCH_USN = 2,
  101: 	MINISSDPD_SEARCH_ALL = 3,
  102: 	MINISSDPD_SUBMIT = 4,
  103: 	MINISSDPD_NOTIF = 5
  104: };
  105: 
  106: /* discovered device list kept in memory */
  107: struct device * devlist = 0;
  108: 
  109: /* bootid and configid */
  110: unsigned int upnp_bootid = 1;
  111: unsigned int upnp_configid = 1337;
  112: 
  113: /* LAN interfaces/addresses */
  114: struct lan_addr_list lan_addrs;
  115: 
  116: /* connected clients */
  117: LIST_HEAD(reqstructhead, reqelem) reqlisthead;
  118: 
  119: /* functions prototypes */
  120: 
  121: #define NOTIF_NEW    1
  122: #define NOTIF_UPDATE 2
  123: #define NOTIF_REMOVE 3
  124: static void
  125: sendNotifications(int notif_type, const struct device * dev, const struct service * serv);
  126: 
  127: /* functions */
  128: 
  129: /* parselanaddr()
  130:  * parse address with mask
  131:  * ex: 192.168.1.1/24 or 192.168.1.1/255.255.255.0
  132:  *
  133:  * Can also use the interface name (ie eth0)
  134:  *
  135:  * return value :
  136:  *    0 : ok
  137:  *   -1 : error */
  138: static int
  139: parselanaddr(struct lan_addr_s * lan_addr, const char * str)
  140: {
  141: 	const char * p;
  142: 	int n;
  143: 	char tmp[16];
  144: 
  145: 	memset(lan_addr, 0, sizeof(struct lan_addr_s));
  146: 	p = str;
  147: 	while(*p && *p != '/' && !isspace(*p))
  148: 		p++;
  149: 	n = p - str;
  150: 	if(!isdigit(str[0]) && n < (int)sizeof(lan_addr->ifname)) {
  151: 		/* not starting with a digit : suppose it is an interface name */
  152: 		memcpy(lan_addr->ifname, str, n);
  153: 		lan_addr->ifname[n] = '\0';
  154: 		if(getifaddr(lan_addr->ifname, lan_addr->str, sizeof(lan_addr->str),
  155: 		             &lan_addr->addr, &lan_addr->mask) < 0)
  156: 			goto parselan_error;
  157: 		/*printf("%s => %s\n", lan_addr->ifname, lan_addr->str);*/
  158: 	} else {
  159: 		if(n>15)
  160: 			goto parselan_error;
  161: 		memcpy(lan_addr->str, str, n);
  162: 		lan_addr->str[n] = '\0';
  163: 		if(!inet_aton(lan_addr->str, &lan_addr->addr))
  164: 			goto parselan_error;
  165: 	}
  166: 	if(*p == '/') {
  167: 		const char * q = ++p;
  168: 		while(*p && isdigit(*p))
  169: 			p++;
  170: 		if(*p=='.') {
  171: 			/* parse mask in /255.255.255.0 format */
  172: 			while(*p && (*p=='.' || isdigit(*p)))
  173: 				p++;
  174: 			n = p - q;
  175: 			if(n>15)
  176: 				goto parselan_error;
  177: 			memcpy(tmp, q, n);
  178: 			tmp[n] = '\0';
  179: 			if(!inet_aton(tmp, &lan_addr->mask))
  180: 				goto parselan_error;
  181: 		} else {
  182: 			/* it is a /24 format */
  183: 			int nbits = atoi(q);
  184: 			if(nbits > 32 || nbits < 0)
  185: 				goto parselan_error;
  186: 			lan_addr->mask.s_addr = htonl(nbits ? (0xffffffffu << (32 - nbits)) : 0);
  187: 		}
  188: 	} else if(lan_addr->mask.s_addr == 0) {
  189: 		/* by default, networks are /24 */
  190: 		lan_addr->mask.s_addr = htonl(0xffffff00u);
  191: 	}
  192: #ifdef ENABLE_IPV6
  193: 	if(lan_addr->ifname[0] != '\0') {
  194: 		lan_addr->index = if_nametoindex(lan_addr->ifname);
  195: 		if(lan_addr->index == 0)
  196: 			fprintf(stderr, "Cannot get index for network interface %s\n",
  197: 			        lan_addr->ifname);
  198: 	} else {
  199: 		fprintf(stderr,
  200: 		        "Error: please specify LAN network interface by name instead of IPv4 address : %s\n",
  201: 		        str);
  202: 		return -1;
  203: 	}
  204: #endif /* ENABLE_IPV6 */
  205: 	return 0;
  206: parselan_error:
  207: 	fprintf(stderr, "Error parsing address/mask (or interface name) : %s\n",
  208: 	        str);
  209: 	return -1;
  210: }
  211: 
  212: static int
  213: write_buffer(struct reqelem * req)
  214: {
  215: 	if(req->output_buffer && req->output_buffer_len > 0) {
  216: 		int n = write(req->socket,
  217: 		              req->output_buffer + req->output_buffer_offset,
  218: 		              req->output_buffer_len);
  219: 		if(n >= 0) {
  220: 			req->output_buffer_offset += n;
  221: 			req->output_buffer_len -= n;
  222: 		} else if(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) {
  223: 			return 0;
  224: 		}
  225: 		return n;
  226: 	} else {
  227: 		return 0;
  228: 	}
  229: }
  230: 
  231: static int
  232: add_to_buffer(struct reqelem * req, const unsigned char * data, int len)
  233: {
  234: 	unsigned char * tmp;
  235: 	if(req->output_buffer_offset > 0) {
  236: 		memmove(req->output_buffer, req->output_buffer + req->output_buffer_offset, req->output_buffer_len);
  237: 		req->output_buffer_offset = 0;
  238: 	}
  239: 	tmp = realloc(req->output_buffer, req->output_buffer_len + len);
  240: 	if(tmp == NULL) {
  241: 		syslog(LOG_ERR, "%s: failed to allocate %d bytes",
  242: 		       __func__, req->output_buffer_len + len);
  243: 		return -1;
  244: 	}
  245: 	req->output_buffer = tmp;
  246: 	memcpy(req->output_buffer + req->output_buffer_len, data, len);
  247: 	req->output_buffer_len += len;
  248: 	return len;
  249: }
  250: 
  251: static int
  252: write_or_buffer(struct reqelem * req, const unsigned char * data, int len)
  253: {
  254: 	if(write_buffer(req) < 0)
  255: 		return -1;
  256: 	if(req->output_buffer && req->output_buffer_len > 0) {
  257: 		return add_to_buffer(req, data, len);
  258: 	} else {
  259: 		int n = write(req->socket, data, len);
  260: 		if(n == len)
  261: 			return len;
  262: 		if(n < 0) {
  263: 			if(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) {
  264: 				n = add_to_buffer(req, data, len);
  265: 				if(n < 0) return n;
  266: 			} else {
  267: 				return n;
  268: 			}
  269: 		} else {
  270: 			n = add_to_buffer(req, data + n, len - n);
  271: 			if(n < 0) return n;
  272: 		}
  273: 	}
  274: 	return len;
  275: }
  276: 
  277: static const char *
  278: nts_to_str(int nts)
  279: {
  280: 	switch(nts)
  281: 	{
  282: 	case NTS_SSDP_ALIVE:
  283: 		return "ssdp:alive";
  284: 	case NTS_SSDP_BYEBYE:
  285: 		return "ssdp:byebye";
  286: 	case NTS_SSDP_UPDATE:
  287: 		return "ssdp:update";
  288: 	}
  289: 	return "unknown";
  290: }
  291: 
  292: /* updateDevice() :
  293:  * adds or updates the device to the list.
  294:  * return value :
  295:  *   0 : the device was updated (or nothing done)
  296:  *   1 : the device was new    */
  297: static int
  298: updateDevice(const struct header * headers, time_t t)
  299: {
  300: 	struct device ** pp = &devlist;
  301: 	struct device * p = *pp;	/* = devlist; */
  302: 	while(p)
  303: 	{
  304: 		if(  p->headers[HEADER_NT].l == headers[HEADER_NT].l
  305: 		  && (0==memcmp(p->headers[HEADER_NT].p, headers[HEADER_NT].p, headers[HEADER_NT].l))
  306: 		  && p->headers[HEADER_USN].l == headers[HEADER_USN].l
  307: 		  && (0==memcmp(p->headers[HEADER_USN].p, headers[HEADER_USN].p, headers[HEADER_USN].l)) )
  308: 		{
  309: 			/*printf("found! %d\n", (int)(t - p->t));*/
  310: 			syslog(LOG_DEBUG, "device updated : %.*s", headers[HEADER_USN].l, headers[HEADER_USN].p);
  311: 			p->t = t;
  312: 			/* update Location ! */
  313: 			if(headers[HEADER_LOCATION].l > p->headers[HEADER_LOCATION].l)
  314: 			{
  315: 				struct device * tmp;
  316: 				tmp = realloc(p, sizeof(struct device)
  317: 				    + headers[0].l+headers[1].l+headers[2].l);
  318: 				if(!tmp)	/* allocation error */
  319: 				{
  320: 					syslog(LOG_ERR, "updateDevice() : memory allocation error");
  321: 					*pp = p->next;	/* remove "p" from the list */
  322: 					free(p);
  323: 					return 0;
  324: 				}
  325: 				p = tmp;
  326: 				*pp = p;
  327: 			}
  328: 			memcpy(p->data + p->headers[0].l + p->headers[1].l,
  329: 			       headers[2].p, headers[2].l);
  330: 			/* TODO : check p->headers[HEADER_LOCATION].l */
  331: 			return 0;
  332: 		}
  333: 		pp = &p->next;
  334: 		p = *pp;	/* p = p->next; */
  335: 	}
  336: 	syslog(LOG_INFO, "new device discovered : %.*s",
  337: 	       headers[HEADER_USN].l, headers[HEADER_USN].p);
  338: 	/* add */
  339: 	{
  340: 		char * pc;
  341: 		int i;
  342: 		p = malloc(  sizeof(struct device)
  343: 		           + headers[0].l+headers[1].l+headers[2].l );
  344: 		if(!p) {
  345: 			syslog(LOG_ERR, "updateDevice(): cannot allocate memory");
  346: 			return -1;
  347: 		}
  348: 		p->next = devlist;
  349: 		p->t = t;
  350: 		pc = p->data;
  351: 		for(i = 0; i < 3; i++)
  352: 		{
  353: 			p->headers[i].p = pc;
  354: 			p->headers[i].l = headers[i].l;
  355: 			memcpy(pc, headers[i].p, headers[i].l);
  356: 			pc += headers[i].l;
  357: 		}
  358: 		devlist = p;
  359: 		sendNotifications(NOTIF_NEW, p, NULL);
  360: 	}
  361: 	return 1;
  362: }
  363: 
  364: /* removeDevice() :
  365:  * remove a device from the list
  366:  * return value :
  367:  *    0 : no device removed
  368:  *   -1 : device removed */
  369: static int
  370: removeDevice(const struct header * headers)
  371: {
  372: 	struct device ** pp = &devlist;
  373: 	struct device * p = *pp;	/* = devlist */
  374: 	while(p)
  375: 	{
  376: 		if(  p->headers[HEADER_NT].l == headers[HEADER_NT].l
  377: 		  && (0==memcmp(p->headers[HEADER_NT].p, headers[HEADER_NT].p, headers[HEADER_NT].l))
  378: 		  && p->headers[HEADER_USN].l == headers[HEADER_USN].l
  379: 		  && (0==memcmp(p->headers[HEADER_USN].p, headers[HEADER_USN].p, headers[HEADER_USN].l)) )
  380: 		{
  381: 			syslog(LOG_INFO, "remove device : %.*s", headers[HEADER_USN].l, headers[HEADER_USN].p);
  382: 			sendNotifications(NOTIF_REMOVE, p, NULL);
  383: 			*pp = p->next;
  384: 			free(p);
  385: 			return -1;
  386: 		}
  387: 		pp = &p->next;
  388: 		p = *pp;	/* p = p->next; */
  389: 	}
  390: 	syslog(LOG_WARNING, "device not found for removing : %.*s", headers[HEADER_USN].l, headers[HEADER_USN].p);
  391: 	return 0;
  392: }
  393: 
  394: /* sent notifications to client having subscribed */
  395: static void
  396: sendNotifications(int notif_type, const struct device * dev, const struct service * serv)
  397: {
  398: 	struct reqelem * req;
  399: 	unsigned int m;
  400: 	unsigned char rbuf[RESPONSE_BUFFER_SIZE];
  401: 	unsigned char * rp;
  402: 
  403: 	for(req = reqlisthead.lh_first; req; req = req->entries.le_next) {
  404: 		if(!req->is_notify) continue;
  405: 		rbuf[0] = '\xff'; /* special code for notifications */
  406: 		rbuf[1] = (unsigned char)notif_type;
  407: 		rbuf[2] = 0;
  408: 		rp = rbuf + 3;
  409: 		if(dev) {
  410: 			/* response :
  411: 			 * 1 - Location
  412: 			 * 2 - NT (device/service type)
  413: 			 * 3 - usn */
  414: 			m = dev->headers[HEADER_LOCATION].l;
  415: 			CODELENGTH(m, rp);
  416: 			memcpy(rp, dev->headers[HEADER_LOCATION].p, dev->headers[HEADER_LOCATION].l);
  417: 			rp += dev->headers[HEADER_LOCATION].l;
  418: 			m = dev->headers[HEADER_NT].l;
  419: 			CODELENGTH(m, rp);
  420: 			memcpy(rp, dev->headers[HEADER_NT].p, dev->headers[HEADER_NT].l);
  421: 			rp += dev->headers[HEADER_NT].l;
  422: 			m = dev->headers[HEADER_USN].l;
  423: 			CODELENGTH(m, rp);
  424: 			memcpy(rp, dev->headers[HEADER_USN].p, dev->headers[HEADER_USN].l);
  425: 			rp += dev->headers[HEADER_USN].l;
  426: 			rbuf[2]++;
  427: 		}
  428: 		if(serv) {
  429: 			/* response :
  430: 			 * 1 - Location
  431: 			 * 2 - NT (device/service type)
  432: 			 * 3 - usn */
  433: 			m = strlen(serv->location);
  434: 			CODELENGTH(m, rp);
  435: 			memcpy(rp, serv->location, m);
  436: 			rp += m;
  437: 			m = strlen(serv->st);
  438: 			CODELENGTH(m, rp);
  439: 			memcpy(rp, serv->st, m);
  440: 			rp += m;
  441: 			m = strlen(serv->usn);
  442: 			CODELENGTH(m, rp);
  443: 			memcpy(rp, serv->usn, m);
  444: 			rp += m;
  445: 			rbuf[2]++;
  446: 		}
  447: 		if(rbuf[2] > 0) {
  448: 			if(write_or_buffer(req, rbuf, rp - rbuf) < 0) {
  449: 				syslog(LOG_ERR, "(s=%d) write: %m", req->socket);
  450: 				/*goto error;*/
  451: 			}
  452: 		}
  453: 	}
  454: }
  455: 
  456: /* SendSSDPMSEARCHResponse() :
  457:  * build and send response to M-SEARCH SSDP packets. */
  458: static void
  459: SendSSDPMSEARCHResponse(int s, const struct sockaddr * sockname,
  460:                         const char * st, size_t st_len, const char * usn,
  461:                         const char * server, const char * location)
  462: {
  463: 	int l, n;
  464: 	char buf[1024];
  465: 	socklen_t sockname_len;
  466: 	/*
  467: 	 * follow guideline from document "UPnP Device Architecture 1.0"
  468: 	 * uppercase is recommended.
  469: 	 * DATE: is recommended
  470: 	 * SERVER: OS/ver UPnP/1.0 miniupnpd/1.0
  471: 	 * - check what to put in the 'Cache-Control' header
  472: 	 *
  473: 	 * have a look at the document "UPnP Device Architecture v1.1 */
  474: 	l = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\n"
  475: 		"CACHE-CONTROL: max-age=120\r\n"
  476: 		/*"DATE: ...\r\n"*/
  477: 		"ST: %.*s\r\n"
  478: 		"USN: %s\r\n"
  479: 		"EXT:\r\n"
  480: 		"SERVER: %s\r\n"
  481: 		"LOCATION: %s\r\n"
  482: 		"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
  483: 		"01-NLS: %u\r\n" /* same as BOOTID. UDA v1.1 */
  484: 		"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
  485: 		"CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
  486: 		"\r\n",
  487: 		(int)st_len, st, usn,
  488: 		server, location,
  489: 		upnp_bootid, upnp_bootid, upnp_configid);
  490: #ifdef ENABLE_IPV6
  491: 	sockname_len = (sockname->sa_family == PF_INET6)
  492: 	             ? sizeof(struct sockaddr_in6)
  493: 	             : sizeof(struct sockaddr_in);
  494: #else	/* ENABLE_IPV6 */
  495: 	sockname_len = sizeof(struct sockaddr_in);
  496: #endif	/* ENABLE_IPV6 */
  497: 	n = sendto_or_schedule(s, buf, l, 0, sockname, sockname_len);
  498: 	if(n < 0) {
  499: 		syslog(LOG_ERR, "%s: sendto(udp): %m", __func__);
  500: 	}
  501: }
  502: 
  503: /* Process M-SEARCH requests */
  504: static void
  505: processMSEARCH(int s, const char * st, size_t st_len,
  506:                const struct sockaddr * addr)
  507: {
  508: 	struct service * serv;
  509: #ifdef ENABLE_IPV6
  510: 	char buf[64];
  511: #endif /* ENABLE_IPV6 */
  512: 
  513: 	if(!st || st_len==0)
  514: 		return;
  515: #ifdef ENABLE_IPV6
  516: 	sockaddr_to_string(addr, buf, sizeof(buf));
  517: 	syslog(LOG_INFO, "SSDP M-SEARCH from %s ST:%.*s",
  518: 	       buf, (int)st_len, st);
  519: #else	/* ENABLE_IPV6 */
  520: 	syslog(LOG_INFO, "SSDP M-SEARCH from %s:%d ST: %.*s",
  521: 	       inet_ntoa(((const struct sockaddr_in *)addr)->sin_addr),
  522: 	       ntohs(((const struct sockaddr_in *)addr)->sin_port),
  523: 	       (int)st_len, st);
  524: #endif	/* ENABLE_IPV6 */
  525: 	if(st_len==8 && (0==memcmp(st, "ssdp:all", 8))) {
  526: 		/* send a response for all services */
  527: 		for(serv = servicelisthead.lh_first;
  528: 		    serv;
  529: 		    serv = serv->entries.le_next) {
  530: 			SendSSDPMSEARCHResponse(s, addr,
  531: 			                        serv->st, strlen(serv->st), serv->usn,
  532: 			                        serv->server, serv->location);
  533: 		}
  534: 	} else if(st_len > 5 && (0==memcmp(st, "uuid:", 5))) {
  535: 		/* find a matching UUID value */
  536: 		for(serv = servicelisthead.lh_first;
  537: 		    serv;
  538: 		    serv = serv->entries.le_next) {
  539: 			if(0 == strncmp(serv->usn, st, st_len)) {
  540: 				SendSSDPMSEARCHResponse(s, addr,
  541: 				                        serv->st, strlen(serv->st), serv->usn,
  542: 				                        serv->server, serv->location);
  543: 			}
  544: 		}
  545: 	} else {
  546: 		size_t l;
  547: 		int st_ver = 0;
  548: 		char atoi_buffer[8];
  549: 
  550: 		/* remove version at the end of the ST string */
  551: 		for (l = st_len; l > 0; l--) {
  552: 			if (st[l-1] == ':') {
  553: 				memset(atoi_buffer, 0, sizeof(atoi_buffer));
  554: 				memcpy(atoi_buffer, st + l, MIN((sizeof(atoi_buffer) - 1), st_len - l));
  555: 				st_ver = atoi(atoi_buffer);
  556: 				break;
  557: 			}
  558: 		}
  559: 		if (l == 0)
  560: 			l = st_len;
  561: 		/* answer for each matching service */
  562: 		/* From UPnP Device Architecture v1.1 :
  563: 		 * 1.3.2 [...] Updated versions of device and service types
  564: 		 * are REQUIRED to be full backward compatible with
  565: 		 * previous versions. Devices MUST respond to M-SEARCH
  566: 		 * requests for any supported version. For example, if a
  567: 		 * device implements “urn:schemas-upnporg:service:xyz:2”,
  568: 		 * it MUST respond to search requests for both that type
  569: 		 * and “urn:schemas-upnp-org:service:xyz:1”. The response
  570: 		 * MUST specify the same version as was contained in the
  571: 		 * search request. [...] */
  572: 		for(serv = servicelisthead.lh_first;
  573: 		    serv;
  574: 		    serv = serv->entries.le_next) {
  575: 			if(0 == strncmp(serv->st, st, l)) {
  576: 				syslog(LOG_DEBUG, "Found matching service : %s %s (v %d)", serv->st, serv->location, st_ver);
  577: 				SendSSDPMSEARCHResponse(s, addr,
  578: 				                        st, st_len, serv->usn,
  579: 				                        serv->server, serv->location);
  580: 			}
  581: 		}
  582: 	}
  583: }
  584: 
  585: /**
  586:  * helper function.
  587:  * reject any non ASCII or non printable character.
  588:  */
  589: static int
  590: containsForbiddenChars(const unsigned char * p, int len)
  591: {
  592: 	while(len > 0) {
  593: 		if(*p < ' ' || *p >= '\x7f')
  594: 			return 1;
  595: 		p++;
  596: 		len--;
  597: 	}
  598: 	return 0;
  599: }
  600: 
  601: #define METHOD_MSEARCH 1
  602: #define METHOD_NOTIFY 2
  603: 
  604: /* ParseSSDPPacket() :
  605:  * parse a received SSDP Packet and call
  606:  * updateDevice() or removeDevice() as needed
  607:  * return value :
  608:  *    -1 : a device was removed
  609:  *     0 : no device removed nor added
  610:  *     1 : a device was added.  */
  611: static int
  612: ParseSSDPPacket(int s, const char * p, ssize_t n,
  613:                 const struct sockaddr * addr,
  614:                 const char * searched_device)
  615: {
  616: 	const char * linestart;
  617: 	const char * lineend;
  618: 	const char * nameend;
  619: 	const char * valuestart;
  620: 	struct header headers[3];
  621: 	int i, r = 0;
  622: 	int methodlen;
  623: 	int nts = -1;
  624: 	int method = -1;
  625: 	unsigned int lifetime = 180;	/* 3 minutes by default */
  626: 	const char * st = NULL;
  627: 	int st_len = 0;
  628: 
  629: 	/* first check from what subnet is the sender */
  630: 	if(get_lan_for_peer(addr) == NULL) {
  631: 		char addr_str[64];
  632: 		sockaddr_to_string(addr, addr_str, sizeof(addr_str));
  633: 		syslog(LOG_WARNING, "peer %s is not from a LAN",
  634: 		       addr_str);
  635: 		return 0;
  636: 	}
  637: 
  638: 	/* do the parsing */
  639: 	memset(headers, 0, sizeof(headers));
  640: 	for(methodlen = 0;
  641: 	    methodlen < n && (isalpha(p[methodlen]) || p[methodlen]=='-');
  642: 		methodlen++);
  643: 	if(methodlen==8 && 0==memcmp(p, "M-SEARCH", 8))
  644: 		method = METHOD_MSEARCH;
  645: 	else if(methodlen==6 && 0==memcmp(p, "NOTIFY", 6))
  646: 		method = METHOD_NOTIFY;
  647: 	else if(methodlen==4 && 0==memcmp(p, "HTTP", 4)) {
  648: 		/* answer to a M-SEARCH => process it as a NOTIFY
  649: 		 * with NTS: ssdp:alive */
  650: 		method = METHOD_NOTIFY;
  651: 		nts = NTS_SSDP_ALIVE;
  652: 	}
  653: 	linestart = p;
  654: 	while(linestart < p + n - 2) {
  655: 		/* start parsing the line : detect line end */
  656: 		lineend = linestart;
  657: 		while(lineend < p + n && *lineend != '\n' && *lineend != '\r')
  658: 			lineend++;
  659: 		/*printf("line: '%.*s'\n", lineend - linestart, linestart);*/
  660: 		/* detect name end : ':' character */
  661: 		nameend = linestart;
  662: 		while(nameend < lineend && *nameend != ':')
  663: 			nameend++;
  664: 		/* detect value */
  665: 		if(nameend < lineend)
  666: 			valuestart = nameend + 1;
  667: 		else
  668: 			valuestart = nameend;
  669: 		/* trim spaces */
  670: 		while(valuestart < lineend && isspace(*valuestart))
  671: 			valuestart++;
  672: 		/* suppress leading " if needed */
  673: 		if(valuestart < lineend && *valuestart=='\"')
  674: 			valuestart++;
  675: 		if(nameend > linestart && valuestart < lineend) {
  676: 			int l = nameend - linestart;	/* header name length */
  677: 			int m = lineend - valuestart;	/* header value length */
  678: 			/* suppress tailing spaces */
  679: 			while(m>0 && isspace(valuestart[m-1]))
  680: 				m--;
  681: 			/* suppress tailing ' if needed */
  682: 			if(m>0 && valuestart[m-1] == '\"')
  683: 				m--;
  684: 			i = -1;
  685: 			/*printf("--%.*s: (%d)%.*s--\n", l, linestart,
  686: 			                           m, m, valuestart);*/
  687: 			if(l==2 && 0==strncasecmp(linestart, "nt", 2))
  688: 				i = HEADER_NT;
  689: 			else if(l==3 && 0==strncasecmp(linestart, "usn", 3))
  690: 				i = HEADER_USN;
  691: 			else if(l==3 && 0==strncasecmp(linestart, "nts", 3)) {
  692: 				if(m==10 && 0==strncasecmp(valuestart, "ssdp:alive", 10))
  693: 					nts = NTS_SSDP_ALIVE;
  694: 				else if(m==11 && 0==strncasecmp(valuestart, "ssdp:byebye", 11))
  695: 					nts = NTS_SSDP_BYEBYE;
  696: 				else if(m==11 && 0==strncasecmp(valuestart, "ssdp:update", 11))
  697: 					nts = NTS_SSDP_UPDATE;
  698: 			}
  699: 			else if(l==8 && 0==strncasecmp(linestart, "location", 8))
  700: 				i = HEADER_LOCATION;
  701: 			else if(l==13 && 0==strncasecmp(linestart, "cache-control", 13)) {
  702: 				/* parse "name1=value1, name_alone, name2=value2" string */
  703: 				const char * name = valuestart;	/* name */
  704: 				const char * val;				/* value */
  705: 				int rem = m;	/* remaining bytes to process */
  706: 				while(rem > 0) {
  707: 					val = name;
  708: 					while(val < name + rem && *val != '=' && *val != ',')
  709: 						val++;
  710: 					if(val >= name + rem)
  711: 						break;
  712: 					if(*val == '=') {
  713: 						while(val < name + rem && (*val == '=' || isspace(*val)))
  714: 							val++;
  715: 						if(val >= name + rem)
  716: 							break;
  717: 						if(0==strncasecmp(name, "max-age", 7))
  718: 							lifetime = (unsigned int)strtoul(val, 0, 0);
  719: 						/* move to the next name=value pair */
  720: 						while(rem > 0 && *name != ',') {
  721: 							rem--;
  722: 							name++;
  723: 						}
  724: 						/* skip spaces */
  725: 						while(rem > 0 && (*name == ',' || isspace(*name))) {
  726: 							rem--;
  727: 							name++;
  728: 						}
  729: 					} else {
  730: 						rem -= (val - name);
  731: 						name = val;
  732: 						while(rem > 0 && (*name == ',' || isspace(*name))) {
  733: 							rem--;
  734: 							name++;
  735: 						}
  736: 					}
  737: 				}
  738: 				/*syslog(LOG_DEBUG, "**%.*s**%u", m, valuestart, lifetime);*/
  739: 			} else if(l==2 && 0==strncasecmp(linestart, "st", 2)) {
  740: 				st = valuestart;
  741: 				st_len = m;
  742: 				if(method == METHOD_NOTIFY)
  743: 					i = HEADER_NT;	/* it was a M-SEARCH response */
  744: 			}
  745: 			if(i>=0) {
  746: 				headers[i].p = valuestart;
  747: 				headers[i].l = m;
  748: 			}
  749: 		}
  750: 		linestart = lineend;
  751: 		while((linestart < p + n) && (*linestart == '\n' || *linestart == '\r'))
  752: 			linestart++;
  753: 	}
  754: #if 0
  755: 	printf("NTS=%d\n", nts);
  756: 	for(i=0; i<3; i++) {
  757: 		if(headers[i].p)
  758: 			printf("%d-'%.*s'\n", i, headers[i].l, headers[i].p);
  759: 	}
  760: #endif
  761: 	syslog(LOG_DEBUG,"SSDP request: '%.*s' (%d) %s %s=%.*s",
  762: 	       methodlen, p, method, nts_to_str(nts),
  763: 	       (method==METHOD_NOTIFY)?"nt":"st",
  764: 	       (method==METHOD_NOTIFY)?headers[HEADER_NT].l:st_len,
  765: 	       (method==METHOD_NOTIFY)?headers[HEADER_NT].p:st);
  766: 	switch(method) {
  767: 	case METHOD_NOTIFY:
  768: 		if(nts==NTS_SSDP_ALIVE || nts==NTS_SSDP_UPDATE) {
  769: 			if(headers[HEADER_NT].p && headers[HEADER_USN].p && headers[HEADER_LOCATION].p) {
  770: 				/* filter if needed */
  771: 				if(searched_device &&
  772: 				   0 != memcmp(headers[HEADER_NT].p, searched_device, headers[HEADER_NT].l))
  773: 					break;
  774: 				r = updateDevice(headers, time(NULL) + lifetime);
  775: 			} else {
  776: 				syslog(LOG_WARNING, "missing header nt=%p usn=%p location=%p",
  777: 				       headers[HEADER_NT].p, headers[HEADER_USN].p,
  778: 				       headers[HEADER_LOCATION].p);
  779: 			}
  780: 		} else if(nts==NTS_SSDP_BYEBYE) {
  781: 			if(headers[HEADER_NT].p && headers[HEADER_USN].p) {
  782: 				r = removeDevice(headers);
  783: 			} else {
  784: 				syslog(LOG_WARNING, "missing header nt=%p usn=%p",
  785: 				       headers[HEADER_NT].p, headers[HEADER_USN].p);
  786: 			}
  787: 		}
  788: 		break;
  789: 	case METHOD_MSEARCH:
  790: 		processMSEARCH(s, st, st_len, addr);
  791: 		break;
  792: 	default:
  793: 		{
  794: 			char addr_str[64];
  795: 			sockaddr_to_string(addr, addr_str, sizeof(addr_str));
  796: 			syslog(LOG_WARNING, "method %.*s, don't know what to do (from %s)",
  797: 			       methodlen, p, addr_str);
  798: 		}
  799: 	}
  800: 	return r;
  801: }
  802: 
  803: /* OpenUnixSocket()
  804:  * open the unix socket and call bind() and listen()
  805:  * return -1 in case of error */
  806: static int
  807: OpenUnixSocket(const char * path)
  808: {
  809: 	struct sockaddr_un addr;
  810: 	int s;
  811: 	int rv;
  812: 	s = socket(AF_UNIX, SOCK_STREAM, 0);
  813: 	if(s < 0)
  814: 	{
  815: 		syslog(LOG_ERR, "socket(AF_UNIX): %m");
  816: 		return -1;
  817: 	}
  818: 	/* unlink the socket pseudo file before binding */
  819: 	rv = unlink(path);
  820: 	if(rv < 0 && errno != ENOENT)
  821: 	{
  822: 		syslog(LOG_ERR, "unlink(unixsocket, \"%s\"): %m", path);
  823: 		close(s);
  824: 		return -1;
  825: 	}
  826: 	addr.sun_family = AF_UNIX;
  827: 	strncpy(addr.sun_path, path, sizeof(addr.sun_path));
  828: 	if(bind(s, (struct sockaddr *)&addr,
  829: 	           sizeof(struct sockaddr_un)) < 0)
  830: 	{
  831: 		syslog(LOG_ERR, "bind(unixsocket, \"%s\"): %m", path);
  832: 		close(s);
  833: 		return -1;
  834: 	}
  835: 	else if(listen(s, 5) < 0)
  836: 	{
  837: 		syslog(LOG_ERR, "listen(unixsocket): %m");
  838: 		close(s);
  839: 		return -1;
  840: 	}
  841: 	/* Change rights so everyone can communicate with us */
  842: 	if(chmod(path, 0666) < 0)
  843: 	{
  844: 		syslog(LOG_WARNING, "chmod(\"%s\"): %m", path);
  845: 	}
  846: 	return s;
  847: }
  848: 
  849: static ssize_t processRequestSub(struct reqelem * req, const unsigned char * buf, ssize_t n);
  850: 
  851: /* processRequest() :
  852:  * process the request coming from a unix socket */
  853: void processRequest(struct reqelem * req)
  854: {
  855: 	ssize_t n, r;
  856: 	unsigned char buf[2048];
  857: 	const unsigned char * p;
  858: 
  859: 	n = read(req->socket, buf, sizeof(buf));
  860: 	if(n<0) {
  861: 		if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
  862: 			return;	/* try again later */
  863: 		syslog(LOG_ERR, "(s=%d) processRequest(): read(): %m", req->socket);
  864: 		goto error;
  865: 	}
  866: 	if(n==0) {
  867: 		syslog(LOG_INFO, "(s=%d) request connection closed", req->socket);
  868: 		goto error;
  869: 	}
  870: 	p = buf;
  871: 	while (n > 0)
  872: 	{
  873: 		r = processRequestSub(req, p, n);
  874: 		if (r < 0)
  875: 			goto error;
  876: 		p += r;
  877: 		n -= r;
  878: 	}
  879: 	return;
  880: error:
  881: 	close(req->socket);
  882: 	req->socket = -1;
  883: }
  884: 
  885: static ssize_t processRequestSub(struct reqelem * req, const unsigned char * buf, ssize_t n)
  886: {
  887: 	unsigned int l, m;
  888: 	unsigned int baselen;	/* without the version */
  889: 	const unsigned char * p;
  890: 	enum request_type type;
  891: 	struct device * d = devlist;
  892: 	unsigned char rbuf[RESPONSE_BUFFER_SIZE];
  893: 	unsigned char * rp;
  894: 	unsigned char nrep = 0;
  895: 	time_t t;
  896: 	struct service * newserv = NULL;
  897: 	struct service * serv;
  898: 
  899: 	t = time(NULL);
  900: 	type = buf[0];
  901: 	p = buf + 1;
  902: 	DECODELENGTH_CHECKLIMIT(l, p, buf + n);
  903: 	if(l > (unsigned)(buf+n-p)) {
  904: 		syslog(LOG_WARNING, "bad request (length encoding l=%u n=%u)",
  905: 		       l, (unsigned)n);
  906: 		goto error;
  907: 	}
  908: 	if(l == 0 && type != MINISSDPD_SEARCH_ALL
  909: 	   && type != MINISSDPD_GET_VERSION && type != MINISSDPD_NOTIF) {
  910: 		syslog(LOG_WARNING, "bad request (length=0, type=%d)", type);
  911: 		goto error;
  912: 	}
  913: 	syslog(LOG_INFO, "(s=%d) request type=%d str='%.*s'",
  914: 	       req->socket, type, l, p);
  915: 	switch(type) {
  916: 	case MINISSDPD_GET_VERSION:
  917: 		rp = rbuf;
  918: 		CODELENGTH((sizeof(MINISSDPD_VERSION) - 1), rp);
  919: 		memcpy(rp, MINISSDPD_VERSION, sizeof(MINISSDPD_VERSION) - 1);
  920: 		rp += (sizeof(MINISSDPD_VERSION) - 1);
  921: 		if(write_or_buffer(req, rbuf, rp - rbuf) < 0) {
  922: 			syslog(LOG_ERR, "(s=%d) write: %m", req->socket);
  923: 			goto error;
  924: 		}
  925: 		p += l;
  926: 		break;
  927: 	case MINISSDPD_SEARCH_TYPE:	/* request by type */
  928: 	case MINISSDPD_SEARCH_USN:	/* request by USN (unique id) */
  929: 	case MINISSDPD_SEARCH_ALL:	/* everything */
  930: 		rp = rbuf+1;
  931: 		/* From UPnP Device Architecture v1.1 :
  932: 		 * 1.3.2 [...] Updated versions of device and service types
  933: 		 * are REQUIRED to be full backward compatible with
  934: 		 * previous versions. Devices MUST respond to M-SEARCH
  935: 		 * requests for any supported version. For example, if a
  936: 		 * device implements “urn:schemas-upnporg:service:xyz:2”,
  937: 		 * it MUST respond to search requests for both that type
  938: 		 * and “urn:schemas-upnp-org:service:xyz:1”. The response
  939: 		 * MUST specify the same version as was contained in the
  940: 		 * search request. [...] */
  941: 		baselen = l;	/* remove the version */
  942: 		while(baselen > 0) {
  943: 			if(p[baselen-1] == ':')
  944: 				break;
  945: 			if(!(p[baselen-1] >= '0' && p[baselen-1] <= '9'))
  946: 				break;
  947: 			baselen--;
  948: 		}
  949: 		while(d && (nrep < 255)) {
  950: 			if(d->t < t) {
  951: 				syslog(LOG_INFO, "outdated device");
  952: 			} else {
  953: 				/* test if we can put more responses in the buffer */
  954: 				if(d->headers[HEADER_LOCATION].l + d->headers[HEADER_NT].l
  955: 				  + d->headers[HEADER_USN].l + 6
  956: 				  + (rp - rbuf) >= (int)sizeof(rbuf))
  957: 					break;
  958: 				if( (type==MINISSDPD_SEARCH_TYPE && 0==memcmp(d->headers[HEADER_NT].p, p, baselen))
  959: 				  ||(type==MINISSDPD_SEARCH_USN && 0==memcmp(d->headers[HEADER_USN].p, p, l))
  960: 				  ||(type==MINISSDPD_SEARCH_ALL) ) {
  961: 					/* response :
  962: 					 * 1 - Location
  963: 					 * 2 - NT (device/service type)
  964: 					 * 3 - usn */
  965: 					m = d->headers[HEADER_LOCATION].l;
  966: 					CODELENGTH(m, rp);
  967: 					memcpy(rp, d->headers[HEADER_LOCATION].p, d->headers[HEADER_LOCATION].l);
  968: 					rp += d->headers[HEADER_LOCATION].l;
  969: 					m = d->headers[HEADER_NT].l;
  970: 					CODELENGTH(m, rp);
  971: 					memcpy(rp, d->headers[HEADER_NT].p, d->headers[HEADER_NT].l);
  972: 					rp += d->headers[HEADER_NT].l;
  973: 					m = d->headers[HEADER_USN].l;
  974: 					CODELENGTH(m, rp);
  975: 					memcpy(rp, d->headers[HEADER_USN].p, d->headers[HEADER_USN].l);
  976: 					rp += d->headers[HEADER_USN].l;
  977: 					nrep++;
  978: 				}
  979: 			}
  980: 			d = d->next;
  981: 		}
  982: 		/* Also look in service list */
  983: 		for(serv = servicelisthead.lh_first;
  984: 		    serv && (nrep < 255);
  985: 		    serv = serv->entries.le_next) {
  986: 			/* test if we can put more responses in the buffer */
  987: 			if(strlen(serv->location) + strlen(serv->st)
  988: 			  + strlen(serv->usn) + 6 + (rp - rbuf) >= sizeof(rbuf))
  989: 			  	break;
  990: 			if( (type==MINISSDPD_SEARCH_TYPE && 0==strncmp(serv->st, (const char *)p, l))
  991: 			  ||(type==MINISSDPD_SEARCH_USN && 0==strncmp(serv->usn, (const char *)p, l))
  992: 			  ||(type==MINISSDPD_SEARCH_ALL) ) {
  993: 				/* response :
  994: 				 * 1 - Location
  995: 				 * 2 - NT (device/service type)
  996: 				 * 3 - usn */
  997: 				m = strlen(serv->location);
  998: 				CODELENGTH(m, rp);
  999: 				memcpy(rp, serv->location, m);
 1000: 				rp += m;
 1001: 				m = strlen(serv->st);
 1002: 				CODELENGTH(m, rp);
 1003: 				memcpy(rp, serv->st, m);
 1004: 				rp += m;
 1005: 				m = strlen(serv->usn);
 1006: 				CODELENGTH(m, rp);
 1007: 				memcpy(rp, serv->usn, m);
 1008: 				rp += m;
 1009: 				nrep++;
 1010: 			}
 1011: 		}
 1012: 		rbuf[0] = nrep;
 1013: 		syslog(LOG_DEBUG, "(s=%d) response : %d device%s",
 1014: 		       req->socket, nrep, (nrep > 1) ? "s" : "");
 1015: 		if(write_or_buffer(req, rbuf, rp - rbuf) < 0) {
 1016: 			syslog(LOG_ERR, "(s=%d) write: %m", req->socket);
 1017: 			goto error;
 1018: 		}
 1019: 		p += l;
 1020: 		break;
 1021: 	case MINISSDPD_SUBMIT:	/* submit service */
 1022: 		newserv = malloc(sizeof(struct service));
 1023: 		if(!newserv) {
 1024: 			syslog(LOG_ERR, "cannot allocate memory");
 1025: 			goto error;
 1026: 		}
 1027: 		memset(newserv, 0, sizeof(struct service));	/* set pointers to NULL */
 1028: 		if(containsForbiddenChars(p, l)) {
 1029: 			syslog(LOG_ERR, "bad request (st contains forbidden chars)");
 1030: 			goto error;
 1031: 		}
 1032: 		newserv->st = malloc(l + 1);
 1033: 		if(!newserv->st) {
 1034: 			syslog(LOG_ERR, "cannot allocate memory");
 1035: 			goto error;
 1036: 		}
 1037: 		memcpy(newserv->st, p, l);
 1038: 		newserv->st[l] = '\0';
 1039: 		p += l;
 1040: 		if(p >= buf + n) {
 1041: 			syslog(LOG_WARNING, "bad request (missing usn)");
 1042: 			goto error;
 1043: 		}
 1044: 		DECODELENGTH_CHECKLIMIT(l, p, buf + n);
 1045: 		if(l > (unsigned)(buf+n-p)) {
 1046: 			syslog(LOG_WARNING, "bad request (length encoding)");
 1047: 			goto error;
 1048: 		}
 1049: 		if(containsForbiddenChars(p, l)) {
 1050: 			syslog(LOG_ERR, "bad request (usn contains forbidden chars)");
 1051: 			goto error;
 1052: 		}
 1053: 		syslog(LOG_INFO, "usn='%.*s'", l, p);
 1054: 		newserv->usn = malloc(l + 1);
 1055: 		if(!newserv->usn) {
 1056: 			syslog(LOG_ERR, "cannot allocate memory");
 1057: 			goto error;
 1058: 		}
 1059: 		memcpy(newserv->usn, p, l);
 1060: 		newserv->usn[l] = '\0';
 1061: 		p += l;
 1062: 		DECODELENGTH_CHECKLIMIT(l, p, buf + n);
 1063: 		if(l > (unsigned)(buf+n-p)) {
 1064: 			syslog(LOG_WARNING, "bad request (length encoding)");
 1065: 			goto error;
 1066: 		}
 1067: 		if(containsForbiddenChars(p, l)) {
 1068: 			syslog(LOG_ERR, "bad request (server contains forbidden chars)");
 1069: 			goto error;
 1070: 		}
 1071: 		syslog(LOG_INFO, "server='%.*s'", l, p);
 1072: 		newserv->server = malloc(l + 1);
 1073: 		if(!newserv->server) {
 1074: 			syslog(LOG_ERR, "cannot allocate memory");
 1075: 			goto error;
 1076: 		}
 1077: 		memcpy(newserv->server, p, l);
 1078: 		newserv->server[l] = '\0';
 1079: 		p += l;
 1080: 		DECODELENGTH_CHECKLIMIT(l, p, buf + n);
 1081: 		if(l > (unsigned)(buf+n-p)) {
 1082: 			syslog(LOG_WARNING, "bad request (length encoding)");
 1083: 			goto error;
 1084: 		}
 1085: 		if(containsForbiddenChars(p, l)) {
 1086: 			syslog(LOG_ERR, "bad request (location contains forbidden chars)");
 1087: 			goto error;
 1088: 		}
 1089: 		syslog(LOG_INFO, "location='%.*s'", l, p);
 1090: 		newserv->location = malloc(l + 1);
 1091: 		if(!newserv->location) {
 1092: 			syslog(LOG_ERR, "cannot allocate memory");
 1093: 			goto error;
 1094: 		}
 1095: 		memcpy(newserv->location, p, l);
 1096: 		newserv->location[l] = '\0';
 1097: 		p += l;
 1098: 		/* look in service list for duplicate */
 1099: 		for(serv = servicelisthead.lh_first;
 1100: 		    serv;
 1101: 		    serv = serv->entries.le_next) {
 1102: 			if(0 == strcmp(newserv->usn, serv->usn)
 1103: 			  && 0 == strcmp(newserv->st, serv->st)) {
 1104: 				syslog(LOG_INFO, "Service already in the list. Updating...");
 1105: 				free(newserv->st);
 1106: 				free(newserv->usn);
 1107: 				free(serv->server);
 1108: 				serv->server = newserv->server;
 1109: 				free(serv->location);
 1110: 				serv->location = newserv->location;
 1111: 				free(newserv);
 1112: 				newserv = NULL;
 1113: 				return (p - buf);
 1114: 			}
 1115: 		}
 1116: 		/* Inserting new service */
 1117: 		LIST_INSERT_HEAD(&servicelisthead, newserv, entries);
 1118: 		sendNotifications(NOTIF_NEW, NULL, newserv);
 1119: 		newserv = NULL;
 1120: 		break;
 1121: 	case MINISSDPD_NOTIF:	/* switch socket to notify */
 1122: 		rbuf[0] = '\0';
 1123: 		if(write_or_buffer(req, rbuf, 1) < 0) {
 1124: 			syslog(LOG_ERR, "(s=%d) write: %m", req->socket);
 1125: 			goto error;
 1126: 		}
 1127: 		req->is_notify = 1;
 1128: 		p += l;
 1129: 		break;
 1130: 	default:
 1131: 		syslog(LOG_WARNING, "Unknown request type %d", type);
 1132: 		rbuf[0] = '\0';
 1133: 		if(write_or_buffer(req, rbuf, 1) < 0) {
 1134: 			syslog(LOG_ERR, "(s=%d) write: %m", req->socket);
 1135: 			goto error;
 1136: 		}
 1137: 	}
 1138: 	return (p - buf);
 1139: error:
 1140: 	if(newserv) {
 1141: 		free(newserv->st);
 1142: 		free(newserv->usn);
 1143: 		free(newserv->server);
 1144: 		free(newserv->location);
 1145: 		free(newserv);
 1146: 		newserv = NULL;
 1147: 	}
 1148: 	return -1;
 1149: }
 1150: 
 1151: static volatile sig_atomic_t quitting = 0;
 1152: /* SIGTERM signal handler */
 1153: static void
 1154: sigterm(int sig)
 1155: {
 1156: 	(void)sig;
 1157: 	/*int save_errno = errno;*/
 1158: 	/*signal(sig, SIG_IGN);*/
 1159: #if 0
 1160: 	/* calling syslog() is forbidden in a signal handler according to
 1161: 	 * signal(3) */
 1162: 	syslog(LOG_NOTICE, "received signal %d, good-bye", sig);
 1163: #endif
 1164: 	quitting = 1;
 1165: 	/*errno = save_errno;*/
 1166: }
 1167: 
 1168: #define PORT 1900
 1169: #define XSTR(s) STR(s)
 1170: #define STR(s) #s
 1171: #define UPNP_MCAST_ADDR "239.255.255.250"
 1172: /* for IPv6 */
 1173: #define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */
 1174: #define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */
 1175: 
 1176: /* send the M-SEARCH request for devices
 1177:  * either all devices (third argument is NULL or "*") or a specific one */
 1178: static void ssdpDiscover(int s, int ipv6, const char * search)
 1179: {
 1180: 	static const char MSearchMsgFmt[] =
 1181: 	"M-SEARCH * HTTP/1.1\r\n"
 1182: 	"HOST: %s:" XSTR(PORT) "\r\n"
 1183: 	"ST: %s\r\n"
 1184: 	"MAN: \"ssdp:discover\"\r\n"
 1185: 	"MX: %u\r\n"
 1186: 	"\r\n";
 1187: 	char bufr[512];
 1188: 	int n;
 1189: 	int mx = 3;
 1190: 	int linklocal = 1;
 1191: 	struct sockaddr_storage sockudp_w;
 1192: 
 1193: 	{
 1194: 		n = snprintf(bufr, sizeof(bufr),
 1195: 		             MSearchMsgFmt,
 1196: 		             ipv6 ?
 1197: 		             (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" :  "[" UPNP_MCAST_SL_ADDR "]")
 1198: 		             : UPNP_MCAST_ADDR,
 1199: 		             (search ? search : "ssdp:all"), mx);
 1200: 		memset(&sockudp_w, 0, sizeof(struct sockaddr_storage));
 1201: 		if(ipv6) {
 1202: 			struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w;
 1203: 			p->sin6_family = AF_INET6;
 1204: 			p->sin6_port = htons(PORT);
 1205: 			inet_pton(AF_INET6,
 1206: 			          linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR,
 1207: 			          &(p->sin6_addr));
 1208: 		} else {
 1209: 			struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w;
 1210: 			p->sin_family = AF_INET;
 1211: 			p->sin_port = htons(PORT);
 1212: 			p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
 1213: 		}
 1214: 
 1215: 		n = sendto_or_schedule(s, bufr, n, 0, (const struct sockaddr *)&sockudp_w,
 1216: 		                       ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
 1217: 		if (n < 0) {
 1218: 			syslog(LOG_ERR, "%s: sendto(s=%d, ipv6=%d): %m", __func__, s, ipv6);
 1219: 		}
 1220: 	}
 1221: }
 1222: 
 1223: /* main(): program entry point */
 1224: int main(int argc, char * * argv)
 1225: {
 1226: 	int ret = 0;
 1227: #ifndef NO_BACKGROUND_NO_PIDFILE
 1228: 	int pid;
 1229: #endif
 1230: 	struct sigaction sa;
 1231: 	char buf[1500];
 1232: 	ssize_t n;
 1233: 	int s_ssdp = -1;	/* udp socket receiving ssdp packets */
 1234: #ifdef ENABLE_IPV6
 1235: 	int s_ssdp6 = -1;	/* udp socket receiving ssdp packets IPv6*/
 1236: #else	/* ENABLE_IPV6 */
 1237: #define s_ssdp6 (-1)
 1238: #endif	/* ENABLE_IPV6 */
 1239: 	int s_unix = -1;	/* unix socket communicating with clients */
 1240: 	int s_ifacewatch = -1;	/* socket to receive Route / network interface config changes */
 1241: 	struct reqelem * req;
 1242: 	struct reqelem * reqnext;
 1243: 	fd_set readfds;
 1244: 	fd_set writefds;
 1245: 	struct timeval now;
 1246: 	int max_fd;
 1247: 	struct lan_addr_s * lan_addr;
 1248: 	int i;
 1249: 	const char * sockpath = "/var/run/minissdpd.sock";
 1250: #ifndef NO_BACKGROUND_NO_PIDFILE
 1251: 	const char * pidfilename = "/var/run/minissdpd.pid";
 1252: #endif
 1253: 	int debug_flag = 0;
 1254: #ifdef ENABLE_IPV6
 1255: 	int ipv6 = 0;
 1256: #endif /* ENABLE_IPV6 */
 1257: 	int deltadev = 0;
 1258: 	struct sockaddr_in sendername;
 1259: 	socklen_t sendername_len;
 1260: #ifdef ENABLE_IPV6
 1261: 	struct sockaddr_in6 sendername6;
 1262: 	socklen_t sendername6_len;
 1263: #endif	/* ENABLE_IPV6 */
 1264: 	unsigned char ttl = 2;	/* UDA says it should default to 2 */
 1265: 	const char * searched_device = NULL;	/* if not NULL, search/filter a specific device type */
 1266: 	int opt;
 1267: 
 1268: 	LIST_INIT(&reqlisthead);
 1269: 	LIST_INIT(&servicelisthead);
 1270: 	LIST_INIT(&lan_addrs);
 1271: 	/* process command line */
 1272: #define OPTSTRING "d6i:s:p:t:f:"
 1273: 	while ((opt = getopt(argc, argv, "di:s:t:f:"
 1274: #ifdef ENABLE_IPV6
 1275: 	                                 "6"
 1276: #endif
 1277: #ifndef NO_BACKGROUND_NO_PIDFILE
 1278: 	                                 "p:"
 1279: #endif
 1280: 
 1281: 	                     )) != -1)
 1282: 	{
 1283: 		switch(opt)
 1284: 		{
 1285: 		case 'd':
 1286: 			debug_flag = 1;
 1287: 			break;
 1288: #ifdef ENABLE_IPV6
 1289: 		case '6':
 1290: 			ipv6 = 1;
 1291: 			break;
 1292: #endif	/* ENABLE_IPV6 */
 1293: 		case 'i':
 1294: 			lan_addr = malloc(sizeof(struct lan_addr_s));
 1295: 			if(lan_addr == NULL) {
 1296: 				fprintf(stderr, "malloc(%d) FAILED\n", (int)sizeof(struct lan_addr_s));
 1297: 				break;
 1298: 			}
 1299: 			if(parselanaddr(lan_addr, optarg) != 0) {
 1300: 				fprintf(stderr, "can't parse \"%s\" as a valid "
 1301: #ifndef ENABLE_IPV6
 1302: 				        "address or "
 1303: #endif
 1304: 				        "interface name\n", optarg);
 1305: 				free(lan_addr);
 1306: 			} else {
 1307: 				LIST_INSERT_HEAD(&lan_addrs, lan_addr, list);
 1308: 			}
 1309: 			break;
 1310: 		case 's':
 1311: 			sockpath = optarg;
 1312: 			break;
 1313: #ifndef NO_BACKGROUND_NO_PIDFILE
 1314: 		case 'p':
 1315: 			pidfilename = optarg;
 1316: 			break;
 1317: #endif
 1318: 		case 't':
 1319: 			ttl = (unsigned char)atoi(optarg);
 1320: 			break;
 1321: 		case 'f':
 1322: 			searched_device = optarg;
 1323: 			break;
 1324: 		}
 1325: 	}
 1326: 	if(lan_addrs.lh_first == NULL)
 1327: 	{
 1328: 		fprintf(stderr,
 1329: 		        "Usage: %s [-d] "
 1330: #ifdef ENABLE_IPV6
 1331: 		        "[-6] "
 1332: #endif /* ENABLE_IPV6 */
 1333: 		        "[-s socket] "
 1334: #ifndef NO_BACKGROUND_NO_PIDFILE
 1335: 				"[-p pidfile] "
 1336: #endif
 1337: 				"[-t TTL] "
 1338: 		        "[-f device] "
 1339: 		        "-i <interface> [-i <interface2>] ...\n",
 1340: 		        argv[0]);
 1341: 		fprintf(stderr,
 1342: 		        "\n  <interface> is "
 1343: #ifndef ENABLE_IPV6
 1344: 		        "either an IPv4 address with mask such as\n"
 1345: 		        "  192.168.1.42/255.255.255.0, or "
 1346: #endif
 1347: 				"an interface name such as eth0.\n");
 1348: 		fprintf(stderr,
 1349: 		        "\n  By default, socket will be open as %s\n"
 1350: #ifndef NO_BACKGROUND_NO_PIDFILE
 1351: 		        "  and pid written to file %s\n",
 1352: 		        sockpath, pidfilename
 1353: #else
 1354: 				,sockpath
 1355: #endif
 1356: 				);
 1357: 		return 1;
 1358: 	}
 1359: 
 1360: 	/* open log */
 1361: 	openlog("minissdpd",
 1362: 	        LOG_CONS|LOG_PID|(debug_flag?LOG_PERROR:0),
 1363: 			LOG_MINISSDPD);
 1364: 	if(!debug_flag) /* speed things up and ignore LOG_INFO and LOG_DEBUG */
 1365: 		setlogmask(LOG_UPTO(LOG_NOTICE));
 1366: 
 1367: #ifndef NO_BACKGROUND_NO_PIDFILE
 1368: 	if(checkforrunning(pidfilename) < 0)
 1369: 	{
 1370: 		syslog(LOG_ERR, "MiniSSDPd is already running. EXITING");
 1371: 		return 1;
 1372: 	}
 1373: #endif
 1374: 
 1375: 	upnp_bootid = (unsigned int)time(NULL);
 1376: 
 1377: 	/* set signal handlers */
 1378: 	memset(&sa, 0, sizeof(struct sigaction));
 1379: 	sa.sa_handler = sigterm;
 1380: 	if(sigaction(SIGTERM, &sa, NULL))
 1381: 	{
 1382: 		syslog(LOG_ERR, "Failed to set SIGTERM handler. EXITING");
 1383: 		ret = 1;
 1384: 		goto quit;
 1385: 	}
 1386: 	if(sigaction(SIGINT, &sa, NULL))
 1387: 	{
 1388: 		syslog(LOG_ERR, "Failed to set SIGINT handler. EXITING");
 1389: 		ret = 1;
 1390: 		goto quit;
 1391: 	}
 1392: 	/* open route/interface config changes socket */
 1393: 	s_ifacewatch = OpenAndConfInterfaceWatchSocket();
 1394: 	/* open UDP socket(s) for receiving SSDP packets */
 1395: 	s_ssdp = OpenAndConfSSDPReceiveSocket(0, ttl);
 1396: 	if(s_ssdp < 0)
 1397: 	{
 1398: 		syslog(LOG_ERR, "Cannot open socket for receiving SSDP messages, exiting");
 1399: 		ret = 1;
 1400: 		goto quit;
 1401: 	}
 1402: #ifdef ENABLE_IPV6
 1403: 	if(ipv6) {
 1404: 		s_ssdp6 = OpenAndConfSSDPReceiveSocket(1, ttl);
 1405: 		if(s_ssdp6 < 0)
 1406: 		{
 1407: 			syslog(LOG_ERR, "Cannot open socket for receiving SSDP messages (IPv6), exiting");
 1408: 			ret = 1;
 1409: 			goto quit;
 1410: 		}
 1411: 	}
 1412: #endif	/* ENABLE_IPV6 */
 1413: 	/* Open Unix socket to communicate with other programs on
 1414: 	 * the same machine */
 1415: 	s_unix = OpenUnixSocket(sockpath);
 1416: 	if(s_unix < 0)
 1417: 	{
 1418: 		syslog(LOG_ERR, "Cannot open unix socket for communicating with clients. Exiting");
 1419: 		ret = 1;
 1420: 		goto quit;
 1421: 	}
 1422: 
 1423: 	/* drop privileges */
 1424: #if 0
 1425: 	/* if we drop privileges, how to unlink(/var/run/minissdpd.sock) ? */
 1426: 	if(getuid() == 0) {
 1427: 		struct passwd * user;
 1428: 		struct group * group;
 1429: 		user = getpwnam("nobody");
 1430: 		if(!user) {
 1431: 			syslog(LOG_ERR, "getpwnam(\"%s\") : %m", "nobody");
 1432: 			ret = 1;
 1433: 			goto quit;
 1434: 		}
 1435: 		group = getgrnam("nogroup");
 1436: 		if(!group) {
 1437: 			syslog(LOG_ERR, "getgrnam(\"%s\") : %m", "nogroup");
 1438: 			ret = 1;
 1439: 			goto quit;
 1440: 		}
 1441: 		if(setgid(group->gr_gid) < 0) {
 1442: 			syslog(LOG_ERR, "setgit(%d) : %m", group->gr_gid);
 1443: 			ret = 1;
 1444: 			goto quit;
 1445: 		}
 1446: 		if(setuid(user->pw_uid) < 0) {
 1447: 			syslog(LOG_ERR, "setuid(%d) : %m", user->pw_uid);
 1448: 			ret = 1;
 1449: 			goto quit;
 1450: 		}
 1451: 	}
 1452: #endif
 1453: 
 1454: #ifndef NO_BACKGROUND_NO_PIDFILE
 1455: 	/* daemonize or in any case get pid ! */
 1456: 	if(debug_flag)
 1457: 		pid = getpid();
 1458: 	else {
 1459: #ifdef USE_DAEMON
 1460: 		if(daemon(0, 0) < 0)
 1461: 			perror("daemon()");
 1462: 		pid = getpid();
 1463: #else  /* USE_DAEMON */
 1464: 		pid = daemonize();
 1465: #endif /* USE_DAEMON */
 1466: 	}
 1467: 
 1468: 	writepidfile(pidfilename, pid);
 1469: #endif
 1470: 
 1471: 	/* send M-SEARCH ssdp:all Requests */
 1472: 	if(s_ssdp >= 0) {
 1473: 		for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) {
 1474: #ifndef HAVE_IP_MREQN
 1475: 			struct in_addr mc_if;
 1476: 
 1477: 			mc_if.s_addr = lan_addr->addr.s_addr;	/*inet_addr(addr);*/
 1478: #else
 1479: 			struct ip_mreqn mc_if;
 1480: 
 1481: 			mc_if.imr_address.s_addr = lan_addr->addr.s_addr;	/*inet_addr(addr);*/
 1482: #ifdef ENABLE_IPV6
 1483: 			mc_if.imr_ifindex = lan_addr->index;
 1484: #else	/* ENABLE_IPV6 */
 1485: 			mc_if.imr_ifindex = if_nametoindex(lan_addr->ifname);
 1486: #endif	/* ENABLE_IPV6 */
 1487: #endif	/* HAVE_IP_MREQN */
 1488: 			if(setsockopt(s_ssdp, IPPROTO_IP, IP_MULTICAST_IF, &mc_if, sizeof(mc_if)) < 0) {
 1489: 				syslog(LOG_WARNING, "setsockopt(IP_MULTICAST_IF): %m");
 1490: 			}
 1491: 			ssdpDiscover(s_ssdp, 0, searched_device);
 1492: 			/* XXX if ssdpDiscover() doesn't send the SSDP packet at once,
 1493: 			 * we should wait here */
 1494: 		}
 1495: 	}
 1496: 	if(s_ssdp6 >= 0)
 1497: 		ssdpDiscover(s_ssdp6, 1, searched_device);
 1498: 
 1499: 	/* Main loop */
 1500: 	while(!quitting) {
 1501: 		/* fill readfds fd_set */
 1502: 		FD_ZERO(&readfds);
 1503: 		FD_ZERO(&writefds);
 1504: 
 1505: 		FD_SET(s_unix, &readfds);
 1506: 		max_fd = s_unix;
 1507: 		if(s_ssdp >= 0) {
 1508: 			FD_SET(s_ssdp, &readfds);
 1509: 			SET_MAX(max_fd, s_ssdp);
 1510: 		}
 1511: #ifdef ENABLE_IPV6
 1512: 		if(s_ssdp6 >= 0) {
 1513: 			FD_SET(s_ssdp6, &readfds);
 1514: 			SET_MAX(max_fd, s_ssdp6);
 1515: 		}
 1516: #endif /* ENABLE_IPV6 */
 1517: 		if(s_ifacewatch >= 0) {
 1518: 			FD_SET(s_ifacewatch, &readfds);
 1519: 			SET_MAX(max_fd, s_ifacewatch);
 1520: 		}
 1521: 		for(req = reqlisthead.lh_first; req; req = req->entries.le_next) {
 1522: 			if(req->socket >= 0) {
 1523: 				FD_SET(req->socket, &readfds);
 1524: 				SET_MAX(max_fd, req->socket);
 1525: 			}
 1526: 			if(req->output_buffer_len > 0) {
 1527: 				FD_SET(req->socket, &writefds);
 1528: 				SET_MAX(max_fd, req->socket);
 1529: 			}
 1530: 		}
 1531: 		gettimeofday(&now, NULL);
 1532: 		i = get_sendto_fds(&writefds, &max_fd, &now);
 1533: 		/* select call */
 1534: 		if(select(max_fd + 1, &readfds, &writefds, 0, 0) < 0) {
 1535: 			if(errno != EINTR) {
 1536: 				syslog(LOG_ERR, "select: %m");
 1537: 				break;	/* quit */
 1538: 			}
 1539: 			continue;	/* try again */
 1540: 		}
 1541: 		if(try_sendto(&writefds) < 0) {
 1542: 			syslog(LOG_ERR, "try_sendto: %m");
 1543: 			break;
 1544: 		}
 1545: #ifdef ENABLE_IPV6
 1546: 		if((s_ssdp6 >= 0) && FD_ISSET(s_ssdp6, &readfds))
 1547: 		{
 1548: 			sendername6_len = sizeof(struct sockaddr_in6);
 1549: 			n = recvfrom(s_ssdp6, buf, sizeof(buf), 0,
 1550: 			             (struct sockaddr *)&sendername6, &sendername6_len);
 1551: 			if(n<0)
 1552: 			{
 1553: 				 /* EAGAIN, EWOULDBLOCK, EINTR : silently ignore (try again next time)
 1554: 				  * other errors : log to LOG_ERR */
 1555: 				if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
 1556: 					syslog(LOG_ERR, "recvfrom: %m");
 1557: 			}
 1558: 			else
 1559: 			{
 1560: 				/* Parse and process the packet received */
 1561: 				/*printf("%.*s", n, buf);*/
 1562: 				i = ParseSSDPPacket(s_ssdp6, buf, n,
 1563: 				                    (struct sockaddr *)&sendername6, searched_device);
 1564: 				syslog(LOG_DEBUG, "** i=%d deltadev=%d **", i, deltadev);
 1565: 				if(i==0 || (i*deltadev < 0))
 1566: 				{
 1567: 					if(deltadev > 0)
 1568: 						syslog(LOG_NOTICE, "%d new devices added", deltadev);
 1569: 					else if(deltadev < 0)
 1570: 						syslog(LOG_NOTICE, "%d devices removed (good-bye!)", -deltadev);
 1571: 					deltadev = i;
 1572: 				}
 1573: 				else if((i*deltadev) >= 0)
 1574: 				{
 1575: 					deltadev += i;
 1576: 				}
 1577: 			}
 1578: 		}
 1579: #endif	/* ENABLE_IPV6 */
 1580: 		if((s_ssdp >= 0) && FD_ISSET(s_ssdp, &readfds))
 1581: 		{
 1582: 			sendername_len = sizeof(struct sockaddr_in);
 1583: 			n = recvfrom(s_ssdp, buf, sizeof(buf), 0,
 1584: 			             (struct sockaddr *)&sendername, &sendername_len);
 1585: 			if(n<0)
 1586: 			{
 1587: 				 /* EAGAIN, EWOULDBLOCK, EINTR : silently ignore (try again next time)
 1588: 				  * other errors : log to LOG_ERR */
 1589: 				if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
 1590: 					syslog(LOG_ERR, "recvfrom: %m");
 1591: 			}
 1592: 			else
 1593: 			{
 1594: 				/* Parse and process the packet received */
 1595: 				/*printf("%.*s", n, buf);*/
 1596: 				i = ParseSSDPPacket(s_ssdp, buf, n,
 1597: 				                    (struct sockaddr *)&sendername, searched_device);
 1598: 				syslog(LOG_DEBUG, "** i=%d deltadev=%d **", i, deltadev);
 1599: 				if(i==0 || (i*deltadev < 0))
 1600: 				{
 1601: 					if(deltadev > 0)
 1602: 						syslog(LOG_NOTICE, "%d new devices added", deltadev);
 1603: 					else if(deltadev < 0)
 1604: 						syslog(LOG_NOTICE, "%d devices removed (good-bye!)", -deltadev);
 1605: 					deltadev = i;
 1606: 				}
 1607: 				else if((i*deltadev) >= 0)
 1608: 				{
 1609: 					deltadev += i;
 1610: 				}
 1611: 			}
 1612: 		}
 1613: 		/* processing unix socket requests */
 1614: 		for(req = reqlisthead.lh_first; req;) {
 1615: 			reqnext = req->entries.le_next;
 1616: 			if((req->socket >= 0) && FD_ISSET(req->socket, &readfds)) {
 1617: 				processRequest(req);
 1618: 			}
 1619: 			if((req->socket >= 0) && FD_ISSET(req->socket, &writefds)) {
 1620: 				write_buffer(req);
 1621: 			}
 1622: 			if(req->socket < 0) {
 1623: 				LIST_REMOVE(req, entries);
 1624: 				free(req->output_buffer);
 1625: 				free(req);
 1626: 			}
 1627: 			req = reqnext;
 1628: 		}
 1629: 		/* processing new requests */
 1630: 		if(FD_ISSET(s_unix, &readfds))
 1631: 		{
 1632: 			struct reqelem * tmp;
 1633: 			int s = accept(s_unix, NULL, NULL);
 1634: 			if(s < 0) {
 1635: 				syslog(LOG_ERR, "accept(s_unix): %m");
 1636: 			} else {
 1637: 				syslog(LOG_INFO, "(s=%d) new request connection", s);
 1638: 				if(!set_non_blocking(s))
 1639: 					syslog(LOG_WARNING, "Failed to set new socket non blocking : %m");
 1640: 				tmp = malloc(sizeof(struct reqelem));
 1641: 				if(!tmp) {
 1642: 					syslog(LOG_ERR, "cannot allocate memory for request");
 1643: 					close(s);
 1644: 				} else {
 1645: 					memset(tmp, 0, sizeof(struct reqelem));
 1646: 					tmp->socket = s;
 1647: 					LIST_INSERT_HEAD(&reqlisthead, tmp, entries);
 1648: 				}
 1649: 			}
 1650: 		}
 1651: 		/* processing route/network interface config changes */
 1652: 		if((s_ifacewatch >= 0) && FD_ISSET(s_ifacewatch, &readfds)) {
 1653: 			ProcessInterfaceWatch(s_ifacewatch, s_ssdp, s_ssdp6);
 1654: 		}
 1655: 	}
 1656: 	syslog(LOG_DEBUG, "quitting...");
 1657: 	finalize_sendto();
 1658: 
 1659: 	/* closing and cleaning everything */
 1660: quit:
 1661: 	if(s_ssdp >= 0) {
 1662: 		close(s_ssdp);
 1663: 		s_ssdp = -1;
 1664: 	}
 1665: #ifdef ENABLE_IPV6
 1666: 	if(s_ssdp6 >= 0) {
 1667: 		close(s_ssdp6);
 1668: 		s_ssdp6 = -1;
 1669: 	}
 1670: #endif	/* ENABLE_IPV6 */
 1671: 	if(s_unix >= 0) {
 1672: 		close(s_unix);
 1673: 		s_unix = -1;
 1674: 		if(unlink(sockpath) < 0)
 1675: 			syslog(LOG_ERR, "unlink(%s): %m", sockpath);
 1676: 	}
 1677: 	if(s_ifacewatch >= 0) {
 1678: 		close(s_ifacewatch);
 1679: 		s_ifacewatch = -1;
 1680: 	}
 1681: 	/* empty LAN interface/address list */
 1682: 	while(lan_addrs.lh_first != NULL) {
 1683: 		lan_addr = lan_addrs.lh_first;
 1684: 		LIST_REMOVE(lan_addrs.lh_first, list);
 1685: 		free(lan_addr);
 1686: 	}
 1687: 	/* empty device list */
 1688: 	while(devlist != NULL) {
 1689: 		struct device * next = devlist->next;
 1690: 		free(devlist);
 1691: 		devlist = next;
 1692: 	}
 1693: 	/* empty service list */
 1694: 	while(servicelisthead.lh_first != NULL) {
 1695: 		struct service * serv = servicelisthead.lh_first;
 1696: 		LIST_REMOVE(servicelisthead.lh_first, entries);
 1697: 		free(serv->st);
 1698: 		free(serv->usn);
 1699: 		free(serv->server);
 1700: 		free(serv->location);
 1701: 		free(serv);
 1702: 	}
 1703: #ifndef NO_BACKGROUND_NO_PIDFILE
 1704: 	if(unlink(pidfilename) < 0)
 1705: 		syslog(LOG_ERR, "unlink(%s): %m", pidfilename);
 1706: #endif
 1707: 	closelog();
 1708: 	return ret;
 1709: }
 1710: 

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