⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 minissdp.c

📁 很小的linux下的upnp服务器端代码适合嵌入式系统
💻 C
字号:
/* $Id: minissdp.c,v 1.9 2007/10/31 18:37:12 nanard Exp $ *//* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */#include <stdio.h>#include <string.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <syslog.h>#include "config.h"#include "upnpdescstrings.h"#include "miniupnpdpath.h"#include "upnphttp.h"#include "upnpglobalvars.h"#include "minissdp.h"/* SSDP ip/port */#define SSDP_PORT (1900)#define SSDP_MCAST_ADDR ("239.255.255.250")static intAddMulticastMembership(int s, in_addr_t ifaddr/*const char * ifaddr*/){	struct ip_mreq imr;	/* Ip multicast membership */    /* setting up imr structure */    imr.imr_multiaddr.s_addr = inet_addr(SSDP_MCAST_ADDR);    /*imr.imr_interface.s_addr = htonl(INADDR_ANY);*/    imr.imr_interface.s_addr = ifaddr;	/*inet_addr(ifaddr);*/		if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&imr, sizeof(struct ip_mreq)) < 0)	{        syslog(LOG_ERR, "setsockopt(udp, IP_ADD_MEMBERSHIP): %m");		return -1;    }	return 0;}intOpenAndConfSSDPReceiveSocket(int n_lan_addr,							 struct lan_addr_s * lan_addr){	int s;	struct sockaddr_in sockname;		if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0)	{		syslog(LOG_ERR, "socket(udp): %m");		return -1;	}			memset(&sockname, 0, sizeof(struct sockaddr_in));    sockname.sin_family = AF_INET;    sockname.sin_port = htons(SSDP_PORT);	/* NOTE : it seems it doesnt work when binding on the specific address */    /*sockname.sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);*/    sockname.sin_addr.s_addr = htonl(INADDR_ANY);    /*sockname.sin_addr.s_addr = inet_addr(ifaddr);*/    if(bind(s, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in)) < 0)	{		syslog(LOG_ERR, "bind(udp): %m");		close(s);		return -1;    }	while(n_lan_addr>0)	{		n_lan_addr--;		if(AddMulticastMembership(s, lan_addr[n_lan_addr].addr.s_addr) < 0)		{			syslog(LOG_WARNING,			       "Failed to add multicast membership for address %s", 			       lan_addr[n_lan_addr].str );		}	}	return s;}/* open the UDP socket used to send SSDP notifications to * the multicast group reserved for them */static intOpenAndConfSSDPNotifySocket(in_addr_t addr){	int s;	unsigned char loopchar = 0;	int bcast = 1;	struct in_addr mc_if;	struct sockaddr_in sockname;		if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0)	{		syslog(LOG_ERR, "socket(udp_notify): %m");		return -1;	}	mc_if.s_addr = addr;	/*inet_addr(addr);*/	if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopchar, sizeof(loopchar)) < 0)	{		syslog(LOG_ERR, "setsockopt(udp_notify, IP_MULTICAST_LOOP): %m");		close(s);		return -1;	}	if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char *)&mc_if, sizeof(mc_if)) < 0)	{		syslog(LOG_ERR, "setsockopt(udp_notify, IP_MULTICAST_IF): %m");		close(s);		return -1;	}		if(setsockopt(s, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast)) < 0)	{		syslog(LOG_ERR, "setsockopt(udp_notify, SO_BROADCAST): %m");		close(s);		return -1;	}	memset(&sockname, 0, sizeof(struct sockaddr_in));    sockname.sin_family = AF_INET;    sockname.sin_addr.s_addr = addr;	/*inet_addr(addr);*/    if (bind(s, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in)) < 0)	{		syslog(LOG_ERR, "bind(udp_notify): %m");		close(s);		return -1;    }	return s;}intOpenAndConfSSDPNotifySockets(int * sockets,                             struct lan_addr_s * lan_addr, int n_lan_addr){	int i, j;	for(i=0; i<n_lan_addr; i++)	{		sockets[i] = OpenAndConfSSDPNotifySocket(lan_addr[i].addr.s_addr);		if(sockets[i] < 0)		{			for(j=0; j<i; j++)			{				close(sockets[j]);				sockets[j] = -1;			}			return -1;		}	}	return 0;}/* * response from a LiveBox (Wanadoo)HTTP/1.1 200 OKCACHE-CONTROL: max-age=1800DATE: Thu, 01 Jan 1970 04:03:23 GMTEXT:LOCATION: http://192.168.0.1:49152/gatedesc.xmlSERVER: Linux/2.4.17, UPnP/1.0, Intel SDK for UPnP devices /1.2ST: upnp:rootdeviceUSN: uuid:75802409-bccb-40e7-8e6c-fa095ecce13e::upnp:rootdevice * response from a Linksys 802.11b :HTTP/1.1 200 OKCache-Control:max-age=120Location:http://192.168.5.1:5678/rootDesc.xmlServer:NT/5.0 UPnP/1.0ST:upnp:rootdeviceUSN:uuid:upnp-InternetGatewayDevice-1_0-0090a2777777::upnp:rootdeviceEXT: *//* not really an SSDP "announce" as it is the response * to a SSDP "M-SEARCH" */static voidSendSSDPAnnounce2(int s, struct sockaddr_in sockname,                  const char * st, int st_len, const char * suffix,                  const char * host, unsigned short port){	int l, n;	char buf[512];	/* TODO :	 * follow guideline from document "UPnP Device Architecture 1.0"	 * put in uppercase.	 * DATE: is recommended	 * SERVER: OS/ver UPnP/1.0 miniupnpd/1.0	 * - check what to put in the 'Cache-Control' header 	 * */	l = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\n"		"Cache-Control: max-age=120\r\n"		"ST: %.*s%s\r\n"		"USN: %s::%.*s%s\r\n"		"EXT:\r\n"		"Server: " MINIUPNPD_SERVER_STRING "\r\n"		"Location: http://%s:%u" ROOTDESC_PATH "\r\n"		"\r\n",		st_len, st, suffix,		uuidvalue, st_len, st, suffix,		host, (unsigned int)port);	n = sendto(s, buf, l, 0,	           (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );	if(n < 0)	{		syslog(LOG_ERR, "sendto(udp): %m");	}}static const char * const known_service_types[] ={	"upnp:rootdevice",	"urn:schemas-upnp-org:device:InternetGatewayDevice:",	"urn:schemas-upnp-org:device:WANConnectionDevice:",	"urn:schemas-upnp-org:device:WANDevice:",	"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:",	"urn:schemas-upnp-org:service:WANIPConnection:",	"urn:schemas-upnp-org:service:WANPPPConnection:",	"urn:schemas-upnp-org:service:Layer3Forwarding:",	0};static voidSendSSDPNotifies(int s, const char * host, unsigned short port,                 unsigned int lifetime){	struct sockaddr_in sockname;	int l, n, i=0;	char bufr[512];	memset(&sockname, 0, sizeof(struct sockaddr_in));	sockname.sin_family = AF_INET;	sockname.sin_port = htons(SSDP_PORT);	sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);	while(known_service_types[i])	{		l = snprintf(bufr, sizeof(bufr), 				"NOTIFY * HTTP/1.1\r\n"				"HOST:%s:%d\r\n"				"Cache-Control:max-age=%u\r\n"				"Location:http://%s:%d" ROOTDESC_PATH"\r\n"				/*"Server:miniupnpd/1.0 UPnP/1.0\r\n"*/				"Server: " MINIUPNPD_SERVER_STRING "\r\n"				"NT:%s%s\r\n"				"USN:%s::%s%s\r\n"				"NTS:ssdp:alive\r\n"				"\r\n",				SSDP_MCAST_ADDR, SSDP_PORT,				lifetime,				host, port,				known_service_types[i], (i==0?"":"1"),				uuidvalue, known_service_types[i], (i==0?"":"1") );		if(l>=sizeof(bufr))		{			syslog(LOG_WARNING, "SendSSDPNotifies(): truncated output");			l = sizeof(bufr);		}		n = sendto(s, bufr, l, 0,			(struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );		if(n < 0)		{			syslog(LOG_ERR, "sendto(udp_notify): %m");		}		i++;	}}voidSendSSDPNotifies2(int * sockets, struct lan_addr_s * lan_addr, int n_lan_addr,                  unsigned short port,                  unsigned int lifetime){	int i;	for(i=0; i<n_lan_addr; i++)	{		SendSSDPNotifies(sockets[i], lan_addr[i].str, port, lifetime);	}}/* ProcessSSDPRequest() * process SSDP M-SEARCH requests and responds to them */voidProcessSSDPRequest(int s, struct lan_addr_s * lan_addr, int n_lan_addr,                   unsigned short port){	int n;	char bufr[1500];	socklen_t len_r;	struct sockaddr_in sendername;	int i, l;	int lan_addr_index = 0;	char * st = 0;	int st_len = 0;	len_r = sizeof(struct sockaddr_in);	n = recvfrom(s, bufr, sizeof(bufr), 0,	             (struct sockaddr *)&sendername, &len_r);	if(n < 0)	{		syslog(LOG_ERR, "recvfrom(udp): %m");		return;	}	if(memcmp(bufr, "NOTIFY", 6) == 0)	{		/* ignore NOTIFY packets. We could log the sender and device type */		return;	}	else if(memcmp(bufr, "M-SEARCH", 8) == 0)	{		i = 0;		while(i < n)		{			while(bufr[i] != '\r' || bufr[i+1] != '\n')				i++;			i += 2;			if(strncasecmp(bufr+i, "st:", 3) == 0)			{				st = bufr+i+3;				st_len = 0;				while(*st == ' ' || *st == '\t') st++;				while(st[st_len]!='\r' && st[st_len]!='\n') st_len++;				/*syslog(LOG_INFO, "ST: %.*s", st_len, st);*/				/*j = 0;*/				/*while(bufr[i+j]!='\r') j++;*/				/*syslog(LOG_INFO, "%.*s", j, bufr+i);*/			}		}		/*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s:%d",	           inet_ntoa(sendername.sin_addr),	           ntohs(sendername.sin_port) );*/		if(st)		{			/* TODO : doesnt answer at once but wait for a random time */			syslog(LOG_INFO, "SSDP M-SEARCH from %s:%d ST: %.*s",	        	   inet_ntoa(sendername.sin_addr),	           	   ntohs(sendername.sin_port),				   st_len, st);			/* find in which sub network the client is */			for(i = 0; i<n_lan_addr; i++)			{				if( (sendername.sin_addr.s_addr & lan_addr[i].mask.s_addr)				   == (lan_addr[i].addr.s_addr & lan_addr[i].mask.s_addr))				{					lan_addr_index = i;					break;				}			}			/* Responds to request with a device as ST header */			for(i = 0; known_service_types[i]; i++)			{				l = (int)strlen(known_service_types[i]);				if(l<=st_len && (0 == memcmp(st, known_service_types[i], l)))				{					SendSSDPAnnounce2(s, sendername,					                  st, st_len, "",					                  lan_addr[lan_addr_index].str, port);					break;				}			}			/* Responds to request with ST: ssdp:all */			/* strlen("ssdp:all") == 8 */			if(st_len==8 && (0 == memcmp(st, "ssdp:all", 8)))			{				for(i=0; known_service_types[i]; i++)				{					l = (int)strlen(known_service_types[i]);					SendSSDPAnnounce2(s, sendername,					                  known_service_types[i], l, i==0?"":"1",					                  lan_addr[lan_addr_index].str, port);				}			}			/* responds to request by UUID value */			l = (int)strlen(uuidvalue);			if(l==st_len && (0 == memcmp(st, uuidvalue, l)))			{				SendSSDPAnnounce2(s, sendername, st, st_len, "",				                  lan_addr[lan_addr_index].str, port);			}		}		else		{			syslog(LOG_INFO, "Invalid SSDP M-SEARCH from %s:%d",	        	   inet_ntoa(sendername.sin_addr), ntohs(sendername.sin_port));		}	}	else	{		syslog(LOG_NOTICE, "Unknown udp packet received from %s:%d",		       inet_ntoa(sendername.sin_addr), ntohs(sendername.sin_port));	}}/* This will broadcast ssdp:byebye notifications to inform  * the network that UPnP is going down. */intSendSSDPGoodbye(int * sockets, int n_sockets){	struct sockaddr_in sockname;	int n, l;	int i, j;	char bufr[512];    memset(&sockname, 0, sizeof(struct sockaddr_in));    sockname.sin_family = AF_INET;    sockname.sin_port = htons(SSDP_PORT);    sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);	for(j=0; j<n_sockets; j++)	{	    for(i=0; known_service_types[i]; i++)	    {	        l = snprintf(bufr, sizeof(bufr),	                 "NOTIFY * HTTP/1.1\r\n"	                 "HOST:%s:%d\r\n"	                 "NT:%s%s\r\n"	                 "USN:%s::%s%s\r\n"	                 "NTS:ssdp:byebye\r\n"	                 "\r\n",	                 SSDP_MCAST_ADDR, SSDP_PORT,					 known_service_types[i], (i==0?"":"1"),	                 uuidvalue, known_service_types[i], (i==0?"":"1"));	        n = sendto(sockets[j], bufr, l, 0,	                   (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );			if(n < 0)			{				syslog(LOG_ERR, "sendto(udp_shutdown): %m");				return -1;			}    	}	}	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -