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

📄 miniupnpd.c

📁 很小的linux下的upnp服务器端代码适合嵌入式系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: miniupnpd.c,v 1.93 2007/11/02 23:56:56 nanard Exp $ *//* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2007 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */#include <stdlib.h>#include <unistd.h>#include <string.h>#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <fcntl.h>#include <sys/file.h>#include <syslog.h>#include <sys/time.h>#include <time.h>#include <signal.h>#include <sys/param.h>#if defined(sun)#include <kstat.h>#else/* for BSD's sysctl */#include <sys/sysctl.h>#endif/* unix sockets *//*#define USE_MINIUPNPDCTL*/#include "config.h"#ifdef USE_MINIUPNPDCTL#include <sys/un.h>#endif#include "upnpglobalvars.h"#include "upnphttp.h"#include "upnpdescgen.h"#include "miniupnpdpath.h"#include "getifaddr.h"#include "daemonize.h"#include "upnpsoap.h"#include "options.h"#include "minissdp.h"#include "upnpredirect.h"#include "miniupnpdtypes.h"#ifdef ENABLE_NATPMP#include "natpmp.h"#endif#ifdef USE_MINIUPNPDCTLstruct ctlelem {	int socket;	LIST_ENTRY(ctlelem) entries;};#endif/* MAX_LAN_ADDR : maximum number of interfaces * to listen to SSDP traffic */#define MAX_LAN_ADDR (4)static volatile int quitting = 0;/* OpenAndConfHTTPSocket() : * setup the socket used to handle incoming HTTP connections. */static intOpenAndConfHTTPSocket(unsigned short port){	int s;	int i = 1;	struct sockaddr_in listenname;	if( (s = socket(PF_INET, SOCK_STREAM, 0)) < 0)	{		syslog(LOG_ERR, "socket(http): %m");		return -1;	}	if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)	{		syslog(LOG_WARNING, "setsockopt(http, SO_REUSEADDR): %m");	}	memset(&listenname, 0, sizeof(struct sockaddr_in));	listenname.sin_family = AF_INET;	listenname.sin_port = htons(port);	listenname.sin_addr.s_addr = htonl(INADDR_ANY);	if(bind(s, (struct sockaddr *)&listenname, sizeof(struct sockaddr_in)) < 0)	{		syslog(LOG_ERR, "bind(http): %m");		close(s);		return -1;	}	if(listen(s, 6) < 0)	{		syslog(LOG_ERR, "listen(http): %m");		close(s);		return -1;	}	return s;}/* Functions used to communicate with miniupnpdctl */#ifdef USE_MINIUPNPDCTLstatic intOpenAndConfCtlUnixSocket(const char * path){	struct sockaddr_un localun;	int s;	s = socket(AF_UNIX, SOCK_STREAM, 0);	localun.sun_family = AF_UNIX;	strncpy(localun.sun_path, path,	          sizeof(localun.sun_path));	if(bind(s, (struct sockaddr *)&localun,	        sizeof(struct sockaddr_un)) < 0)	{		syslog(LOG_ERR, "bind(sctl): %m");		close(s);		s = -1;	}	else if(listen(s, 5) < 0)	{		syslog(LOG_ERR, "listen(sctl): %m");		close(s);		s = -1;	}	return s;}static voidwrite_upnphttp_details(int fd, struct upnphttp * e){	char buffer[256];	int len;	while(e)	{		len = snprintf(buffer, sizeof(buffer),		               "%d %d %s req_buf=%p(%dbytes) res_buf=%p(%dbytes alloc)\n",		               e->socket, e->state, e->HttpVer,		               e->req_buf, e->req_buflen,		               e->res_buf, e->res_buf_alloclen);		write(fd, buffer, len);		e = e->entries.le_next;	}}static voidwrite_ctlsockets_list(int fd, struct ctlelem * e){	char buffer[256];	int len;	while(e)	{		len = snprintf(buffer, sizeof(buffer),		               "struct ctlelem: socket=%d\n", e->socket);		write(fd, buffer, len);		e = e->entries.le_next;	}}static voidwrite_option_list(int fd){	char buffer[256];	int len;	int i;	for(i=0; i<num_options; i++)	{		len = snprintf(buffer, sizeof(buffer),		               "opt=%02d %s\n",		               ary_options[i].id, ary_options[i].value);		write(fd, buffer, len);	}}#endif/* Handler for the SIGTERM signal (kill) */static voidsigterm(int sig){	/*int save_errno = errno;*/	signal(sig, SIG_IGN);	syslog(LOG_NOTICE, "received signal %d, good-bye", sig);	quitting = 1;	/*errno = save_errno;*/}/* record the startup time, for returning uptime */static voidset_startup_time(int sysuptime){	startup_time = time(NULL);	if(sysuptime)	{		/* use system uptime instead of daemon uptime */#if defined(__linux__)		char buff[64];		int uptime, fd;		fd = open("/proc/uptime", O_RDONLY);		if(fd < 0)		{			syslog(LOG_ERR, "open(\"/proc/uptime\" : %m");		}		else		{			memset(buff, 0, sizeof(buff));			read(fd, buff, sizeof(buff) - 1);			uptime = atoi(buff);			syslog(LOG_INFO, "system uptime is %d seconds", uptime);			close(fd);			startup_time -= uptime;		}#elif defined(SOLARIS_KSTATS)		kstat_ctl_t *kc;		kc = kstat_open();		if(kc != NULL)		{			kstat_t *ksp;			ksp = kstat_lookup(kc, "unix", 0, "system_misc");			if(ksp && (kstat_read(kc, ksp, NULL) != -1))			{				void *ptr = kstat_data_lookup(ksp, "boot_time");				if(ptr)					memcpy(&startup_time, ptr, sizeof(startup_time));				else					syslog(LOG_ERR, "cannot find boot_time kstat");			}			else				syslog(LOG_ERR, "cannot open kstats for unix/0/system_misc: %m");			kstat_close(kc);		}#else		struct timeval boottime;		size_t size = sizeof(boottime);		int name[2] = { CTL_KERN, KERN_BOOTTIME };		if(sysctl(name, 2, &boottime, &size, NULL, 0) < 0)		{			syslog(LOG_ERR, "sysctl(\"kern.boottime\") failed");		}		else		{			startup_time = boottime.tv_sec;		}#endif	}}/* structure containing variables used during "main loop" * that are filled during the init */struct runtime_vars {	/* LAN IP addresses for SSDP traffic and HTTP */	int n_lan_addr;	/*const char * lan_addr[MAX_LAN_ADDR];*/	struct lan_addr_s lan_addr[MAX_LAN_ADDR];	int port;	/* HTTP Port */	int notify_interval;	/* seconds between SSDP announces */	/* unused rules cleaning related variables : */	int clean_ruleset_threshold;	/* threshold for removing unused rules */	int clean_ruleset_interval;		/* (minimum) interval between checks */};/* parselanaddr() * parse address with mask * ex: 192.168.1.1/24 * return value :  *    0 : ok *   -1 : error */static intparselanaddr(struct lan_addr_s * lan_addr, const char * str){	const char * p;	int nbits = 24;	int n;	p = str;	while(*p && *p != '/')		p++;	if(*p == '/')		nbits = atoi(p+1);	n = p - str;	if(n>15)	{		fprintf(stderr, "Error parsing address/mask : %s\n", str);		return -1;	}	memcpy(lan_addr->str, str, n);	lan_addr->str[n] = '\0';	if(!inet_aton(lan_addr->str, &lan_addr->addr))	{		fprintf(stderr, "Error parsing address/mask : %s\n", str);		return -1;	}	lan_addr->mask.s_addr = htonl(nbits ? (0xffffffff << (32 - nbits)) : 0);	return 0;}/* init phase : * 1) read configuration file * 2) read command line arguments * 3) daemonize * 4) open syslog * 5) check and write pid file * 6) set startup time stamp * 7) compute presentation URL * 8) set signal handlers */static intinit(int argc, char * * argv, struct runtime_vars * v){	int i;	int pid;	int debug_flag = 0;	int options_flag = 0;	int openlog_option;	struct sigaction sa;	/*const char * logfilename = 0;*/	const char * presurl = 0;	const char * optionsfile = "/etc/miniupnpd.conf";	/* first check if "-f" option is used */	for(i=2; i<argc; i++)	{		if(0 == strcmp(argv[i-1], "-f"))		{			optionsfile = argv[i];			options_flag = 1;			break;		}	}	/* set initial values */	v->n_lan_addr = 0;	v->port = -1;	v->notify_interval = 30;	/* seconds between SSDP announces */	v->clean_ruleset_threshold = 20;	v->clean_ruleset_interval = 0;	/* interval between ruleset check. 0=disabled */	/* read options file first since	 * command line arguments have final say */	if(readoptionsfile(optionsfile) < 0)	{		/* only error if file exists or using -f */		if(access(optionsfile, F_OK) == 0 || options_flag)			fprintf(stderr, "Error reading configuration file %s\n", optionsfile);	}	else	{		for(i=0; i<num_options; i++)		{			switch(ary_options[i].id)			{			case UPNPEXT_IFNAME:				ext_if_name = ary_options[i].value;				break;			case UPNPEXT_IP:				use_ext_ip_addr = ary_options[i].value;				break;			case UPNPLISTENING_IP:				if(v->n_lan_addr < MAX_LAN_ADDR)				{					/*v->lan_addr[v->n_lan_addr++] = ary_options[i].value;*/					if(parselanaddr(&v->lan_addr[v->n_lan_addr],					             ary_options[i].value) == 0)						v->n_lan_addr++;				}				else				{					fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n",			    		    MAX_LAN_ADDR, ary_options[i].value);				}				break;			case UPNPPORT:				v->port = atoi(ary_options[i].value);				break;			case UPNPBITRATE_UP:				upstream_bitrate = strtoul(ary_options[i].value, 0, 0);				break;			case UPNPBITRATE_DOWN:				downstream_bitrate = strtoul(ary_options[i].value, 0, 0);				break;			case UPNPPRESENTATIONURL:				presurl = ary_options[i].value;				break;			case UPNPNOTIFY_INTERVAL:				v->notify_interval = atoi(ary_options[i].value);				break;			case UPNPSYSTEM_UPTIME:				if(strcmp(ary_options[i].value, "yes") == 0)					sysuptime = 1;				break;			case UPNPPACKET_LOG:				if(strcmp(ary_options[i].value, "yes") == 0)					logpackets = 1;				break;			case UPNPUUID:				strncpy(uuidvalue+5, ary_options[i].value,				        strlen(uuidvalue+5) + 1);				break;			case UPNPSERIAL:				strncpy(serialnumber, ary_options[i].value, SERIALNUMBER_MAX_LEN);				serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0';				break;							case UPNPMODEL_NUMBER:				strncpy(modelnumber, ary_options[i].value, MODELNUMBER_MAX_LEN);				modelnumber[MODELNUMBER_MAX_LEN-1] = '\0';				break;			case UPNPCLEANTHRESHOLD:				v->clean_ruleset_threshold = atoi(ary_options[i].value);				break;			case UPNPCLEANINTERVAL:				v->clean_ruleset_interval = atoi(ary_options[i].value);				break;			default:				fprintf(stderr, "Unknown option in file %s\n",				        optionsfile);			}		}	}	/* command line arguments processing */	for(i=1; i<argc; i++)	{		if(argv[i][0]!='-')		{			fprintf(stderr, "Unknown option: %s\n", argv[i]);		}		else switch(argv[i][1])		{		case 'o':			if(i+1 < argc)				use_ext_ip_addr = argv[++i];			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			break;		case 't':			if(i+1 < argc)				v->notify_interval = atoi(argv[++i]);			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			break;		case 'u':			if(i+1 < argc)				strncpy(uuidvalue+5, argv[++i], strlen(uuidvalue+5) + 1);			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			break;		case 's':			if(i+1 < argc)				strncpy(serialnumber, argv[++i], SERIALNUMBER_MAX_LEN);			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0';			break;		case 'm':			if(i+1 < argc)				strncpy(modelnumber, argv[++i], MODELNUMBER_MAX_LEN);			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			modelnumber[MODELNUMBER_MAX_LEN-1] = '\0';			break;					case 'U':			sysuptime = 1;			break;		/*case 'l':			logfilename = argv[++i];			break;*/		case 'L':			logpackets = 1;			break;		case 'i':			if(i+1 < argc)				ext_if_name = argv[++i];			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			break;		case 'p':			if(i+1 < argc)

⌨️ 快捷键说明

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