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

📄 miniupnpc.c

📁 很小的linux下的upnp客户端代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: miniupnpc.c,v 1.45 2007/10/16 15:23:44 nanard Exp $ *//* Project : miniupnp * Author : Thomas BERNARD * copyright (c) 2005-2007 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENCE file. */#include <stdio.h>#include <stdlib.h>#include <string.h>#ifdef WIN32#include <winsock2.h>#include <Ws2tcpip.h>#include <io.h>#define snprintf _snprintf#define strncasecmp memicmp#define MAXHOSTNAMELEN 64#else#include <unistd.h>#include <sys/socket.h>#include <sys/types.h>#include <sys/param.h>#include <netinet/in.h>#include <arpa/inet.h>#include <poll.h>#include <netdb.h>#define closesocket close#endif#include "miniupnpc.h"#include "minissdpc.h"#include "miniwget.h"#include "minisoap.h"#include "minixml.h"#include "upnpcommands.h"/* Uncomment the following to transmit the msearch from the same port * as the UPnP multicast port. With WinXP this seems to result in the * responses to the msearch being lost, thus if things dont work then * comment this out. *//* #define TX_FROM_UPNP_PORT */#ifdef WIN32#define PRINT_SOCKET_ERROR(x)    printf("Socket error: %s, %d\n", x, WSAGetLastError());#else#define PRINT_SOCKET_ERROR(x) perror(x)#endif/* root description parsing */void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data){	struct xmlparser parser;	/* xmlparser object */	parser.xmlstart = buffer;	parser.xmlsize = bufsize;	parser.data = data;	parser.starteltfunc = IGDstartelt;	parser.endeltfunc = IGDendelt;	parser.datafunc = IGDdata;	parser.attfunc = 0;	parsexml(&parser);#ifndef NDEBUG	printIGD(data);#endif}/* Content-length: nnn */static int getcontentlenfromline(const char * p, int n){	static const char contlenstr[] = "content-length";	const char * p2 = contlenstr;	int a = 0;	while(*p2)	{		if(n==0)			return -1;		if(*p2 != *p && *p2 != (*p + 32))			return -1;		p++; p2++; n--;	}	if(n==0)		return -1;	if(*p != ':')		return -1;	p++; n--;	while(*p == ' ')	{		if(n==0)			return -1;		p++; n--;	}	while(*p >= '0' && *p <= '9')	{		if(n==0)			return -1;		a = (a * 10) + (*p - '0');		p++; n--;	}	return a;}static voidgetContentLengthAndHeaderLength(char * p, int n,                                int * contentlen, int * headerlen){	char * line;	int linelen;	int r;	line = p;	while(line < p + n)	{		linelen = 0;		while(line[linelen] != '\r' && line[linelen] != '\r')		{			if(line+linelen >= p+n)				return;			linelen++;		}		r = getcontentlenfromline(line, linelen);		if(r>0)			*contentlen = r;		line = line + linelen + 2;		if(line[0] == '\r' && line[1] == '\n')		{			*headerlen = (line - p) + 2;			return;		}	}}/* simpleUPnPcommand : * not so simple ! *  */int simpleUPnPcommand(int s, const char * url, const char * service,                      const char * action, struct UPNParg * args,                      char * buffer, int * bufsize){	struct sockaddr_in dest;	char hostname[MAXHOSTNAMELEN+1];	unsigned short port = 0;	char * path;	char soapact[128];	char soapbody[2048];	int soapbodylen;	char * buf;	int buffree;    int n;	int contentlen, headerlen;	/* for the response */	snprintf(soapact, sizeof(soapact), "%s#%s", service, action);	if(args==NULL)	{		soapbodylen = snprintf(soapbody, sizeof(soapbody),						"<?xml version=\"1.0\"?>\r\n"	    	              "<SOAP-ENV:Envelope "						  "xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" "						  "SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"						  "<SOAP-ENV:Body>"						  "<m:%s xmlns:m=\"%s\"/>"						  "</SOAP-ENV:Body></SOAP-ENV:Envelope>"					 	  "\r\n", action, service);	}	else	{		char * p;		const char * pe, * pv;		soapbodylen = snprintf(soapbody, sizeof(soapbody),						"<?xml version=\"1.0\"?>\r\n"	    	            "<SOAP-ENV:Envelope "						"xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" "						"SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"						"<SOAP-ENV:Body>"						"<m:%s xmlns:m=\"%s\">",						action, service);		p = soapbody + soapbodylen;		while(args->elt)		{			/* check that we are never overflowing the string... */			if(soapbody + sizeof(soapbody) <= p + 100)			{				/* we keep a margin of at least 100 bytes */				*bufsize = 0;				return -1;			}			*(p++) = '<';			pe = args->elt;			while(*pe)				*(p++) = *(pe++);			*(p++) = '>';			if((pv = args->val))			{				while(*pv)					*(p++) = *(pv++);			}			*(p++) = '<';			*(p++) = '/';			pe = args->elt;			while(*pe)				*(p++) = *(pe++);			*(p++) = '>';			args++;		}		*(p++) = '<';		*(p++) = '/';		*(p++) = 'm';		*(p++) = ':';		pe = action;		while(*pe)			*(p++) = *(pe++);		strncpy(p, "></SOAP-ENV:Body></SOAP-ENV:Envelope>\r\n",		        soapbody + sizeof(soapbody) - p);	}	if(!parseURL(url, hostname, &port, &path)) return -1;	if(s<0)	{		s = socket(PF_INET, SOCK_STREAM, 0);		dest.sin_family = AF_INET;		dest.sin_port = htons(port);		dest.sin_addr.s_addr = inet_addr(hostname);		if(connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr))<0)		{			PRINT_SOCKET_ERROR("connect");			*bufsize = 0;			return -1;		}	}	n = soapPostSubmit(s, path, hostname, port, soapact, soapbody);	contentlen = -1;	headerlen = -1;	buf = buffer;	buffree = *bufsize;	*bufsize = 0;	while ((n = ReceiveData(s, buf, buffree, 5000)) > 0) {		buffree -= n;		buf += n;		*bufsize += n;		getContentLengthAndHeaderLength(buffer, *bufsize,		                                &contentlen, &headerlen);#ifdef DEBUG		printf("n=%d bufsize=%d ContLen=%d HeadLen=%d\n",		       n, *bufsize, contentlen, headerlen);#endif		if(contentlen > 0 && headerlen > 0 && *bufsize >= contentlen+headerlen)			break;	}		closesocket(s);	return -1;}/* parseMSEARCHReply() * the last 4 arguments are filled during the parsing : *    - location/locationsize : "location:" field of the SSDP reply packet *    - st/stsize : "st:" field of the SSDP reply packet. * The strings are NOT null terminated */static voidparseMSEARCHReply(const char * reply, int size,                  const char * * location, int * locationsize,			      const char * * st, int * stsize){	int a, b, i;	i = 0;	a = i;	/* start of the line */	b = 0;	while(i<size)	{		switch(reply[i])		{		case ':':				if(b==0)				{					b = i; /* end of the "header" */					/*for(j=a; j<b; j++)					{						putchar(reply[j]);					}					*/				}				break;		case '\x0a':		case '\x0d':				if(b!=0)				{					/*for(j=b+1; j<i; j++)					{						putchar(reply[j]);					}					putchar('\n');*/					do { b++; } while(reply[b]==' ');					if(0==strncasecmp(reply+a, "location", 8))					{						*location = reply+b;						*locationsize = i-b;					}					else if(0==strncasecmp(reply+a, "st", 2))					{						*st = reply+b;						*stsize = i-b;					}					b = 0;				}				a = i+1;				break;		default:				break;		}		i++;	}}/* port upnp discover : SSDP protocol */#define PORT (1900)#define UPNP_MCAST_ADDR "239.255.255.250"/* upnpDiscover() : * return a chained list of all devices found or NULL if * no devices was found. * It is up to the caller to free the chained list * delay is in millisecond (poll) */struct UPNPDev * upnpDiscover(int delay, const char * multicastif){	struct UPNPDev * tmp;	struct UPNPDev * devlist = 0;	int opt = 1;	static const char MSearchMsgFmt[] = 	"M-SEARCH * HTTP/1.1\r\n"	"HOST: " UPNP_MCAST_ADDR ":" "1900" "\r\n"	"ST: %s\r\n"	"MAN: \"ssdp:discover\"\r\n"	"MX: 3\r\n"	"\r\n";	static const char * const deviceList[] = {		"urn:schemas-upnp-org:device:InternetGatewayDevice:1",		"urn:schemas-upnp-org:service:WANIPConnection:1",		"urn:schemas-upnp-org:service:WANPPPConnection:1",		"upnp:rootdevice",		0	};	int deviceIndex = 0;	char bufr[1536];	/* reception and emission buffer */	int sudp;	int n;	struct sockaddr_in sockudp_r, sockudp_w;#ifndef WIN32	/* first try to get infos from minissdpd ! */	devlist = getDevicesFromMiniSSDPD(deviceList[0], "/var/run/minissdpd.sock");	if(devlist)		return devlist;#endif	/* fallback to direct discovery */#ifdef WIN32	sudp = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);#else	sudp = socket(PF_INET, SOCK_DGRAM, 0);#endif	if(sudp < 0)

⌨️ 快捷键说明

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