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

📄 miniupnpd.c

📁 很小的linux下的upnp服务器端代码适合嵌入式系统
💻 C
📖 第 1 页 / 共 2 页
字号:
				v->port = atoi(argv[++i]);			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			break;		case 'P':			if(i+1 < argc)				pidfilename = argv[++i];			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			break;		case 'd':			debug_flag = 1;			break;		case 'w':			if(i+1 < argc)				presurl = argv[++i];			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			break;		case 'B':			if(i+2<argc)			{				downstream_bitrate = strtoul(argv[++i], 0, 0);				upstream_bitrate = strtoul(argv[++i], 0, 0);			}			else				fprintf(stderr, "Option -%c takes two arguments.\n", argv[i][1]);			break;		case 'a':			i++;			if(i+1 < argc)			{				int address_already_there = 0;				int j;				for(j=0; j<v->n_lan_addr; j++)				{					struct lan_addr_s tmpaddr;					parselanaddr(&tmpaddr, argv[i]);					/*if(0 == strcmp(v->lan_addr[j], argv[i]))*/					if(0 == strcmp(v->lan_addr[j].str, tmpaddr.str))						address_already_there = 1;				}				if(address_already_there)					break;				if(v->n_lan_addr < MAX_LAN_ADDR)				{					/*v->lan_addr[v->n_lan_addr++] = argv[i];*/					if(parselanaddr(&v->lan_addr[v->n_lan_addr], argv[i]) == 0)						v->n_lan_addr++;				}				else				{					fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n",				    	    MAX_LAN_ADDR, argv[i]);				}			}			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			break;		case 'f':			i++;	/* discarding, the config file is already read */			break;		default:			fprintf(stderr, "Unknown option: %s\n", argv[i]);		}	}	if(!ext_if_name || (v->n_lan_addr==0) || v->port<=0)	{		fprintf(stderr, "Usage:\n\t"		        "%s [-f config_file] [-i ext_ifname] [-o ext_ip]\n"				"\t\t[-a listening_ip] [-p port] [-d] [-L] [-U]\n"				/*"[-l logfile] " not functionnal */				"\t\t[-u uuid] [-s serial] [-m model_number] \n"				"\t\t[-t notify_interval] [-P pid_filename]\n"				"\t\t[-B down up] [-w url]\n"		        "\nNotes:\n\tThere can be one or several listening_ips.\n"		        "\tNotify interval is in seconds. Default is 30 seconds.\n"				"\tDefault pid file is %s.\n"				"\tWith -d miniupnpd will run as a standard program.\n"				"\t-L sets packet log in pf on.\n"				"\t-U causes miniupnpd to report system uptime instead "				"of daemon uptime.\n"				"\t-B sets bitrates reported by daemon in bits per second.\n"				"\t-w sets the presentation url. Default is http address on port 80\n",		        argv[0], pidfilename);		return 1;	}	if(debug_flag)	{		pid = getpid();	}	else	{		pid = daemonize();	}	openlog_option = LOG_PID|LOG_CONS;	if(debug_flag)	{		openlog_option |= LOG_PERROR;	/* also log on stderr */	}	openlog("miniupnpd", openlog_option, LOG_MINIUPNPD);	if(!debug_flag)	{		/* speed things up and ignore LOG_INFO and LOG_DEBUG */		setlogmask(LOG_UPTO(LOG_NOTICE));	}	if(checkforrunning(pidfilename) < 0)	{		syslog(LOG_ERR, "MiniUPnPd is already running. EXITING");		return 1;	}		writepidfile(pidfilename, pid);	set_startup_time(sysuptime);	/* presentation url */	if(presurl)	{		strncpy(presentationurl, presurl, PRESENTATIONURL_MAX_LEN);		presentationurl[PRESENTATIONURL_MAX_LEN-1] = '\0';	}	else	{		snprintf(presentationurl, PRESENTATIONURL_MAX_LEN,		         "http://%s:%d/", v->lan_addr[0].str, 80);	}	/* set signal handler */	memset(&sa, 0, sizeof(struct sigaction));	sa.sa_handler = sigterm;	if (sigaction(SIGTERM, &sa, NULL))	{		syslog(LOG_ERR, "Failed to set SIGTERM handler. EXITING");		return 1;	}	if (sigaction(SIGINT, &sa, NULL))	{		syslog(LOG_ERR, "Failed to set SIGINT handler. EXITING");		return 1;	}	return 0;}/* === main === *//* process HTTP or SSDP requests */intmain(int argc, char * * argv){	int i;	int sudp, shttpl;#ifdef ENABLE_NATPMP	int snatpmp;#endif	int snotify[MAX_LAN_ADDR];	LIST_HEAD(httplisthead, upnphttp) upnphttphead;	struct upnphttp * e = 0;	struct upnphttp * next;	fd_set readset;	/* for select() */	struct timeval timeout, timeofday, lasttimeofday = {0, 0};#ifdef USE_MINIUPNPDCTL	int sctl;	LIST_HEAD(ctlstructhead, ctlelem) ctllisthead;	struct ctlelem * ectl;	struct ctlelem * ectlnext;#endif	struct runtime_vars v;	/* variables used for the unused-rule cleanup process */	struct rule_state * rule_list = 0;	struct timeval checktime = {0, 0};	if(init(argc, argv, &v) != 0)		return 1;	LIST_INIT(&upnphttphead);#ifdef USE_MINIUPNPDCTL	LIST_INIT(&ctllisthead);#endif	/* open socket for SSDP connections */	sudp = OpenAndConfSSDPReceiveSocket(v.n_lan_addr, v.lan_addr);	if(sudp < 0)	{		syslog(LOG_ERR, "Failed to open socket for receiving SSDP. EXITING");		return 1;	}	/* open socket for HTTP connections. Listen on the 1st LAN address */	shttpl = OpenAndConfHTTPSocket(v.port);	if(shttpl < 0)	{		syslog(LOG_ERR, "Failed to open socket for HTTP. EXITING");		return 1;	}	syslog(LOG_NOTICE, "HTTP listening on port %d", v.port);	/* open socket for sending notifications */	if(OpenAndConfSSDPNotifySockets(snotify, v.lan_addr, v.n_lan_addr) < 0)	{		syslog(LOG_ERR, "Failed to open sockets for sending SSDP notify "		                "messages. EXITING");		return 1;	}#ifdef ENABLE_NATPMP	/* open socket for NAT PMP traffic */	snatpmp = OpenAndConfNATPMPSocket();	if(snatpmp<0)	{		syslog(LOG_ERR, "Failed to open socket for NAT PMP. EXITING");		return 1;	}	syslog(LOG_NOTICE, "Listening for NAT-PMP traffic on port %u", NATPMP_PORT);#endif	/* for miniupnpdctl */#ifdef USE_MINIUPNPDCTL	sctl = OpenAndConfCtlUnixSocket("/var/run/miniupnpd.ctl");#endif	/* main loop */	while(!quitting)	{		/* Check if we need to send SSDP NOTIFY messages and do it if		 * needed */		if(gettimeofday(&timeofday, 0) < 0)		{			syslog(LOG_ERR, "gettimeofday(): %m");			timeout.tv_sec = v.notify_interval;			timeout.tv_usec = 0;		}		else		{			/* the comparaison is not very precise but who cares ? */			if(timeofday.tv_sec >= (lasttimeofday.tv_sec + v.notify_interval))			{				SendSSDPNotifies2(snotify, v.lan_addr, v.n_lan_addr,				                  (unsigned short)v.port,				                  v.notify_interval << 1);				memcpy(&lasttimeofday, &timeofday, sizeof(struct timeval));				timeout.tv_sec = v.notify_interval;				timeout.tv_usec = 0;			}			else			{				timeout.tv_sec = lasttimeofday.tv_sec + v.notify_interval				                 - timeofday.tv_sec;				if(timeofday.tv_usec > lasttimeofday.tv_usec)				{					timeout.tv_usec = 1000000 + lasttimeofday.tv_usec					                  - timeofday.tv_usec;					timeout.tv_sec--;				}				else				{					timeout.tv_usec = lasttimeofday.tv_usec - timeofday.tv_usec;				}			}		}		/* remove unused rules */		if( v.clean_ruleset_interval		  && (timeofday.tv_sec >= checktime.tv_sec + v.clean_ruleset_interval))		{			if(rule_list)			{				remove_unused_rules(rule_list);				rule_list = NULL;			}			else			{				rule_list = get_upnp_rules_state_list(v.clean_ruleset_threshold);			}			memcpy(&checktime, &timeofday, sizeof(struct timeval));		}		/* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */		FD_ZERO(&readset);		FD_SET(sudp, &readset);		FD_SET(shttpl, &readset);		i = 0;	/* active HTTP connections count */		for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next)		{			if((e->socket >= 0) && (e->state <= 2))			{				FD_SET(e->socket, &readset);				i++;			}		}		/* for debug */#ifdef DEBUG		if(i > 1)		{			syslog(LOG_DEBUG, "%d active incoming HTTP connections", i);		}#endif#ifdef ENABLE_NATPMP		if(snatpmp >= 0)			FD_SET(snatpmp, &readset);#endif#ifdef USE_MINIUPNPDCTL		if(sctl >= 0)			FD_SET(sctl, &readset);		for(ectl = ctllisthead.lh_first; ectl; ectl = ectl->entries.le_next)		{			if(ectl->socket >= 0)				FD_SET(ectl->socket, &readset);		}#endif		if(select(FD_SETSIZE, &readset, 0, 0, &timeout) < 0)		{			if(quitting) goto shutdown;			syslog(LOG_ERR, "select(all): %m");			syslog(LOG_ERR, "Failed to select open sockets. EXITING");			return 1;	/* very serious cause of error */		}#ifdef USE_MINIUPNPDCTL		for(ectl = ctllisthead.lh_first; ectl;)		{			ectlnext =  ectl->entries.le_next;			if((ectl->socket >= 0) && FD_ISSET(ectl->socket, &readset))			{				char buf[256];				int l;				l = read(ectl->socket, buf, sizeof(buf));				if(l > 0)				{					/*write(ectl->socket, buf, l);*/					write_option_list(ectl->socket);					write_permlist(ectl->socket, upnppermlist, num_upnpperm);					write_upnphttp_details(ectl->socket, upnphttphead.lh_first);					write_ctlsockets_list(ectl->socket, ctllisthead.lh_first);					write_ruleset_details(ectl->socket);					/* close the socket */					close(ectl->socket);					ectl->socket = -1;				}				else				{					close(ectl->socket);					ectl->socket = -1;				}			}			if(ectl->socket < 0)			{				LIST_REMOVE(ectl, entries);				free(ectl);			}			ectl = ectlnext;		}		if((sctl >= 0) && FD_ISSET(sctl, &readset))		{			int s;			struct sockaddr_un clientname;			struct ctlelem * tmp;			socklen_t clientnamelen = sizeof(struct sockaddr_un);			//syslog(LOG_DEBUG, "sctl!");			s = accept(sctl, (struct sockaddr *)&clientname,			           &clientnamelen);			syslog(LOG_DEBUG, "sctl! : '%s'", clientname.sun_path);			tmp = malloc(sizeof(struct ctlelem));			tmp->socket = s;			LIST_INSERT_HEAD(&ctllisthead, tmp, entries);		}#endif#ifdef ENABLE_NATPMP		/* process NAT-PMP packets */		if((snatpmp >= 0) && FD_ISSET(snatpmp, &readset))		{			ProcessIncomingNATPMPPacket(snatpmp);		}#endif		/* process SSDP packets */		if(FD_ISSET(sudp, &readset))		{			/*syslog(LOG_INFO, "Received UDP Packet");*/			ProcessSSDPRequest(sudp, v.lan_addr, v.n_lan_addr,			                   (unsigned short)v.port);		}		/* process active HTTP connections */		/* LIST_FOREACH is not available under linux */		for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next)		{			if(  (e->socket >= 0) && (e->state <= 2)				&&(FD_ISSET(e->socket, &readset)) )			{				Process_upnphttp(e);			}		}		/* process incoming HTTP connections */		if(FD_ISSET(shttpl, &readset))		{			int shttp;			socklen_t clientnamelen;			struct sockaddr_in clientname;			clientnamelen = sizeof(struct sockaddr_in);			shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen);			if(shttp<0)			{				syslog(LOG_ERR, "accept(http): %m");			}			else			{				struct upnphttp * tmp = 0;				syslog(LOG_INFO, "HTTP connection from %s:%d",					inet_ntoa(clientname.sin_addr),					ntohs(clientname.sin_port) );				/*if (fcntl(shttp, F_SETFL, O_NONBLOCK) < 0) {					syslog(LOG_ERR, "fcntl F_SETFL, O_NONBLOCK");				}*/				/* Create a new upnphttp object and add it to				 * the active upnphttp object list */				tmp = New_upnphttp(shttp);				if(tmp)				{					LIST_INSERT_HEAD(&upnphttphead, tmp, entries);				}				else				{					syslog(LOG_ERR, "New_upnphttp() failed");					close(shttp);				}			}		}		/* delete finished HTTP connections */		for(e = upnphttphead.lh_first; e != NULL; )		{			next = e->entries.le_next;			if(e->state >= 100)			{				LIST_REMOVE(e, entries);				Delete_upnphttp(e);			}			e = next;		}	}shutdown:	/* close out open sockets */	while(upnphttphead.lh_first != NULL)	{		e = upnphttphead.lh_first;		LIST_REMOVE(e, entries);		Delete_upnphttp(e);	}	close(sudp);	close(shttpl);#ifdef ENABLE_NATPMP	close(snatpmp);#endif#ifdef USE_MINIUPNPDCTL	close(sctl);	if(unlink("/var/run/miniupnpd.ctl") < 0)	{		syslog(LOG_ERR, "unlink() %m");	}#endif		if(SendSSDPGoodbye(snotify, v.n_lan_addr) < 0)	{		syslog(LOG_ERR, "Failed to broadcast good-bye notifications");	}	for(i=0; i<v.n_lan_addr; i++)		close(snotify[i]);	if(unlink(pidfilename) < 0)	{		syslog(LOG_ERR, "Failed to remove pidfile %s: %m", pidfilename);	}	closelog();		freeoptions();		return 0;}

⌨️ 快捷键说明

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