miniupnpc-1.9.20140610/Makefile010064400017500000024000000225321234555371300151170ustar00nanardstaff# $Id: Makefile,v 1.108 2014/06/10 09:51:33 nanard Exp $ # MiniUPnP Project # http://miniupnp.free.fr/ # http://miniupnp.tuxfamily.org/ # https://github.com/miniupnp/miniupnp # (c) 2005-2014 Thomas Bernard # to install use : # $ make DESTDIR=/tmp/dummylocation install # or # $ INSTALLPREFIX=/usr/local make install # or # $ make install (default INSTALLPREFIX is /usr) OS = $(shell uname -s) VERSION = $(shell cat VERSION) ifeq ($(OS), Darwin) JARSUFFIX=mac endif ifeq ($(OS), Linux) JARSUFFIX=linux endif ifneq (,$(findstring NT-5.1,$(OS))) JARSUFFIX=win32 endif HAVE_IPV6 ?= yes export HAVE_IPV6 CC ?= gcc #AR = gar #CFLAGS = -O -g -DDEBUG CFLAGS ?= -O CFLAGS += -Wall CFLAGS += -W -Wstrict-prototypes CFLAGS += -fno-common CFLAGS += -DMINIUPNPC_SET_SOCKET_TIMEOUT CFLAGS += -DMINIUPNPC_GET_SRC_ADDR CFLAGS += -D_BSD_SOURCE -D_POSIX_C_SOURCE=1 CFLAGS += -ansi # -DNO_GETADDRINFO INSTALL = install SH = /bin/sh JAVA = java # see http://code.google.com/p/jnaerator/ #JNAERATOR = jnaerator-0.9.7.jar #JNAERATOR = jnaerator-0.9.8-shaded.jar #JNAERATORARGS = -library miniupnpc #JNAERATOR = jnaerator-0.10-shaded.jar JNAERATOR = jnaerator-0.11-shaded.jar JNAERATORARGS = -mode StandaloneJar -runtime JNAerator -library miniupnpc JNAERATORBASEURL = http://jnaerator.googlecode.com/files/ ifeq (SunOS, $(OS)) LDFLAGS=-lsocket -lnsl -lresolv endif # APIVERSION is used to build SONAME APIVERSION = 10 SRCS = igd_desc_parse.c miniupnpc.c minixml.c minisoap.c miniwget.c \ upnpc.c upnpcommands.c upnpreplyparse.c testminixml.c \ minixmlvalid.c testupnpreplyparse.c minissdpc.c \ upnperrors.c testigddescparse.c testminiwget.c \ connecthostport.c portlistingparse.c receivedata.c LIBOBJS = miniwget.o minixml.o igd_desc_parse.o minisoap.o \ miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \ connecthostport.o portlistingparse.o receivedata.o ifneq ($(OS), AmigaOS) CFLAGS := -fPIC $(CFLAGS) LIBOBJS := $(LIBOBJS) minissdpc.o endif OBJS = $(patsubst %.c,%.o,$(SRCS)) # HEADERS to install HEADERS = miniupnpc.h miniwget.h upnpcommands.h igd_desc_parse.h \ upnpreplyparse.h upnperrors.h miniupnpctypes.h \ portlistingparse.h \ declspec.h # library names LIBRARY = libminiupnpc.a ifeq ($(OS), Darwin) SHAREDLIBRARY = libminiupnpc.dylib SONAME = $(basename $(SHAREDLIBRARY)).$(APIVERSION).dylib CFLAGS := -DMACOSX -D_DARWIN_C_SOURCE $(CFLAGS) else ifeq ($(JARSUFFIX), win32) SHAREDLIBRARY = miniupnpc.dll else # Linux/BSD/etc. SHAREDLIBRARY = libminiupnpc.so SONAME = $(SHAREDLIBRARY).$(APIVERSION) endif endif EXECUTABLES = upnpc-static EXECUTABLES_ADDTESTS = testminixml minixmlvalid testupnpreplyparse \ testigddescparse testminiwget TESTMINIXMLOBJS = minixml.o igd_desc_parse.o testminixml.o TESTMINIWGETOBJS = miniwget.o testminiwget.o connecthostport.o receivedata.o TESTUPNPREPLYPARSE = testupnpreplyparse.o minixml.o upnpreplyparse.o TESTIGDDESCPARSE = testigddescparse.o igd_desc_parse.o minixml.o \ miniupnpc.o miniwget.o upnpcommands.o upnpreplyparse.o \ minisoap.o connecthostport.o receivedata.o \ portlistingparse.o ifneq ($(OS), AmigaOS) EXECUTABLES := $(EXECUTABLES) upnpc-shared TESTMINIWGETOBJS := $(TESTMINIWGETOBJS) minissdpc.o TESTIGDDESCPARSE := $(TESTIGDDESCPARSE) minissdpc.o endif LIBDIR ?= lib # install directories INSTALLPREFIX ?= $(PREFIX)/usr INSTALLDIRINC = $(INSTALLPREFIX)/include/miniupnpc INSTALLDIRLIB = $(INSTALLPREFIX)/$(LIBDIR) INSTALLDIRBIN = $(INSTALLPREFIX)/bin INSTALLDIRMAN = $(INSTALLPREFIX)/share/man FILESTOINSTALL = $(LIBRARY) $(EXECUTABLES) ifneq ($(OS), AmigaOS) FILESTOINSTALL := $(FILESTOINSTALL) $(SHAREDLIBRARY) endif .PHONY: install clean depend all check test everything \ installpythonmodule updateversion # validateminixml validateminiwget all: $(LIBRARY) $(EXECUTABLES) test: check check: validateminixml validateminiwget validateupnpreplyparse everything: all $(EXECUTABLES_ADDTESTS) pythonmodule: $(LIBRARY) miniupnpcmodule.c setup.py python setup.py build touch $@ installpythonmodule: pythonmodule python setup.py install pythonmodule3: $(LIBRARY) miniupnpcmodule.c setup.py python3 setup.py build touch $@ installpythonmodule3: pythonmodule3 python3 setup.py install validateminixml: minixmlvalid @echo "minixml validation test" ./minixmlvalid touch $@ validateminiwget: testminiwget minihttptestserver testminiwget.sh @echo "miniwget validation test" ./testminiwget.sh touch $@ validateupnpreplyparse: testupnpreplyparse testupnpreplyparse.sh @echo "upnpreplyparse validation test" ./testupnpreplyparse.sh touch $@ clean: $(RM) $(LIBRARY) $(SHAREDLIBRARY) $(EXECUTABLES) $(OBJS) miniupnpcstrings.h $(RM) $(EXECUTABLES_ADDTESTS) # clean python stuff $(RM) pythonmodule pythonmodule3 $(RM) validateminixml validateminiwget validateupnpreplyparse $(RM) -r build/ dist/ #python setup.py clean # clean jnaerator stuff $(RM) _jnaerator.* java/miniupnpc_$(OS).jar distclean: clean $(RM) $(JNAERATOR) java/*.jar java/*.class out.errors.txt updateversion: miniupnpc.h cp miniupnpc.h miniupnpc.h.bak sed 's/\(.*MINIUPNPC_API_VERSION\s\+\)[0-9]\+/\1$(APIVERSION)/' < miniupnpc.h.bak > miniupnpc.h install: updateversion $(FILESTOINSTALL) $(INSTALL) -d $(DESTDIR)$(INSTALLDIRINC) $(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INSTALLDIRINC) $(INSTALL) -d $(DESTDIR)$(INSTALLDIRLIB) $(INSTALL) -m 644 $(LIBRARY) $(DESTDIR)$(INSTALLDIRLIB) ifneq ($(OS), AmigaOS) $(INSTALL) -m 644 $(SHAREDLIBRARY) $(DESTDIR)$(INSTALLDIRLIB)/$(SONAME) ln -fs $(SONAME) $(DESTDIR)$(INSTALLDIRLIB)/$(SHAREDLIBRARY) endif $(INSTALL) -d $(DESTDIR)$(INSTALLDIRBIN) ifeq ($(OS), AmigaOS) $(INSTALL) -m 755 upnpc-static $(DESTDIR)$(INSTALLDIRBIN)/upnpc else $(INSTALL) -m 755 upnpc-shared $(DESTDIR)$(INSTALLDIRBIN)/upnpc endif $(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip ifneq ($(OS), AmigaOS) $(INSTALL) -d $(DESTDIR)$(INSTALLDIRMAN)/man3 $(INSTALL) man3/miniupnpc.3 $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3 ifeq ($(OS), Linux) gzip $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3 endif endif cleaninstall: $(RM) -r $(DESTDIR)$(INSTALLDIRINC) $(RM) $(DESTDIR)$(INSTALLDIRLIB)/$(LIBRARY) $(RM) $(DESTDIR)$(INSTALLDIRLIB)/$(SHAREDLIBRARY) depend: makedepend -Y -- $(CFLAGS) -- $(SRCS) 2>/dev/null $(LIBRARY): $(LIBOBJS) $(AR) crs $@ $? $(SHAREDLIBRARY): $(LIBOBJS) ifeq ($(OS), Darwin) # $(CC) -dynamiclib $(LDFLAGS) -Wl,-install_name,$(SONAME) -o $@ $^ $(CC) -dynamiclib $(LDFLAGS) -Wl,-install_name,$(INSTALLDIRLIB)/$(SONAME) -o $@ $^ else $(CC) -shared $(LDFLAGS) -Wl,-soname,$(SONAME) -o $@ $^ endif upnpc-static: upnpc.o $(LIBRARY) $(CC) $(LDFLAGS) -o $@ $^ upnpc-shared: upnpc.o $(SHAREDLIBRARY) $(CC) $(LDFLAGS) -o $@ $^ testminixml: $(TESTMINIXMLOBJS) testminiwget: $(TESTMINIWGETOBJS) minixmlvalid: minixml.o minixmlvalid.o testupnpreplyparse: $(TESTUPNPREPLYPARSE) testigddescparse: $(TESTIGDDESCPARSE) miniupnpcstrings.h: miniupnpcstrings.h.in updateminiupnpcstrings.sh VERSION $(SH) updateminiupnpcstrings.sh # ftp tool supplied with OpenBSD can download files from http. jnaerator-%.jar: wget $(JNAERATORBASEURL)/$@ || \ curl -o $@ $(JNAERATORBASEURL)/$@ || \ ftp $(JNAERATORBASEURL)/$@ jar: $(SHAREDLIBRARY) $(JNAERATOR) $(JAVA) -jar $(JNAERATOR) $(JNAERATORARGS) \ miniupnpc.h declspec.h upnpcommands.h upnpreplyparse.h \ igd_desc_parse.h miniwget.h upnperrors.h $(SHAREDLIBRARY) \ -package fr.free.miniupnp -o . -jar java/miniupnpc_$(JARSUFFIX).jar -v mvn_install: mvn install:install-file -Dfile=java/miniupnpc_$(JARSUFFIX).jar \ -DgroupId=com.github \ -DartifactId=miniupnp \ -Dversion=$(VERSION) \ -Dpackaging=jar \ -Dclassifier=$(JARSUFFIX) \ -DgeneratePom=true \ -DcreateChecksum=true # make .deb packages deb: /usr/share/pyshared/stdeb all (python setup.py --command-packages=stdeb.command bdist_deb) # install .deb packages ideb: (sudo dpkg -i deb_dist/*.deb) /usr/share/pyshared/stdeb: /usr/share/doc/python-all-dev (sudo apt-get install python-stdeb) /usr/share/doc/python-all-dev: (sudo apt-get install python-all-dev) minihttptestserver: minihttptestserver.o # DO NOT DELETE THIS LINE -- make depend depends on it. igd_desc_parse.o: igd_desc_parse.h miniupnpc.o: miniupnpc.h declspec.h igd_desc_parse.h minissdpc.h miniwget.h miniupnpc.o: minisoap.h minixml.h upnpcommands.h upnpreplyparse.h miniupnpc.o: portlistingparse.h miniupnpctypes.h connecthostport.h miniupnpc.o: receivedata.h minixml.o: minixml.h minisoap.o: minisoap.h miniupnpcstrings.h miniwget.o: miniupnpcstrings.h miniwget.h declspec.h connecthostport.h miniwget.o: receivedata.h upnpc.o: miniwget.h declspec.h miniupnpc.h igd_desc_parse.h upnpcommands.h upnpc.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h upnperrors.h upnpcommands.o: upnpcommands.h upnpreplyparse.h portlistingparse.h declspec.h upnpcommands.o: miniupnpctypes.h miniupnpc.h igd_desc_parse.h upnpreplyparse.o: upnpreplyparse.h minixml.h testminixml.o: minixml.h igd_desc_parse.h minixmlvalid.o: minixml.h testupnpreplyparse.o: upnpreplyparse.h minissdpc.o: minissdpc.h miniupnpc.h declspec.h igd_desc_parse.h codelength.h upnperrors.o: upnperrors.h declspec.h upnpcommands.h upnpreplyparse.h upnperrors.o: portlistingparse.h miniupnpctypes.h miniupnpc.h upnperrors.o: igd_desc_parse.h testigddescparse.o: igd_desc_parse.h minixml.h miniupnpc.h declspec.h testminiwget.o: miniwget.h declspec.h connecthostport.o: connecthostport.h receivedata.o: receivedata.h miniupnpc-1.9.20140610/igd_desc_parse.c010064400017500000024000000110121155054365100165420ustar00nanardstaff/* $Id: igd_desc_parse.c,v 1.14 2011/04/11 09:19:24 nanard Exp $ */ /* Project : miniupnp * http://miniupnp.free.fr/ * Author : Thomas Bernard * Copyright (c) 2005-2010 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ #include "igd_desc_parse.h" #include #include /* Start element handler : * update nesting level counter and copy element name */ void IGDstartelt(void * d, const char * name, int l) { struct IGDdatas * datas = (struct IGDdatas *)d; memcpy( datas->cureltname, name, l); datas->cureltname[l] = '\0'; datas->level++; if( (l==7) && !memcmp(name, "service", l) ) { datas->tmp.controlurl[0] = '\0'; datas->tmp.eventsuburl[0] = '\0'; datas->tmp.scpdurl[0] = '\0'; datas->tmp.servicetype[0] = '\0'; } } /* End element handler : * update nesting level counter and update parser state if * service element is parsed */ void IGDendelt(void * d, const char * name, int l) { struct IGDdatas * datas = (struct IGDdatas *)d; datas->level--; /*printf("endelt %2d %.*s\n", datas->level, l, name);*/ if( (l==7) && !memcmp(name, "service", l) ) { /* if( datas->state < 1 && !strcmp(datas->servicetype, // "urn:schemas-upnp-org:service:WANIPConnection:1") ) "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) datas->state ++; */ if(0==strcmp(datas->tmp.servicetype, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) { memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service)); } else if(0==strcmp(datas->tmp.servicetype, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1")) { memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service)); } else if(0==strcmp(datas->tmp.servicetype, "urn:schemas-upnp-org:service:WANIPConnection:1") || 0==strcmp(datas->tmp.servicetype, "urn:schemas-upnp-org:service:WANPPPConnection:1") ) { if(datas->first.servicetype[0] == '\0') { memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service)); } else { memcpy(&datas->second, &datas->tmp, sizeof(struct IGDdatas_service)); } } } } /* Data handler : * copy data depending on the current element name and state */ void IGDdata(void * d, const char * data, int l) { struct IGDdatas * datas = (struct IGDdatas *)d; char * dstmember = 0; /*printf("%2d %s : %.*s\n", datas->level, datas->cureltname, l, data); */ if( !strcmp(datas->cureltname, "URLBase") ) dstmember = datas->urlbase; else if( !strcmp(datas->cureltname, "presentationURL") ) dstmember = datas->presentationurl; else if( !strcmp(datas->cureltname, "serviceType") ) dstmember = datas->tmp.servicetype; else if( !strcmp(datas->cureltname, "controlURL") ) dstmember = datas->tmp.controlurl; else if( !strcmp(datas->cureltname, "eventSubURL") ) dstmember = datas->tmp.eventsuburl; else if( !strcmp(datas->cureltname, "SCPDURL") ) dstmember = datas->tmp.scpdurl; /* else if( !strcmp(datas->cureltname, "deviceType") ) dstmember = datas->devicetype_tmp;*/ if(dstmember) { if(l>=MINIUPNPC_URL_MAXSIZE) l = MINIUPNPC_URL_MAXSIZE-1; memcpy(dstmember, data, l); dstmember[l] = '\0'; } } void printIGD(struct IGDdatas * d) { printf("urlbase = '%s'\n", d->urlbase); printf("WAN Device (Common interface config) :\n"); /*printf(" deviceType = '%s'\n", d->CIF.devicetype);*/ printf(" serviceType = '%s'\n", d->CIF.servicetype); printf(" controlURL = '%s'\n", d->CIF.controlurl); printf(" eventSubURL = '%s'\n", d->CIF.eventsuburl); printf(" SCPDURL = '%s'\n", d->CIF.scpdurl); printf("primary WAN Connection Device (IP or PPP Connection):\n"); /*printf(" deviceType = '%s'\n", d->first.devicetype);*/ printf(" servicetype = '%s'\n", d->first.servicetype); printf(" controlURL = '%s'\n", d->first.controlurl); printf(" eventSubURL = '%s'\n", d->first.eventsuburl); printf(" SCPDURL = '%s'\n", d->first.scpdurl); printf("secondary WAN Connection Device (IP or PPP Connection):\n"); /*printf(" deviceType = '%s'\n", d->second.devicetype);*/ printf(" servicetype = '%s'\n", d->second.servicetype); printf(" controlURL = '%s'\n", d->second.controlurl); printf(" eventSubURL = '%s'\n", d->second.eventsuburl); printf(" SCPDURL = '%s'\n", d->second.scpdurl); printf("WAN IPv6 Firewall Control :\n"); /*printf(" deviceType = '%s'\n", d->IPv6FC.devicetype);*/ printf(" servicetype = '%s'\n", d->IPv6FC.servicetype); printf(" controlURL = '%s'\n", d->IPv6FC.controlurl); printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl); printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl); } miniupnpc-1.9.20140610/igd_desc_parse.h010064400017500000024000000030361210144722100165430ustar00nanardstaff/* $Id: igd_desc_parse.h,v 1.11 2012/10/16 16:49:02 nanard Exp $ */ /* Project : miniupnp * http://miniupnp.free.fr/ * Author : Thomas Bernard * Copyright (c) 2005-2010 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ #ifndef IGD_DESC_PARSE_H_INCLUDED #define IGD_DESC_PARSE_H_INCLUDED /* Structure to store the result of the parsing of UPnP * descriptions of Internet Gateway Devices */ #define MINIUPNPC_URL_MAXSIZE (128) struct IGDdatas_service { char controlurl[MINIUPNPC_URL_MAXSIZE]; char eventsuburl[MINIUPNPC_URL_MAXSIZE]; char scpdurl[MINIUPNPC_URL_MAXSIZE]; char servicetype[MINIUPNPC_URL_MAXSIZE]; /*char devicetype[MINIUPNPC_URL_MAXSIZE];*/ }; struct IGDdatas { char cureltname[MINIUPNPC_URL_MAXSIZE]; char urlbase[MINIUPNPC_URL_MAXSIZE]; char presentationurl[MINIUPNPC_URL_MAXSIZE]; int level; /*int state;*/ /* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */ struct IGDdatas_service CIF; /* "urn:schemas-upnp-org:service:WANIPConnection:1" * "urn:schemas-upnp-org:service:WANPPPConnection:1" */ struct IGDdatas_service first; /* if both WANIPConnection and WANPPPConnection are present */ struct IGDdatas_service second; /* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */ struct IGDdatas_service IPv6FC; /* tmp */ struct IGDdatas_service tmp; }; void IGDstartelt(void *, const char *, int); void IGDendelt(void *, const char *, int); void IGDdata(void *, const char *, int); void printIGD(struct IGDdatas *); #endif miniupnpc-1.9.20140610/miniwget.c010064400017500000024000000346311234555371500154530ustar00nanardstaff/* $Id: miniwget.c,v 1.62 2014/06/10 09:47:10 nanard Exp $ */ /* Project : miniupnp * Website : http://miniupnp.free.fr/ * Author : Thomas Bernard * Copyright (c) 2005-2014 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ #include #include #include #include #ifdef _WIN32 #include #include #include #define MAXHOSTNAMELEN 64 #define MIN(x,y) (((x)<(y))?(x):(y)) #define snprintf _snprintf #define socklen_t int #ifndef strncasecmp #if defined(_MSC_VER) && (_MSC_VER >= 1400) #define strncasecmp _memicmp #else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ #define strncasecmp memicmp #endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ #endif /* #ifndef strncasecmp */ #else /* #ifdef _WIN32 */ #include #include #if defined(__amigaos__) && !defined(__amigaos4__) #define socklen_t int #else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ #include #endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ #include #include #include #include #include #define closesocket close #endif /* #else _WIN32 */ #if defined(__sun) || defined(sun) #define MIN(x,y) (((x)<(y))?(x):(y)) #endif #ifdef __GNU__ #define MAXHOSTNAMELEN 64 #endif #include "miniupnpcstrings.h" #include "miniwget.h" #include "connecthostport.h" #include "receivedata.h" #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif /* * Read a HTTP response from a socket. * Process Content-Length and Transfer-encoding headers. * return a pointer to the content buffer, which length is saved * to the length parameter. */ void * getHTTPResponse(int s, int * size) { char buf[2048]; int n; int endofheaders = 0; int chunked = 0; int content_length = -1; unsigned int chunksize = 0; unsigned int bytestocopy = 0; /* buffers : */ char * header_buf; unsigned int header_buf_len = 2048; unsigned int header_buf_used = 0; char * content_buf; unsigned int content_buf_len = 2048; unsigned int content_buf_used = 0; char chunksize_buf[32]; unsigned int chunksize_buf_index; header_buf = malloc(header_buf_len); content_buf = malloc(content_buf_len); chunksize_buf[0] = '\0'; chunksize_buf_index = 0; while((n = receivedata(s, buf, 2048, 5000, NULL)) > 0) { if(endofheaders == 0) { int i; int linestart=0; int colon=0; int valuestart=0; if(header_buf_used + n > header_buf_len) { header_buf = realloc(header_buf, header_buf_used + n); header_buf_len = header_buf_used + n; } memcpy(header_buf + header_buf_used, buf, n); header_buf_used += n; /* search for CR LF CR LF (end of headers) * recognize also LF LF */ i = 0; while(i < ((int)header_buf_used-1) && (endofheaders == 0)) { if(header_buf[i] == '\r') { i++; if(header_buf[i] == '\n') { i++; if(i < (int)header_buf_used && header_buf[i] == '\r') { i++; if(i < (int)header_buf_used && header_buf[i] == '\n') { endofheaders = i+1; } } } } else if(header_buf[i] == '\n') { i++; if(header_buf[i] == '\n') { endofheaders = i+1; } } i++; } if(endofheaders == 0) continue; /* parse header lines */ for(i = 0; i < endofheaders - 1; i++) { if(colon <= linestart && header_buf[i]==':') { colon = i; while(i < (endofheaders-1) && (header_buf[i+1] == ' ' || header_buf[i+1] == '\t')) i++; valuestart = i + 1; } /* detecting end of line */ else if(header_buf[i]=='\r' || header_buf[i]=='\n') { if(colon > linestart && valuestart > colon) { #ifdef DEBUG printf("header='%.*s', value='%.*s'\n", colon-linestart, header_buf+linestart, i-valuestart, header_buf+valuestart); #endif if(0==strncasecmp(header_buf+linestart, "content-length", colon-linestart)) { content_length = atoi(header_buf+valuestart); #ifdef DEBUG printf("Content-Length: %d\n", content_length); #endif } else if(0==strncasecmp(header_buf+linestart, "transfer-encoding", colon-linestart) && 0==strncasecmp(header_buf+valuestart, "chunked", 7)) { #ifdef DEBUG printf("chunked transfer-encoding!\n"); #endif chunked = 1; } } while((i < (int)header_buf_used) && (header_buf[i]=='\r' || header_buf[i] == '\n')) i++; linestart = i; colon = linestart; valuestart = 0; } } /* copy the remaining of the received data back to buf */ n = header_buf_used - endofheaders; memcpy(buf, header_buf + endofheaders, n); /* if(headers) */ } if(endofheaders) { /* content */ if(chunked) { int i = 0; while(i < n) { if(chunksize == 0) { /* reading chunk size */ if(chunksize_buf_index == 0) { /* skipping any leading CR LF */ if(i= '0' && chunksize_buf[j] <= '9') chunksize = (chunksize << 4) + (chunksize_buf[j] - '0'); else chunksize = (chunksize << 4) + ((chunksize_buf[j] | 32) - 'a' + 10); } chunksize_buf[0] = '\0'; chunksize_buf_index = 0; i++; } else { /* not finished to get chunksize */ continue; } #ifdef DEBUG printf("chunksize = %u (%x)\n", chunksize, chunksize); #endif if(chunksize == 0) { #ifdef DEBUG printf("end of HTTP content - %d %d\n", i, n); /*printf("'%.*s'\n", n-i, buf+i);*/ #endif goto end_of_stream; } } bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i); if((content_buf_used + bytestocopy) > content_buf_len) { if(content_length >= (int)(content_buf_used + bytestocopy)) { content_buf_len = content_length; } else { content_buf_len = content_buf_used + bytestocopy; } content_buf = (char *)realloc((void *)content_buf, content_buf_len); } memcpy(content_buf + content_buf_used, buf + i, bytestocopy); content_buf_used += bytestocopy; i += bytestocopy; chunksize -= bytestocopy; } } else { /* not chunked */ if(content_length > 0 && (int)(content_buf_used + n) > content_length) { /* skipping additional bytes */ n = content_length - content_buf_used; } if(content_buf_used + n > content_buf_len) { if(content_length >= (int)(content_buf_used + n)) { content_buf_len = content_length; } else { content_buf_len = content_buf_used + n; } content_buf = (char *)realloc((void *)content_buf, content_buf_len); } memcpy(content_buf + content_buf_used, buf, n); content_buf_used += n; } } /* use the Content-Length header value if available */ if(content_length > 0 && (int)content_buf_used >= content_length) { #ifdef DEBUG printf("End of HTTP content\n"); #endif break; } } end_of_stream: free(header_buf); header_buf = NULL; *size = content_buf_used; if(content_buf_used == 0) { free(content_buf); content_buf = NULL; } return content_buf; } /* miniwget3() : * do all the work. * Return NULL if something failed. */ static void * miniwget3(const char * host, unsigned short port, const char * path, int * size, char * addr_str, int addr_str_len, const char * httpversion, unsigned int scope_id) { char buf[2048]; int s; int n; int len; int sent; void * content; *size = 0; s = connecthostport(host, port, scope_id); if(s < 0) return NULL; /* get address for caller ! */ if(addr_str) { struct sockaddr_storage saddr; socklen_t saddrlen; saddrlen = sizeof(saddr); if(getsockname(s, (struct sockaddr *)&saddr, &saddrlen) < 0) { perror("getsockname"); } else { #if defined(__amigaos__) && !defined(__amigaos4__) /* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD); * But his function make a string with the port : nn.nn.nn.nn:port */ /* if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr), NULL, addr_str, (DWORD *)&addr_str_len)) { printf("WSAAddressToStringA() failed : %d\n", WSAGetLastError()); }*/ /* the following code is only compatible with ip v4 addresses */ strncpy(addr_str, inet_ntoa(((struct sockaddr_in *)&saddr)->sin_addr), addr_str_len); #else #if 0 if(saddr.sa_family == AF_INET6) { inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)&saddr)->sin6_addr), addr_str, addr_str_len); } else { inet_ntop(AF_INET, &(((struct sockaddr_in *)&saddr)->sin_addr), addr_str, addr_str_len); } #endif /* getnameinfo return ip v6 address with the scope identifier * such as : 2a01:e35:8b2b:7330::%4281128194 */ n = getnameinfo((const struct sockaddr *)&saddr, saddrlen, addr_str, addr_str_len, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); if(n != 0) { #ifdef _WIN32 fprintf(stderr, "getnameinfo() failed : %d\n", n); #else fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n)); #endif } #endif } #ifdef DEBUG printf("address miniwget : %s\n", addr_str); #endif } len = snprintf(buf, sizeof(buf), "GET %s HTTP/%s\r\n" "Host: %s:%d\r\n" "Connection: Close\r\n" "User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" "\r\n", path, httpversion, host, port); sent = 0; /* sending the HTTP request */ while(sent < len) { n = send(s, buf+sent, len-sent, 0); if(n < 0) { perror("send"); closesocket(s); return NULL; } else { sent += n; } } content = getHTTPResponse(s, size); closesocket(s); return content; } /* miniwget2() : * Call miniwget3(); retry with HTTP/1.1 if 1.0 fails. */ static void * miniwget2(const char * host, unsigned short port, const char * path, int * size, char * addr_str, int addr_str_len, unsigned int scope_id) { char * respbuffer; #if 1 respbuffer = miniwget3(host, port, path, size, addr_str, addr_str_len, "1.1", scope_id); #else respbuffer = miniwget3(host, port, path, size, addr_str, addr_str_len, "1.0", scope_id); if (*size == 0) { #ifdef DEBUG printf("Retrying with HTTP/1.1\n"); #endif free(respbuffer); respbuffer = miniwget3(host, port, path, size, addr_str, addr_str_len, "1.1", scope_id); } #endif return respbuffer; } /* parseURL() * arguments : * url : source string not modified * hostname : hostname destination string (size of MAXHOSTNAMELEN+1) * port : port (destination) * path : pointer to the path part of the URL * * Return values : * 0 - Failure * 1 - Success */ int parseURL(const char * url, char * hostname, unsigned short * port, char * * path, unsigned int * scope_id) { char * p1, *p2, *p3; if(!url) return 0; p1 = strstr(url, "://"); if(!p1) return 0; p1 += 3; if( (url[0]!='h') || (url[1]!='t') ||(url[2]!='t') || (url[3]!='p')) return 0; memset(hostname, 0, MAXHOSTNAMELEN + 1); if(*p1 == '[') { /* IP v6 : http://[2a00:1450:8002::6a]/path/abc */ char * scope; scope = strchr(p1, '%'); p2 = strchr(p1, ']'); if(p2 && scope && scope < p2 && scope_id) { /* parse scope */ #ifdef IF_NAMESIZE char tmp[IF_NAMESIZE]; int l; scope++; /* "%25" is just '%' in URL encoding */ if(scope[0] == '2' && scope[1] == '5') scope += 2; /* skip "25" */ l = p2 - scope; if(l >= IF_NAMESIZE) l = IF_NAMESIZE - 1; memcpy(tmp, scope, l); tmp[l] = '\0'; *scope_id = if_nametoindex(tmp); if(*scope_id == 0) { *scope_id = (unsigned int)strtoul(tmp, NULL, 10); } #else /* under windows, scope is numerical */ char tmp[8]; int l; scope++; /* "%25" is just '%' in URL encoding */ if(scope[0] == '2' && scope[1] == '5') scope += 2; /* skip "25" */ l = p2 - scope; if(l >= sizeof(tmp)) l = sizeof(tmp) - 1; memcpy(tmp, scope, l); tmp[l] = '\0'; *scope_id = (unsigned int)strtoul(tmp, NULL, 10); #endif } p3 = strchr(p1, '/'); if(p2 && p3) { p2++; strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1))); if(*p2 == ':') { *port = 0; p2++; while( (*p2 >= '0') && (*p2 <= '9')) { *port *= 10; *port += (unsigned short)(*p2 - '0'); p2++; } } else { *port = 80; } *path = p3; return 1; } } p2 = strchr(p1, ':'); p3 = strchr(p1, '/'); if(!p3) return 0; if(!p2 || (p2>p3)) { strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1))); *port = 80; } else { strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1))); *port = 0; p2++; while( (*p2 >= '0') && (*p2 <= '9')) { *port *= 10; *port += (unsigned short)(*p2 - '0'); p2++; } } *path = p3; return 1; } void * miniwget(const char * url, int * size, unsigned int scope_id) { unsigned short port; char * path; /* protocol://host:port/chemin */ char hostname[MAXHOSTNAMELEN+1]; *size = 0; if(!parseURL(url, hostname, &port, &path, &scope_id)) return NULL; #ifdef DEBUG printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n", hostname, port, path, scope_id); #endif return miniwget2(hostname, port, path, size, 0, 0, scope_id); } void * miniwget_getaddr(const char * url, int * size, char * addr, int addrlen, unsigned int scope_id) { unsigned short port; char * path; /* protocol://host:port/path */ char hostname[MAXHOSTNAMELEN+1]; *size = 0; if(addr) addr[0] = '\0'; if(!parseURL(url, hostname, &port, &path, &scope_id)) return NULL; #ifdef DEBUG printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n", hostname, port, path, scope_id); #endif return miniwget2(hostname, port, path, size, addr, addrlen, scope_id); } miniupnpc-1.9.20140610/miniwget.h010064400017500000024000000013271234555371500154540ustar00nanardstaff/* $Id: miniwget.h,v 1.9 2014/06/10 09:44:55 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2005-2012 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ #ifndef MINIWGET_H_INCLUDED #define MINIWGET_H_INCLUDED #include "declspec.h" #ifdef __cplusplus extern "C" { #endif MINIUPNP_LIBSPEC void * getHTTPResponse(int s, int * size); MINIUPNP_LIBSPEC void * miniwget(const char *, int *, unsigned int); MINIUPNP_LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int); int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *); #ifdef __cplusplus } #endif #endif miniupnpc-1.9.20140610/minixml.c010064400017500000024000000130041227446335500152750ustar00nanardstaff/* $Id: minixml.c,v 1.11 2014/02/03 15:54:12 nanard Exp $ */ /* minixml.c : the minimum size a xml parser can be ! */ /* Project : miniupnp * webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author : Thomas Bernard Copyright (c) 2005-2014, Thomas BERNARD All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "minixml.h" /* parseatt : used to parse the argument list * return 0 (false) in case of success and -1 (true) if the end * of the xmlbuffer is reached. */ static int parseatt(struct xmlparser * p) { const char * attname; int attnamelen; const char * attvalue; int attvaluelen; while(p->xml < p->xmlend) { if(*p->xml=='/' || *p->xml=='>') return 0; if( !IS_WHITE_SPACE(*p->xml) ) { char sep; attname = p->xml; attnamelen = 0; while(*p->xml!='=' && !IS_WHITE_SPACE(*p->xml) ) { attnamelen++; p->xml++; if(p->xml >= p->xmlend) return -1; } while(*(p->xml++) != '=') { if(p->xml >= p->xmlend) return -1; } while(IS_WHITE_SPACE(*p->xml)) { p->xml++; if(p->xml >= p->xmlend) return -1; } sep = *p->xml; if(sep=='\'' || sep=='\"') { p->xml++; if(p->xml >= p->xmlend) return -1; attvalue = p->xml; attvaluelen = 0; while(*p->xml != sep) { attvaluelen++; p->xml++; if(p->xml >= p->xmlend) return -1; } } else { attvalue = p->xml; attvaluelen = 0; while( !IS_WHITE_SPACE(*p->xml) && *p->xml != '>' && *p->xml != '/') { attvaluelen++; p->xml++; if(p->xml >= p->xmlend) return -1; } } /*printf("%.*s='%.*s'\n", attnamelen, attname, attvaluelen, attvalue);*/ if(p->attfunc) p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen); } p->xml++; } return -1; } /* parseelt parse the xml stream and * call the callback functions when needed... */ static void parseelt(struct xmlparser * p) { int i; const char * elementname; while(p->xml < (p->xmlend - 1)) { if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "", 3) != 0); p->xml += 3; } else if((p->xml)[0]=='<' && (p->xml)[1]!='?') { i = 0; elementname = ++p->xml; while( !IS_WHITE_SPACE(*p->xml) && (*p->xml!='>') && (*p->xml!='/') ) { i++; p->xml++; if (p->xml >= p->xmlend) return; /* to ignore namespace : */ if(*p->xml==':') { i = 0; elementname = ++p->xml; } } if(i>0) { if(p->starteltfunc) p->starteltfunc(p->data, elementname, i); if(parseatt(p)) return; if(*p->xml!='/') { const char * data; i = 0; data = ++p->xml; if (p->xml >= p->xmlend) return; while( IS_WHITE_SPACE(*p->xml) ) { i++; p->xml++; if (p->xml >= p->xmlend) return; } if(memcmp(p->xml, "xml += 9; data = p->xml; i = 0; while(memcmp(p->xml, "]]>", 3) != 0) { i++; p->xml++; if ((p->xml + 3) >= p->xmlend) return; } if(i>0 && p->datafunc) p->datafunc(p->data, data, i); while(*p->xml!='<') { p->xml++; if (p->xml >= p->xmlend) return; } } else { while(*p->xml!='<') { i++; p->xml++; if ((p->xml + 1) >= p->xmlend) return; } if(i>0 && p->datafunc && *(p->xml + 1) == '/') p->datafunc(p->data, data, i); } } } else if(*p->xml == '/') { i = 0; elementname = ++p->xml; if (p->xml >= p->xmlend) return; while((*p->xml != '>')) { i++; p->xml++; if (p->xml >= p->xmlend) return; } if(p->endeltfunc) p->endeltfunc(p->data, elementname, i); p->xml++; } } else { p->xml++; } } } /* the parser must be initialized before calling this function */ void parsexml(struct xmlparser * parser) { parser->xml = parser->xmlstart; parser->xmlend = parser->xmlstart + parser->xmlsize; parseelt(parser); } miniupnpc-1.9.20140610/minixml.h010064400017500000024000000022331203340734000152650ustar00nanardstaff/* $Id: minixml.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */ /* minimal xml parser * * Project : miniupnp * Website : http://miniupnp.free.fr/ * Author : Thomas Bernard * Copyright (c) 2005 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ #ifndef MINIXML_H_INCLUDED #define MINIXML_H_INCLUDED #define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n')) /* if a callback function pointer is set to NULL, * the function is not called */ struct xmlparser { const char *xmlstart; const char *xmlend; const char *xml; /* pointer to current character */ int xmlsize; void * data; void (*starteltfunc) (void *, const char *, int); void (*endeltfunc) (void *, const char *, int); void (*datafunc) (void *, const char *, int); void (*attfunc) (void *, const char *, int, const char *, int); }; /* parsexml() * the xmlparser structure must be initialized before the call * the following structure members have to be initialized : * xmlstart, xmlsize, data, *func * xml is for internal usage, xmlend is computed automatically */ void parsexml(struct xmlparser *); #endif miniupnpc-1.9.20140610/upnpc.c010064400017500000024000000607241233507702200147460ustar00nanardstaff/* $Id: upnpc.c,v 1.103 2014/05/15 08:41:44 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2005-2014 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ #include #include #include #include #ifdef _WIN32 #include #define snprintf _snprintf #else /* for IPPROTO_TCP / IPPROTO_UDP */ #include #endif #include "miniwget.h" #include "miniupnpc.h" #include "upnpcommands.h" #include "upnperrors.h" /* protofix() checks if protocol is "UDP" or "TCP" * returns NULL if not */ const char * protofix(const char * proto) { static const char proto_tcp[4] = { 'T', 'C', 'P', 0}; static const char proto_udp[4] = { 'U', 'D', 'P', 0}; int i, b; for(i=0, b=1; i<4; i++) b = b && ( (proto[i] == proto_tcp[i]) || (proto[i] == (proto_tcp[i] | 32)) ); if(b) return proto_tcp; for(i=0, b=1; i<4; i++) b = b && ( (proto[i] == proto_udp[i]) || (proto[i] == (proto_udp[i] | 32)) ); if(b) return proto_udp; return 0; } static void DisplayInfos(struct UPNPUrls * urls, struct IGDdatas * data) { char externalIPAddress[40]; char connectionType[64]; char status[64]; char lastconnerr[64]; unsigned int uptime; unsigned int brUp, brDown; time_t timenow, timestarted; int r; if(UPNP_GetConnectionTypeInfo(urls->controlURL, data->first.servicetype, connectionType) != UPNPCOMMAND_SUCCESS) printf("GetConnectionTypeInfo failed.\n"); else printf("Connection Type : %s\n", connectionType); if(UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, status, &uptime, lastconnerr) != UPNPCOMMAND_SUCCESS) printf("GetStatusInfo failed.\n"); else printf("Status : %s, uptime=%us, LastConnectionError : %s\n", status, uptime, lastconnerr); timenow = time(NULL); timestarted = timenow - uptime; printf(" Time started : %s", ctime(×tarted)); if(UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype, &brDown, &brUp) != UPNPCOMMAND_SUCCESS) { printf("GetLinkLayerMaxBitRates failed.\n"); } else { printf("MaxBitRateDown : %u bps", brDown); if(brDown >= 1000000) { printf(" (%u.%u Mbps)", brDown / 1000000, (brDown / 100000) % 10); } else if(brDown >= 1000) { printf(" (%u Kbps)", brDown / 1000); } printf(" MaxBitRateUp %u bps", brUp); if(brUp >= 1000000) { printf(" (%u.%u Mbps)", brUp / 1000000, (brUp / 100000) % 10); } else if(brUp >= 1000) { printf(" (%u Kbps)", brUp / 1000); } printf("\n"); } r = UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, externalIPAddress); if(r != UPNPCOMMAND_SUCCESS) { printf("GetExternalIPAddress failed. (errorcode=%d)\n", r); } else { printf("ExternalIPAddress = %s\n", externalIPAddress); } } static void GetConnectionStatus(struct UPNPUrls * urls, struct IGDdatas * data) { unsigned int bytessent, bytesreceived, packetsreceived, packetssent; DisplayInfos(urls, data); bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype); bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype); packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype); packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype); printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived); printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived); } static void ListRedirections(struct UPNPUrls * urls, struct IGDdatas * data) { int r; int i = 0; char index[6]; char intClient[40]; char intPort[6]; char extPort[6]; char protocol[4]; char desc[80]; char enabled[6]; char rHost[64]; char duration[16]; /*unsigned int num=0; UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num); printf("PortMappingNumberOfEntries : %u\n", num);*/ printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n"); do { snprintf(index, 6, "%d", i); rHost[0] = '\0'; enabled[0] = '\0'; duration[0] = '\0'; desc[0] = '\0'; extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0'; r = UPNP_GetGenericPortMappingEntry(urls->controlURL, data->first.servicetype, index, extPort, intClient, intPort, protocol, desc, enabled, rHost, duration); if(r==0) /* printf("%02d - %s %s->%s:%s\tenabled=%s leaseDuration=%s\n" " desc='%s' rHost='%s'\n", i, protocol, extPort, intClient, intPort, enabled, duration, desc, rHost); */ printf("%2d %s %5s->%s:%-5s '%s' '%s' %s\n", i, protocol, extPort, intClient, intPort, desc, rHost, duration); else printf("GetGenericPortMappingEntry() returned %d (%s)\n", r, strupnperror(r)); i++; } while(r==0); } static void NewListRedirections(struct UPNPUrls * urls, struct IGDdatas * data) { int r; int i = 0; struct PortMappingParserData pdata; struct PortMapping * pm; memset(&pdata, 0, sizeof(struct PortMappingParserData)); r = UPNP_GetListOfPortMappings(urls->controlURL, data->first.servicetype, "0", "65535", "TCP", "1000", &pdata); if(r == UPNPCOMMAND_SUCCESS) { printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n"); for(pm = pdata.head.lh_first; pm != NULL; pm = pm->entries.le_next) { printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", i, pm->protocol, pm->externalPort, pm->internalClient, pm->internalPort, pm->description, pm->remoteHost, (unsigned)pm->leaseTime); i++; } FreePortListing(&pdata); } else { printf("GetListOfPortMappings() returned %d (%s)\n", r, strupnperror(r)); } r = UPNP_GetListOfPortMappings(urls->controlURL, data->first.servicetype, "0", "65535", "UDP", "1000", &pdata); if(r == UPNPCOMMAND_SUCCESS) { for(pm = pdata.head.lh_first; pm != NULL; pm = pm->entries.le_next) { printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", i, pm->protocol, pm->externalPort, pm->internalClient, pm->internalPort, pm->description, pm->remoteHost, (unsigned)pm->leaseTime); i++; } FreePortListing(&pdata); } else { printf("GetListOfPortMappings() returned %d (%s)\n", r, strupnperror(r)); } } /* Test function * 1 - get connection type * 2 - get extenal ip address * 3 - Add port mapping * 4 - get this port mapping from the IGD */ static void SetRedirectAndTest(struct UPNPUrls * urls, struct IGDdatas * data, const char * iaddr, const char * iport, const char * eport, const char * proto, const char * leaseDuration, const char * description, int addAny) { char externalIPAddress[40]; char intClient[40]; char intPort[6]; char reservedPort[6]; char duration[16]; int r; if(!iaddr || !iport || !eport || !proto) { fprintf(stderr, "Wrong arguments\n"); return; } proto = protofix(proto); if(!proto) { fprintf(stderr, "invalid protocol\n"); return; } r = UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, externalIPAddress); if(r!=UPNPCOMMAND_SUCCESS) printf("GetExternalIPAddress failed.\n"); else printf("ExternalIPAddress = %s\n", externalIPAddress); if (addAny) { r = UPNP_AddAnyPortMapping(urls->controlURL, data->first.servicetype, eport, iport, iaddr, description, proto, 0, leaseDuration, reservedPort); if(r==UPNPCOMMAND_SUCCESS) eport = reservedPort; else printf("AddAnyPortMapping(%s, %s, %s) failed with code %d (%s)\n", eport, iport, iaddr, r, strupnperror(r)); } else { r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype, eport, iport, iaddr, description, proto, 0, leaseDuration); if(r!=UPNPCOMMAND_SUCCESS) printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", eport, iport, iaddr, r, strupnperror(r)); } r = UPNP_GetSpecificPortMappingEntry(urls->controlURL, data->first.servicetype, eport, proto, NULL/*remoteHost*/, intClient, intPort, NULL/*desc*/, NULL/*enabled*/, duration); if(r!=UPNPCOMMAND_SUCCESS) printf("GetSpecificPortMappingEntry() failed with code %d (%s)\n", r, strupnperror(r)); else { printf("InternalIP:Port = %s:%s\n", intClient, intPort); printf("external %s:%s %s is redirected to internal %s:%s (duration=%s)\n", externalIPAddress, eport, proto, intClient, intPort, duration); } } static void RemoveRedirect(struct UPNPUrls * urls, struct IGDdatas * data, const char * eport, const char * proto) { int r; if(!proto || !eport) { fprintf(stderr, "invalid arguments\n"); return; } proto = protofix(proto); if(!proto) { fprintf(stderr, "protocol invalid\n"); return; } r = UPNP_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, 0); printf("UPNP_DeletePortMapping() returned : %d\n", r); } static void RemoveRedirectRange(struct UPNPUrls * urls, struct IGDdatas * data, const char * ePortStart, char const * ePortEnd, const char * proto, const char * manage) { int r; if (!manage) manage = "0"; if(!proto || !ePortStart || !ePortEnd) { fprintf(stderr, "invalid arguments\n"); return; } proto = protofix(proto); if(!proto) { fprintf(stderr, "protocol invalid\n"); return; } r = UPNP_DeletePortMappingRange(urls->controlURL, data->first.servicetype, ePortStart, ePortEnd, proto, manage); printf("UPNP_DeletePortMappingRange() returned : %d\n", r); } /* IGD:2, functions for service WANIPv6FirewallControl:1 */ static void GetFirewallStatus(struct UPNPUrls * urls, struct IGDdatas * data) { unsigned int bytessent, bytesreceived, packetsreceived, packetssent; int firewallEnabled = 0, inboundPinholeAllowed = 0; UPNP_GetFirewallStatus(urls->controlURL_6FC, data->IPv6FC.servicetype, &firewallEnabled, &inboundPinholeAllowed); printf("FirewallEnabled: %d & Inbound Pinhole Allowed: %d\n", firewallEnabled, inboundPinholeAllowed); printf("GetFirewallStatus:\n Firewall Enabled: %s\n Inbound Pinhole Allowed: %s\n", (firewallEnabled)? "Yes":"No", (inboundPinholeAllowed)? "Yes":"No"); bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype); bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype); packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype); packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype); printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived); printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived); } /* Test function * 1 - Add pinhole * 2 - Check if pinhole is working from the IGD side */ static void SetPinholeAndTest(struct UPNPUrls * urls, struct IGDdatas * data, const char * remoteaddr, const char * eport, const char * intaddr, const char * iport, const char * proto, const char * lease_time) { char uniqueID[8]; /*int isWorking = 0;*/ int r; char proto_tmp[8]; if(!intaddr || !remoteaddr || !iport || !eport || !proto || !lease_time) { fprintf(stderr, "Wrong arguments\n"); return; } if(atoi(proto) == 0) { const char * protocol; protocol = protofix(proto); if(protocol && (strcmp("TCP", protocol) == 0)) { snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_TCP); proto = proto_tmp; } else if(protocol && (strcmp("UDP", protocol) == 0)) { snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_UDP); proto = proto_tmp; } else { fprintf(stderr, "invalid protocol\n"); return; } } r = UPNP_AddPinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, lease_time, uniqueID); if(r!=UPNPCOMMAND_SUCCESS) printf("AddPinhole([%s]:%s -> [%s]:%s) failed with code %d (%s)\n", remoteaddr, eport, intaddr, iport, r, strupnperror(r)); else { printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n", remoteaddr, eport, intaddr, iport, uniqueID); /*r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->servicetype_6FC, uniqueID, &isWorking); if(r!=UPNPCOMMAND_SUCCESS) printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");*/ } } /* Test function * 1 - Check if pinhole is working from the IGD side * 2 - Update pinhole */ static void GetPinholeAndUpdate(struct UPNPUrls * urls, struct IGDdatas * data, const char * uniqueID, const char * lease_time) { int isWorking = 0; int r; if(!uniqueID || !lease_time) { fprintf(stderr, "Wrong arguments\n"); return; } r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking); printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No"); if(r!=UPNPCOMMAND_SUCCESS) printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); if(isWorking || r==709) { r = UPNP_UpdatePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, lease_time); printf("UpdatePinhole: Pinhole ID = %s with Lease Time: %s\n", uniqueID, lease_time); if(r!=UPNPCOMMAND_SUCCESS) printf("UpdatePinhole: ID (%s) failed with code %d (%s)\n", uniqueID, r, strupnperror(r)); } } /* Test function * Get pinhole timeout */ static void GetPinholeOutboundTimeout(struct UPNPUrls * urls, struct IGDdatas * data, const char * remoteaddr, const char * eport, const char * intaddr, const char * iport, const char * proto) { int timeout = 0; int r; if(!intaddr || !remoteaddr || !iport || !eport || !proto) { fprintf(stderr, "Wrong arguments\n"); return; } r = UPNP_GetOutboundPinholeTimeout(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, &timeout); if(r!=UPNPCOMMAND_SUCCESS) printf("GetOutboundPinholeTimeout([%s]:%s -> [%s]:%s) failed with code %d (%s)\n", intaddr, iport, remoteaddr, eport, r, strupnperror(r)); else printf("GetOutboundPinholeTimeout: ([%s]:%s -> [%s]:%s) / Timeout = %d\n", intaddr, iport, remoteaddr, eport, timeout); } static void GetPinholePackets(struct UPNPUrls * urls, struct IGDdatas * data, const char * uniqueID) { int r, pinholePackets = 0; if(!uniqueID) { fprintf(stderr, "invalid arguments\n"); return; } r = UPNP_GetPinholePackets(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &pinholePackets); if(r!=UPNPCOMMAND_SUCCESS) printf("GetPinholePackets() failed with code %d (%s)\n", r, strupnperror(r)); else printf("GetPinholePackets: Pinhole ID = %s / PinholePackets = %d\n", uniqueID, pinholePackets); } static void CheckPinhole(struct UPNPUrls * urls, struct IGDdatas * data, const char * uniqueID) { int r, isWorking = 0; if(!uniqueID) { fprintf(stderr, "invalid arguments\n"); return; } r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking); if(r!=UPNPCOMMAND_SUCCESS) printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); else printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No"); } static void RemovePinhole(struct UPNPUrls * urls, struct IGDdatas * data, const char * uniqueID) { int r; if(!uniqueID) { fprintf(stderr, "invalid arguments\n"); return; } r = UPNP_DeletePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID); printf("UPNP_DeletePinhole() returned : %d\n", r); } /* sample upnp client program */ int main(int argc, char ** argv) { char command = 0; char ** commandargv = 0; int commandargc = 0; struct UPNPDev * devlist = 0; char lanaddr[64]; /* my ip address on the LAN */ int i; const char * rootdescurl = 0; const char * multicastif = 0; const char * minissdpdpath = 0; int retcode = 0; int error = 0; int ipv6 = 0; const char * description = 0; #ifdef _WIN32 WSADATA wsaData; int nResult = WSAStartup(MAKEWORD(2,2), &wsaData); if(nResult != NO_ERROR) { fprintf(stderr, "WSAStartup() failed.\n"); return -1; } #endif printf("upnpc : miniupnpc library test client. (c) 2005-2014 Thomas Bernard\n"); printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n" "for more information.\n"); /* command line processing */ for(i=1; ipNext) { printf(" desc: %s\n st: %s\n\n", device->descURL, device->st); } } else { printf("upnpDiscover() error code=%d\n", error); } i = 1; if( (rootdescurl && UPNP_GetIGDFromUrl(rootdescurl, &urls, &data, lanaddr, sizeof(lanaddr))) || (i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)))) { switch(i) { case 1: printf("Found valid IGD : %s\n", urls.controlURL); break; case 2: printf("Found a (not connected?) IGD : %s\n", urls.controlURL); printf("Trying to continue anyway\n"); break; case 3: printf("UPnP device found. Is it an IGD ? : %s\n", urls.controlURL); printf("Trying to continue anyway\n"); break; default: printf("Found device (igd ?) : %s\n", urls.controlURL); printf("Trying to continue anyway\n"); } printf("Local LAN ip address : %s\n", lanaddr); #if 0 printf("getting \"%s\"\n", urls.ipcondescURL); descXML = miniwget(urls.ipcondescURL, &descXMLsize); if(descXML) { /*fwrite(descXML, 1, descXMLsize, stdout);*/ free(descXML); descXML = NULL; } #endif switch(command) { case 'l': DisplayInfos(&urls, &data); ListRedirections(&urls, &data); break; case 'L': NewListRedirections(&urls, &data); break; case 'a': SetRedirectAndTest(&urls, &data, commandargv[0], commandargv[1], commandargv[2], commandargv[3], (commandargc > 4)?commandargv[4]:"0", description, 0); break; case 'd': for(i=0; i 4)?commandargv[4]:"0", description, 1); break; case 'N': if (commandargc < 3) fprintf(stderr, "too few arguments\n"); RemoveRedirectRange(&urls, &data, commandargv[0], commandargv[1], commandargv[2], commandargc > 3 ? commandargv[3] : NULL); break; case 's': GetConnectionStatus(&urls, &data); break; case 'r': for(i=0; i #include #include #include "minixml.h" #include "igd_desc_parse.h" /* ---------------------------------------------------------------------- */ void printeltname1(void * d, const char * name, int l) { int i; (void)d; printf("element "); for(i=0;i #include #ifdef _WIN32 #include #include #define snprintf _snprintf #else #include #include #include #endif #include "minisoap.h" #include "miniupnpcstrings.h" /* only for malloc */ #include #ifdef _WIN32 #define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); #else #define PRINT_SOCKET_ERROR(x) perror(x) #endif /* httpWrite sends the headers and the body to the socket * and returns the number of bytes sent */ static int httpWrite(int fd, const char * body, int bodysize, const char * headers, int headerssize) { int n = 0; /*n = write(fd, headers, headerssize);*/ /*if(bodysize>0) n += write(fd, body, bodysize);*/ /* Note : my old linksys router only took into account * soap request that are sent into only one packet */ char * p; /* TODO: AVOID MALLOC */ p = malloc(headerssize+bodysize); if(!p) return 0; memcpy(p, headers, headerssize); memcpy(p+headerssize, body, bodysize); /*n = write(fd, p, headerssize+bodysize);*/ n = send(fd, p, headerssize+bodysize, 0); if(n<0) { PRINT_SOCKET_ERROR("send"); } /* disable send on the socket */ /* draytek routers dont seems to like that... */ #if 0 #ifdef _WIN32 if(shutdown(fd, SD_SEND)<0) { #else if(shutdown(fd, SHUT_WR)<0) { /*SD_SEND*/ #endif PRINT_SOCKET_ERROR("shutdown"); } #endif free(p); return n; } /* self explanatory */ int soapPostSubmit(int fd, const char * url, const char * host, unsigned short port, const char * action, const char * body, const char * httpversion) { int bodysize; char headerbuf[512]; int headerssize; char portstr[8]; bodysize = (int)strlen(body); /* We are not using keep-alive HTTP connections. * HTTP/1.1 needs the header Connection: close to do that. * This is the default with HTTP/1.0 * Using HTTP/1.1 means we need to support chunked transfer-encoding : * When using HTTP/1.1, the router "BiPAC 7404VNOX" always use chunked * transfer encoding. */ /* Connection: Close is normally there only in HTTP/1.1 but who knows */ portstr[0] = '\0'; if(port != 80) snprintf(portstr, sizeof(portstr), ":%hu", port); headerssize = snprintf(headerbuf, sizeof(headerbuf), "POST %s HTTP/%s\r\n" "Host: %s%s\r\n" "User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" "Content-Length: %d\r\n" "Content-Type: text/xml\r\n" "SOAPAction: \"%s\"\r\n" "Connection: Close\r\n" "Cache-Control: no-cache\r\n" /* ??? */ "Pragma: no-cache\r\n" "\r\n", url, httpversion, host, portstr, bodysize, action); #ifdef DEBUG /*printf("SOAP request : headersize=%d bodysize=%d\n", headerssize, bodysize); */ printf("SOAP request : POST %s HTTP/%s - Host: %s%s\n", url, httpversion, host, portstr); printf("SOAPAction: \"%s\" - Content-Length: %d\n", action, bodysize); printf("Headers :\n%s", headerbuf); printf("Body :\n%s\n", body); #endif return httpWrite(fd, body, bodysize, headerbuf, headerssize); } miniupnpc-1.9.20140610/minisoap.h010064400017500000024000000007621203340733500154400ustar00nanardstaff/* $Id: minisoap.h,v 1.5 2012/09/27 15:42:10 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2005 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ #ifndef MINISOAP_H_INCLUDED #define MINISOAP_H_INCLUDED /*int httpWrite(int, const char *, int, const char *);*/ int soapPostSubmit(int, const char *, const char *, unsigned short, const char *, const char *, const char *); #endif miniupnpc-1.9.20140610/miniupnpc.c010064400017500000024000000704721234555371300156330ustar00nanardstaff/* $Id: miniupnpc.c,v 1.118 2014/06/10 09:43:41 nanard Exp $ */ /* Project : miniupnp * Web : http://miniupnp.free.fr/ * Author : Thomas BERNARD * copyright (c) 2005-2014 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENSE file. */ #define __EXTENSIONS__ 1 #if !defined(MACOSX) && !defined(__sun) #if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) && !defined(__NetBSD__) #ifndef __cplusplus #define _XOPEN_SOURCE 600 #endif #endif #ifndef __BSD_VISIBLE #define __BSD_VISIBLE 1 #endif #endif #if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(MACOSX) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) && !defined(__GNU__) && !defined(__FreeBSD_kernel__) #define HAS_IP_MREQN #endif #include #include #include #ifdef _WIN32 /* Win32 Specific includes and defines */ #include #include #include #include #define snprintf _snprintf #define strdup _strdup #ifndef strncasecmp #if defined(_MSC_VER) && (_MSC_VER >= 1400) #define strncasecmp _memicmp #else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ #define strncasecmp memicmp #endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ #endif /* #ifndef strncasecmp */ #define MAXHOSTNAMELEN 64 #else /* #ifdef _WIN32 */ /* Standard POSIX includes */ #include #if defined(__amigaos__) && !defined(__amigaos4__) /* Amiga OS 3 specific stuff */ #define socklen_t int #else #include #endif #include #include #include #include #include #include #include #if !defined(__amigaos__) && !defined(__amigaos4__) #include #endif #include #include #define closesocket close #endif /* #else _WIN32 */ #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT #include #endif #if defined(__amigaos__) || defined(__amigaos4__) /* Amiga OS specific stuff */ #define TIMEVAL struct timeval #endif #ifdef __GNU__ #define MAXHOSTNAMELEN 64 #endif #if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN) /* Several versions of glibc don't define this structure, define it here and compile with CFLAGS NEED_STRUCT_IP_MREQN */ struct ip_mreqn { struct in_addr imr_multiaddr; /* IP multicast address of group */ struct in_addr imr_address; /* local IP address of interface */ int imr_ifindex; /* Interface index */ }; #endif #include "miniupnpc.h" #include "minissdpc.h" #include "miniwget.h" #include "minisoap.h" #include "minixml.h" #include "upnpcommands.h" #include "connecthostport.h" #include "receivedata.h" #ifdef _WIN32 #define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); #else #define PRINT_SOCKET_ERROR(x) perror(x) #endif #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif #define SOAPPREFIX "s" #define SERVICEPREFIX "u" #define SERVICEPREFIX2 'u' /* root description parsing */ MINIUPNP_LIBSPEC 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); #ifdef DEBUG printIGD(data); #endif } /* simpleUPnPcommand2 : * not so simple ! * return values : * pointer - OK * NULL - error */ char * simpleUPnPcommand2(int s, const char * url, const char * service, const char * action, struct UPNParg * args, int * bufsize, const char * httpversion) { char hostname[MAXHOSTNAMELEN+1]; unsigned short port = 0; char * path; char soapact[128]; char soapbody[2048]; char * buf; int n; *bufsize = 0; snprintf(soapact, sizeof(soapact), "%s#%s", service, action); if(args==NULL) { /*soapbodylen = */snprintf(soapbody, sizeof(soapbody), "\r\n" "<" SOAPPREFIX ":Envelope " "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" "<" SOAPPREFIX ":Body>" "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">" "" "" "\r\n", action, service, action); } else { char * p; const char * pe, * pv; int soapbodylen; soapbodylen = snprintf(soapbody, sizeof(soapbody), "\r\n" "<" SOAPPREFIX ":Envelope " "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" "<" SOAPPREFIX ":Body>" "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%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 */ return NULL; } *(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++) = SERVICEPREFIX2; *(p++) = ':'; pe = action; while(*pe) *(p++) = *(pe++); strncpy(p, ">\r\n", soapbody + sizeof(soapbody) - p); } if(!parseURL(url, hostname, &port, &path, NULL)) return NULL; if(s < 0) { s = connecthostport(hostname, port, 0); if(s < 0) { /* failed to connect */ return NULL; } } n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion); if(n<=0) { #ifdef DEBUG printf("Error sending SOAP request\n"); #endif closesocket(s); return NULL; } buf = getHTTPResponse(s, bufsize); #ifdef DEBUG if(*bufsize > 0 && buf) { printf("SOAP Response :\n%.*s\n", *bufsize, buf); } #endif closesocket(s); return buf; } /* simpleUPnPcommand : * not so simple ! * return values : * pointer - OK * NULL - error */ char * simpleUPnPcommand(int s, const char * url, const char * service, const char * action, struct UPNParg * args, int * bufsize) { char * buf; #if 1 buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); #else buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.0"); if (!buf || *bufsize == 0) { #if DEBUG printf("Error or no result from SOAP request; retrying with HTTP/1.1\n"); #endif buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); } #endif return buf; } /* 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 void parseMSEARCHReply(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; /* end of the "header" (position of the colon) */ while(isin6_family = AF_INET6; if(sameport) p->sin6_port = htons(PORT); p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */ } else { struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r; p->sin_family = AF_INET; if(sameport) p->sin_port = htons(PORT); p->sin_addr.s_addr = INADDR_ANY; } #ifdef _WIN32 /* This code could help us to use the right Network interface for * SSDP multicast traffic */ /* Get IP associated with the index given in the ip_forward struct * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */ if(!ipv6 && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) { DWORD dwRetVal = 0; PMIB_IPADDRTABLE pIPAddrTable; DWORD dwSize = 0; #ifdef DEBUG IN_ADDR IPAddr; #endif int i; #ifdef DEBUG printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop); #endif pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE)); if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { free(pIPAddrTable); pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize); } if(pIPAddrTable) { dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 ); #ifdef DEBUG printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries); #endif for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) { #ifdef DEBUG printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex); IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr; printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask; printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr; printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr); printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize); printf("\tType and State[%d]:", i); printf("\n"); #endif if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) { /* Set the address of this interface to be used */ struct in_addr mc_if; memset(&mc_if, 0, sizeof(mc_if)); mc_if.s_addr = pIPAddrTable->table[i].dwAddr; if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr; #ifndef DEBUG break; #endif } } free(pIPAddrTable); pIPAddrTable = NULL; } } #endif #ifdef _WIN32 if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0) #else if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0) #endif { if(error) *error = UPNPDISCOVER_SOCKET_ERROR; PRINT_SOCKET_ERROR("setsockopt"); return NULL; } if(multicastif) { if(ipv6) { #if !defined(_WIN32) /* according to MSDN, if_nametoindex() is supported since * MS Windows Vista and MS Windows Server 2008. * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */ unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */ if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(&ifindex)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } #else #ifdef DEBUG printf("Setting of multicast interface not supported in IPv6 under Windows.\n"); #endif #endif } else { struct in_addr mc_if; mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */ if(mc_if.s_addr != INADDR_NONE) { ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } } else { #ifdef HAS_IP_MREQN /* was not an ip address, try with an interface name */ struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */ memset(&reqn, 0, sizeof(struct ip_mreqn)); reqn.imr_ifindex = if_nametoindex(multicastif); if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } #else #ifdef DEBUG printf("Setting of multicast interface not supported with interface name.\n"); #endif #endif } } } /* Before sending the packed, we first "bind" in order to be able * to receive the response */ if (bind(sudp, (const struct sockaddr *)&sockudp_r, ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0) { if(error) *error = UPNPDISCOVER_SOCKET_ERROR; PRINT_SOCKET_ERROR("bind"); closesocket(sudp); return NULL; } if(error) *error = UPNPDISCOVER_SUCCESS; /* Calculating maximum response time in seconds */ mx = ((unsigned int)delay) / 1000u; if(mx == 0) { mx = 1; delay = 1000; } /* receiving SSDP response packet */ for(n = 0; deviceList[deviceIndex]; deviceIndex++) { if(n == 0) { /* sending the SSDP M-SEARCH packet */ n = snprintf(bufr, sizeof(bufr), MSearchMsgFmt, ipv6 ? (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") : UPNP_MCAST_ADDR, deviceList[deviceIndex], mx); #ifdef DEBUG printf("Sending %s", bufr); #endif #ifdef NO_GETADDRINFO /* the following code is not using getaddrinfo */ /* emission */ memset(&sockudp_w, 0, sizeof(struct sockaddr_storage)); if(ipv6) { struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w; p->sin6_family = AF_INET6; p->sin6_port = htons(PORT); inet_pton(AF_INET6, linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR, &(p->sin6_addr)); } else { struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w; p->sin_family = AF_INET; p->sin_port = htons(PORT); p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR); } n = sendto(sudp, bufr, n, 0, &sockudp_w, ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); if (n < 0) { if(error) *error = UPNPDISCOVER_SOCKET_ERROR; PRINT_SOCKET_ERROR("sendto"); break; } #else /* #ifdef NO_GETADDRINFO */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */ hints.ai_socktype = SOCK_DGRAM; /*hints.ai_flags = */ if ((rv = getaddrinfo(ipv6 ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR) : UPNP_MCAST_ADDR, XSTR(PORT), &hints, &servinfo)) != 0) { if(error) *error = UPNPDISCOVER_SOCKET_ERROR; #ifdef _WIN32 fprintf(stderr, "getaddrinfo() failed: %d\n", rv); #else fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); #endif break; } for(p = servinfo; p; p = p->ai_next) { n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen); if (n < 0) { #ifdef DEBUG char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf); } #endif PRINT_SOCKET_ERROR("sendto"); continue; } } freeaddrinfo(servinfo); if(n < 0) { if(error) *error = UPNPDISCOVER_SOCKET_ERROR; break; } #endif /* #ifdef NO_GETADDRINFO */ } /* Waiting for SSDP REPLY packet to M-SEARCH */ n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id); if (n < 0) { /* error */ if(error) *error = UPNPDISCOVER_SOCKET_ERROR; break; } else if (n == 0) { /* no data or Time Out */ if (devlist) { /* no more device type to look for... */ if(error) *error = UPNPDISCOVER_SUCCESS; break; } if(ipv6) { if(linklocal) { linklocal = 0; --deviceIndex; } else { linklocal = 1; } } } else { const char * descURL=NULL; int urlsize=0; const char * st=NULL; int stsize=0; /*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */ parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize); if(st&&descURL) { #ifdef DEBUG printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n", stsize, st, urlsize, descURL); #endif for(tmp=devlist; tmp; tmp = tmp->pNext) { if(memcmp(tmp->descURL, descURL, urlsize) == 0 && tmp->descURL[urlsize] == '\0' && memcmp(tmp->st, st, stsize) == 0 && tmp->st[stsize] == '\0') break; } /* at the exit of the loop above, tmp is null if * no duplicate device was found */ if(tmp) continue; tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize); if(!tmp) { /* memory allocation error */ if(error) *error = UPNPDISCOVER_MEMORY_ERROR; break; } tmp->pNext = devlist; tmp->descURL = tmp->buffer; tmp->st = tmp->buffer + 1 + urlsize; memcpy(tmp->buffer, descURL, urlsize); tmp->buffer[urlsize] = '\0'; memcpy(tmp->buffer + urlsize + 1, st, stsize); tmp->buffer[urlsize+1+stsize] = '\0'; tmp->scope_id = scope_id; devlist = tmp; } } } closesocket(sudp); return devlist; } /* freeUPNPDevlist() should be used to * free the chained list returned by upnpDiscover() */ MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist) { struct UPNPDev * next; while(devlist) { next = devlist->pNext; free(devlist); devlist = next; } } static void url_cpy_or_cat(char * dst, const char * src, int n) { if( (src[0] == 'h') &&(src[1] == 't') &&(src[2] == 't') &&(src[3] == 'p') &&(src[4] == ':') &&(src[5] == '/') &&(src[6] == '/')) { strncpy(dst, src, n); } else { int l = strlen(dst); if(src[0] != '/') dst[l++] = '/'; if(l<=n) strncpy(dst + l, src, n - l); } } /* Prepare the Urls for usage... */ MINIUPNP_LIBSPEC void GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data, const char * descURL, unsigned int scope_id) { char * p; int n1, n2, n3, n4; #ifdef IF_NAMESIZE char ifname[IF_NAMESIZE]; #else char scope_str[8]; #endif n1 = strlen(data->urlbase); if(n1==0) n1 = strlen(descURL); if(scope_id != 0) { #ifdef IF_NAMESIZE if(if_indextoname(scope_id, ifname)) { n1 += 3 + strlen(ifname); /* 3 == strlen(%25) */ } #else /* under windows, scope is numerical */ snprintf(scope_str, sizeof(scope_str), "%u", scope_id); #endif } n1 += 2; /* 1 byte more for Null terminator, 1 byte for '/' if needed */ n2 = n1; n3 = n1; n4 = n1; n1 += strlen(data->first.scpdurl); n2 += strlen(data->first.controlurl); n3 += strlen(data->CIF.controlurl); n4 += strlen(data->IPv6FC.controlurl); /* allocate memory to store URLs */ urls->ipcondescURL = (char *)malloc(n1); urls->controlURL = (char *)malloc(n2); urls->controlURL_CIF = (char *)malloc(n3); urls->controlURL_6FC = (char *)malloc(n4); /* strdup descURL */ urls->rootdescURL = strdup(descURL); /* get description of WANIPConnection */ if(data->urlbase[0] != '\0') strncpy(urls->ipcondescURL, data->urlbase, n1); else strncpy(urls->ipcondescURL, descURL, n1); p = strchr(urls->ipcondescURL+7, '/'); if(p) p[0] = '\0'; if(scope_id != 0) { if(0 == memcmp(urls->ipcondescURL, "http://[fe80:", 13)) { /* this is a linklocal IPv6 address */ p = strchr(urls->ipcondescURL, ']'); if(p) { /* insert %25 into URL */ #ifdef IF_NAMESIZE memmove(p + 3 + strlen(ifname), p, strlen(p) + 1); memcpy(p, "%25", 3); memcpy(p + 3, ifname, strlen(ifname)); #else memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1); memcpy(p, "%25", 3); memcpy(p + 3, scope_str, strlen(scope_str)); #endif } } } strncpy(urls->controlURL, urls->ipcondescURL, n2); strncpy(urls->controlURL_CIF, urls->ipcondescURL, n3); strncpy(urls->controlURL_6FC, urls->ipcondescURL, n4); url_cpy_or_cat(urls->ipcondescURL, data->first.scpdurl, n1); url_cpy_or_cat(urls->controlURL, data->first.controlurl, n2); url_cpy_or_cat(urls->controlURL_CIF, data->CIF.controlurl, n3); url_cpy_or_cat(urls->controlURL_6FC, data->IPv6FC.controlurl, n4); #ifdef DEBUG printf("urls->ipcondescURL='%s' %u n1=%d\n", urls->ipcondescURL, (unsigned)strlen(urls->ipcondescURL), n1); printf("urls->controlURL='%s' %u n2=%d\n", urls->controlURL, (unsigned)strlen(urls->controlURL), n2); printf("urls->controlURL_CIF='%s' %u n3=%d\n", urls->controlURL_CIF, (unsigned)strlen(urls->controlURL_CIF), n3); printf("urls->controlURL_6FC='%s' %u n4=%d\n", urls->controlURL_6FC, (unsigned)strlen(urls->controlURL_6FC), n4); #endif } MINIUPNP_LIBSPEC void FreeUPNPUrls(struct UPNPUrls * urls) { if(!urls) return; free(urls->controlURL); urls->controlURL = 0; free(urls->ipcondescURL); urls->ipcondescURL = 0; free(urls->controlURL_CIF); urls->controlURL_CIF = 0; free(urls->controlURL_6FC); urls->controlURL_6FC = 0; free(urls->rootdescURL); urls->rootdescURL = 0; } int UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data) { char status[64]; unsigned int uptime; status[0] = '\0'; UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, status, &uptime, NULL); if(0 == strcmp("Connected", status)) { return 1; } else return 0; } /* UPNP_GetValidIGD() : * return values : * -1 = Internal error * 0 = NO IGD found * 1 = A valid connected IGD has been found * 2 = A valid IGD has been found but it reported as * not connected * 3 = an UPnP device has been found but was not recognized as an IGD * * In any positive non zero return case, the urls and data structures * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to * free allocated memory. */ MINIUPNP_LIBSPEC int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen) { struct xml_desc { char * xml; int size; int is_igd; } * desc = NULL; struct UPNPDev * dev; int ndev = 0; int i; int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ int n_igd = 0; char extIpAddr[16]; if(!devlist) { #ifdef DEBUG printf("Empty devlist\n"); #endif return 0; } /* counting total number of devices in the list */ for(dev = devlist; dev; dev = dev->pNext) ndev++; if(ndev > 0) { desc = calloc(ndev, sizeof(struct xml_desc)); if(!desc) return -1; /* memory allocation error */ } /* Step 1 : downloading descriptions and testing type */ for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) { /* we should choose an internet gateway device. * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */ desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size), lanaddr, lanaddrlen, dev->scope_id); #ifdef DEBUG if(!desc[i].xml) { printf("error getting XML description %s\n", dev->descURL); } #endif if(desc[i].xml) { memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); parserootdesc(desc[i].xml, desc[i].size, data); if(0==strcmp(data->CIF.servicetype, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) { desc[i].is_igd = 1; n_igd++; } } } /* iterate the list to find a device depending on state */ for(state = 1; state <= 3; state++) { for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) { if(desc[i].xml) { memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); parserootdesc(desc[i].xml, desc[i].size, data); if(desc[i].is_igd || state >= 3 ) { GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); /* in state 2 and 3 we dont test if device is connected ! */ if(state >= 2) goto free_and_return; #ifdef DEBUG printf("UPNPIGD_IsConnected(%s) = %d\n", urls->controlURL, UPNPIGD_IsConnected(urls, data)); #endif /* checks that status is connected AND there is a external IP address assigned */ if(UPNPIGD_IsConnected(urls, data) && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) goto free_and_return; FreeUPNPUrls(urls); if(data->second.servicetype[0] != '\0') { #ifdef DEBUG printf("We tried %s, now we try %s !\n", data->first.servicetype, data->second.servicetype); #endif /* swaping WANPPPConnection and WANIPConnection ! */ memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service)); memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service)); memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service)); GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); #ifdef DEBUG printf("UPNPIGD_IsConnected(%s) = %d\n", urls->controlURL, UPNPIGD_IsConnected(urls, data)); #endif if(UPNPIGD_IsConnected(urls, data) && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) goto free_and_return; FreeUPNPUrls(urls); } } memset(data, 0, sizeof(struct IGDdatas)); } } } state = 0; free_and_return: if(desc) { for(i = 0; i < ndev; i++) { if(desc[i].xml) { free(desc[i].xml); } } free(desc); } return state; } /* UPNP_GetIGDFromUrl() * Used when skipping the discovery process. * return value : * 0 - Not ok * 1 - OK */ int UPNP_GetIGDFromUrl(const char * rootdescurl, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen) { char * descXML; int descXMLsize = 0; descXML = miniwget_getaddr(rootdescurl, &descXMLsize, lanaddr, lanaddrlen, 0); if(descXML) { memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); parserootdesc(descXML, descXMLsize, data); free(descXML); descXML = NULL; GetUPNPUrls(urls, data, rootdescurl, 0); return 1; } else { return 0; } } miniupnpc-1.9.20140610/miniupnpc.h010064400017500000024000000075101234555667500156430ustar00nanardstaff/* $Id: miniupnpc.h,v 1.36 2014/06/10 09:43:41 nanard Exp $ */ /* Project: miniupnp * http://miniupnp.free.fr/ * Author: Thomas Bernard * Copyright (c) 2005-2012 Thomas Bernard * This software is subjects to the conditions detailed * in the LICENCE file provided within this distribution */ #ifndef MINIUPNPC_H_INCLUDED #define MINIUPNPC_H_INCLUDED #include "declspec.h" #include "igd_desc_parse.h" /* error codes : */ #define UPNPDISCOVER_SUCCESS (0) #define UPNPDISCOVER_UNKNOWN_ERROR (-1) #define UPNPDISCOVER_SOCKET_ERROR (-101) #define UPNPDISCOVER_MEMORY_ERROR (-102) /* versions : */ #define MINIUPNPC_VERSION "1.9.20140610" #define MINIUPNPC_API_VERSION 10 #ifdef __cplusplus extern "C" { #endif /* Structures definitions : */ struct UPNParg { const char * elt; const char * val; }; char * simpleUPnPcommand(int, const char *, const char *, const char *, struct UPNParg *, int *); struct UPNPDev { struct UPNPDev * pNext; char * descURL; char * st; unsigned int scope_id; char buffer[2]; }; /* upnpDiscover() * discover UPnP devices on the network. * The discovered devices are returned as a chained list. * It is up to the caller to free the list with freeUPNPDevlist(). * delay (in millisecond) is the maximum time for waiting any device * response. * If available, device list will be obtained from MiniSSDPd. * Default path for minissdpd socket will be used if minissdpdsock argument * is NULL. * If multicastif is not NULL, it will be used instead of the default * multicast interface for sending SSDP discover packets. * If sameport is not null, SSDP packets will be sent from the source port * 1900 (same as destination port) otherwise system assign a source port. */ MINIUPNP_LIBSPEC struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport, int ipv6, int * error); /* freeUPNPDevlist() * free list returned by upnpDiscover() */ MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist); /* parserootdesc() : * parse root XML description of a UPnP device and fill the IGDdatas * structure. */ MINIUPNP_LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *); /* structure used to get fast access to urls * controlURL: controlURL of the WANIPConnection * ipcondescURL: url of the description of the WANIPConnection * controlURL_CIF: controlURL of the WANCommonInterfaceConfig * controlURL_6FC: controlURL of the WANIPv6FirewallControl */ struct UPNPUrls { char * controlURL; char * ipcondescURL; char * controlURL_CIF; char * controlURL_6FC; char * rootdescURL; }; /* UPNP_GetValidIGD() : * return values : * 0 = NO IGD found * 1 = A valid connected IGD has been found * 2 = A valid IGD has been found but it reported as * not connected * 3 = an UPnP device has been found but was not recognized as an IGD * * In any non zero return case, the urls and data structures * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to * free allocated memory. */ MINIUPNP_LIBSPEC int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen); /* UPNP_GetIGDFromUrl() * Used when skipping the discovery process. * return value : * 0 - Not ok * 1 - OK */ MINIUPNP_LIBSPEC int UPNP_GetIGDFromUrl(const char * rootdescurl, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen); MINIUPNP_LIBSPEC void GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, const char *, unsigned int); MINIUPNP_LIBSPEC void FreeUPNPUrls(struct UPNPUrls *); /* return 0 or 1 */ MINIUPNP_LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); #ifdef __cplusplus } #endif #endif miniupnpc-1.9.20140610/README010064400017500000024000000041311175640011300143200ustar00nanardstaffProject: miniupnp Project web page: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ github: https://github.com/miniupnp/miniupnp freecode: http://freecode.com/projects/miniupnp Author: Thomas Bernard Copyright (c) 2005-2012 Thomas Bernard This software is subject to the conditions detailed in the LICENSE file provided within this distribution. For the comfort of Win32 users, bsdqueue.h is included in the distribution. Its licence is included in the header of the file. bsdqueue.h is a copy of the sys/queue.h of an OpenBSD system. * miniUPnP Client - miniUPnPc * To compile, simply run 'gmake' (could be 'make' on your system). Under win32, to compile with MinGW, type "mingw32make.bat". MS Visual C solution and project files are supplied in the msvc/ subdirectory. The compilation is known to work under linux, FreeBSD, OpenBSD, MacOS X, AmigaOS and cygwin. The official AmigaOS4.1 SDK was used for AmigaOS4 and GeekGadgets for AmigaOS3. upx (http://upx.sourceforge.net) is used to compress the win32 .exe files. To install the library and headers on the system use : > su > make install > exit alternatively, to install into a specific location, use : > INSTALLPREFIX=/usr/local make install upnpc.c is a sample client using the libminiupnpc. To use the libminiupnpc in your application, link it with libminiupnpc.a (or .so) and use the following functions found in miniupnpc.h, upnpcommands.h and miniwget.h : - upnpDiscover() - miniwget() - parserootdesc() - GetUPNPUrls() - UPNP_* (calling UPNP methods) Note : use #include etc... for the includes and -lminiupnpc for the link Discovery process is speeded up when MiniSSDPd is running on the machine. * Python module * you can build a python module with 'make pythonmodule' and install it with 'make installpythonmodule'. setup.py (and setupmingw32.py) are included in the distribution. Feel free to contact me if you have any problem : e-mail : miniupnp@free.fr If you are using libminiupnpc in your application, please send me an email ! For any question, you can use the web forum : http://miniupnp.tuxfamily.org/forum/ miniupnpc-1.9.20140610/LICENSE010064400017500000024000000027101233650314400144510ustar00nanardstaffMiniUPnPc Copyright (c) 2005-2014, Thomas BERNARD All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. miniupnpc-1.9.20140610/upnpcommands.c010064400017500000024000001035621234555371500163340ustar00nanardstaff/* $Id: upnpcommands.c,v 1.44 2014/06/10 09:44:07 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2005-2012 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ #include #include #include #include "upnpcommands.h" #include "miniupnpc.h" #include "portlistingparse.h" static UNSIGNED_INTEGER my_atoui(const char * s) { return s ? ((UNSIGNED_INTEGER)STRTOUI(s, NULL, 0)) : 0; } /* * */ MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalBytesSent(const char * controlURL, const char * servicetype) { struct NameValueParserData pdata; char * buffer; int bufsize; unsigned int r = 0; char * p; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalBytesSent", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "NewTotalBytesSent"); r = my_atoui(p); ClearNameValueList(&pdata); return r; } /* * */ MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalBytesReceived(const char * controlURL, const char * servicetype) { struct NameValueParserData pdata; char * buffer; int bufsize; unsigned int r = 0; char * p; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalBytesReceived", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "NewTotalBytesReceived"); r = my_atoui(p); ClearNameValueList(&pdata); return r; } /* * */ MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalPacketsSent(const char * controlURL, const char * servicetype) { struct NameValueParserData pdata; char * buffer; int bufsize; unsigned int r = 0; char * p; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalPacketsSent", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "NewTotalPacketsSent"); r = my_atoui(p); ClearNameValueList(&pdata); return r; } /* * */ MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalPacketsReceived(const char * controlURL, const char * servicetype) { struct NameValueParserData pdata; char * buffer; int bufsize; unsigned int r = 0; char * p; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalPacketsReceived", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "NewTotalPacketsReceived"); r = my_atoui(p); ClearNameValueList(&pdata); return r; } /* UPNP_GetStatusInfo() call the corresponding UPNP method * returns the current status and uptime */ MINIUPNP_LIBSPEC int UPNP_GetStatusInfo(const char * controlURL, const char * servicetype, char * status, unsigned int * uptime, char * lastconnerror) { struct NameValueParserData pdata; char * buffer; int bufsize; char * p; char * up; char * err; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!status && !uptime) return UPNPCOMMAND_INVALID_ARGS; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetStatusInfo", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ free(buffer); buffer = NULL; up = GetValueFromNameValueList(&pdata, "NewUptime"); p = GetValueFromNameValueList(&pdata, "NewConnectionStatus"); err = GetValueFromNameValueList(&pdata, "NewLastConnectionError"); if(p && up) ret = UPNPCOMMAND_SUCCESS; if(status) { if(p){ strncpy(status, p, 64 ); status[63] = '\0'; }else status[0]= '\0'; } if(uptime) { if(up) sscanf(up,"%u",uptime); else uptime = 0; } if(lastconnerror) { if(err) { strncpy(lastconnerror, err, 64 ); lastconnerror[63] = '\0'; } else lastconnerror[0] = '\0'; } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } /* UPNP_GetConnectionTypeInfo() call the corresponding UPNP method * returns the connection type */ MINIUPNP_LIBSPEC int UPNP_GetConnectionTypeInfo(const char * controlURL, const char * servicetype, char * connectionType) { struct NameValueParserData pdata; char * buffer; int bufsize; char * p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!connectionType) return UPNPCOMMAND_INVALID_ARGS; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetConnectionTypeInfo", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "NewConnectionType"); /*p = GetValueFromNameValueList(&pdata, "NewPossibleConnectionTypes");*/ /* PossibleConnectionTypes will have several values.... */ if(p) { strncpy(connectionType, p, 64 ); connectionType[63] = '\0'; ret = UPNPCOMMAND_SUCCESS; } else connectionType[0] = '\0'; p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } /* UPNP_GetLinkLayerMaxBitRate() call the corresponding UPNP method. * Returns 2 values: Downloadlink bandwidth and Uplink bandwidth. * One of the values can be null * Note : GetLinkLayerMaxBitRates belongs to WANPPPConnection:1 only * We can use the GetCommonLinkProperties from WANCommonInterfaceConfig:1 */ MINIUPNP_LIBSPEC int UPNP_GetLinkLayerMaxBitRates(const char * controlURL, const char * servicetype, unsigned int * bitrateDown, unsigned int * bitrateUp) { struct NameValueParserData pdata; char * buffer; int bufsize; int ret = UPNPCOMMAND_UNKNOWN_ERROR; char * down; char * up; char * p; if(!bitrateDown && !bitrateUp) return UPNPCOMMAND_INVALID_ARGS; /* shouldn't we use GetCommonLinkProperties ? */ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetCommonLinkProperties", 0, &bufsize))) { /*"GetLinkLayerMaxBitRates", 0, &bufsize);*/ return UPNPCOMMAND_HTTP_ERROR; } /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; /*down = GetValueFromNameValueList(&pdata, "NewDownstreamMaxBitRate");*/ /*up = GetValueFromNameValueList(&pdata, "NewUpstreamMaxBitRate");*/ down = GetValueFromNameValueList(&pdata, "NewLayer1DownstreamMaxBitRate"); up = GetValueFromNameValueList(&pdata, "NewLayer1UpstreamMaxBitRate"); /*GetValueFromNameValueList(&pdata, "NewWANAccessType");*/ /*GetValueFromNameValueList(&pdata, "NewPhysicalLinkStatus");*/ if(down && up) ret = UPNPCOMMAND_SUCCESS; if(bitrateDown) { if(down) sscanf(down,"%u",bitrateDown); else *bitrateDown = 0; } if(bitrateUp) { if(up) sscanf(up,"%u",bitrateUp); else *bitrateUp = 0; } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } /* UPNP_GetExternalIPAddress() call the corresponding UPNP method. * if the third arg is not null the value is copied to it. * at least 16 bytes must be available * * Return values : * 0 : SUCCESS * NON ZERO : ERROR Either an UPnP error code or an unknown error. * * 402 Invalid Args - See UPnP Device Architecture section on Control. * 501 Action Failed - See UPnP Device Architecture section on Control. */ MINIUPNP_LIBSPEC int UPNP_GetExternalIPAddress(const char * controlURL, const char * servicetype, char * extIpAdd) { struct NameValueParserData pdata; char * buffer; int bufsize; char * p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!extIpAdd || !controlURL || !servicetype) return UPNPCOMMAND_INVALID_ARGS; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetExternalIPAddress", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; /*printf("external ip = %s\n", GetValueFromNameValueList(&pdata, "NewExternalIPAddress") );*/ p = GetValueFromNameValueList(&pdata, "NewExternalIPAddress"); if(p) { strncpy(extIpAdd, p, 16 ); extIpAdd[15] = '\0'; ret = UPNPCOMMAND_SUCCESS; } else extIpAdd[0] = '\0'; p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } MINIUPNP_LIBSPEC int UPNP_AddPortMapping(const char * controlURL, const char * servicetype, const char * extPort, const char * inPort, const char * inClient, const char * desc, const char * proto, const char * remoteHost, const char * leaseDuration) { struct UPNParg * AddPortMappingArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; int ret; if(!inPort || !inClient || !proto || !extPort) return UPNPCOMMAND_INVALID_ARGS; AddPortMappingArgs = calloc(9, sizeof(struct UPNParg)); AddPortMappingArgs[0].elt = "NewRemoteHost"; AddPortMappingArgs[0].val = remoteHost; AddPortMappingArgs[1].elt = "NewExternalPort"; AddPortMappingArgs[1].val = extPort; AddPortMappingArgs[2].elt = "NewProtocol"; AddPortMappingArgs[2].val = proto; AddPortMappingArgs[3].elt = "NewInternalPort"; AddPortMappingArgs[3].val = inPort; AddPortMappingArgs[4].elt = "NewInternalClient"; AddPortMappingArgs[4].val = inClient; AddPortMappingArgs[5].elt = "NewEnabled"; AddPortMappingArgs[5].val = "1"; AddPortMappingArgs[6].elt = "NewPortMappingDescription"; AddPortMappingArgs[6].val = desc?desc:"libminiupnpc"; AddPortMappingArgs[7].elt = "NewLeaseDuration"; AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0"; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "AddPortMapping", AddPortMappingArgs, &bufsize))) { free(AddPortMappingArgs); return UPNPCOMMAND_HTTP_ERROR; } /*DisplayNameValueList(buffer, bufsize);*/ /*buffer[bufsize] = '\0';*/ /*puts(buffer);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { /*printf("AddPortMapping errorCode = '%s'\n", resVal); */ ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); free(AddPortMappingArgs); return ret; } MINIUPNP_LIBSPEC int UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype, const char * extPort, const char * inPort, const char * inClient, const char * desc, const char * proto, const char * remoteHost, const char * leaseDuration, char * reservedPort) { struct UPNParg * AddPortMappingArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; int ret; if(!inPort || !inClient || !proto || !extPort) return UPNPCOMMAND_INVALID_ARGS; AddPortMappingArgs = calloc(9, sizeof(struct UPNParg)); AddPortMappingArgs[0].elt = "NewRemoteHost"; AddPortMappingArgs[0].val = remoteHost; AddPortMappingArgs[1].elt = "NewExternalPort"; AddPortMappingArgs[1].val = extPort; AddPortMappingArgs[2].elt = "NewProtocol"; AddPortMappingArgs[2].val = proto; AddPortMappingArgs[3].elt = "NewInternalPort"; AddPortMappingArgs[3].val = inPort; AddPortMappingArgs[4].elt = "NewInternalClient"; AddPortMappingArgs[4].val = inClient; AddPortMappingArgs[5].elt = "NewEnabled"; AddPortMappingArgs[5].val = "1"; AddPortMappingArgs[6].elt = "NewPortMappingDescription"; AddPortMappingArgs[6].val = desc?desc:"libminiupnpc"; AddPortMappingArgs[7].elt = "NewLeaseDuration"; AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0"; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "AddAnyPortMapping", AddPortMappingArgs, &bufsize))) { free(AddPortMappingArgs); return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { char *p; p = GetValueFromNameValueList(&pdata, "NewReservedPort"); if(p) { strncpy(reservedPort, p, 6); reservedPort[5] = '\0'; ret = UPNPCOMMAND_SUCCESS; } else { ret = UPNPCOMMAND_INVALID_RESPONSE; } } ClearNameValueList(&pdata); free(AddPortMappingArgs); return ret; } MINIUPNP_LIBSPEC int UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, const char * extPort, const char * proto, const char * remoteHost) { /*struct NameValueParserData pdata;*/ struct UPNParg * DeletePortMappingArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; int ret; if(!extPort || !proto) return UPNPCOMMAND_INVALID_ARGS; DeletePortMappingArgs = calloc(4, sizeof(struct UPNParg)); DeletePortMappingArgs[0].elt = "NewRemoteHost"; DeletePortMappingArgs[0].val = remoteHost; DeletePortMappingArgs[1].elt = "NewExternalPort"; DeletePortMappingArgs[1].val = extPort; DeletePortMappingArgs[2].elt = "NewProtocol"; DeletePortMappingArgs[2].val = proto; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "DeletePortMapping", DeletePortMappingArgs, &bufsize))) { free(DeletePortMappingArgs); return UPNPCOMMAND_HTTP_ERROR; } /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); free(DeletePortMappingArgs); return ret; } MINIUPNP_LIBSPEC int UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, const char * extPortStart, const char * extPortEnd, const char * proto, const char * manage) { struct UPNParg * DeletePortMappingArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; int ret; if(!extPortStart || !extPortEnd || !proto || !manage) return UPNPCOMMAND_INVALID_ARGS; DeletePortMappingArgs = calloc(5, sizeof(struct UPNParg)); DeletePortMappingArgs[0].elt = "NewStartPort"; DeletePortMappingArgs[0].val = extPortStart; DeletePortMappingArgs[1].elt = "NewEndPort"; DeletePortMappingArgs[1].val = extPortEnd; DeletePortMappingArgs[2].elt = "NewProtocol"; DeletePortMappingArgs[2].val = proto; DeletePortMappingArgs[3].elt = "NewManage"; DeletePortMappingArgs[3].val = manage; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "DeletePortMappingRange", DeletePortMappingArgs, &bufsize))) { free(DeletePortMappingArgs); return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); free(DeletePortMappingArgs); return ret; } MINIUPNP_LIBSPEC int UPNP_GetGenericPortMappingEntry(const char * controlURL, const char * servicetype, const char * index, char * extPort, char * intClient, char * intPort, char * protocol, char * desc, char * enabled, char * rHost, char * duration) { struct NameValueParserData pdata; struct UPNParg * GetPortMappingArgs; char * buffer; int bufsize; char * p; int r = UPNPCOMMAND_UNKNOWN_ERROR; if(!index) return UPNPCOMMAND_INVALID_ARGS; intClient[0] = '\0'; intPort[0] = '\0'; GetPortMappingArgs = calloc(2, sizeof(struct UPNParg)); GetPortMappingArgs[0].elt = "NewPortMappingIndex"; GetPortMappingArgs[0].val = index; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetGenericPortMappingEntry", GetPortMappingArgs, &bufsize))) { free(GetPortMappingArgs); return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "NewRemoteHost"); if(p && rHost) { strncpy(rHost, p, 64); rHost[63] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewExternalPort"); if(p && extPort) { strncpy(extPort, p, 6); extPort[5] = '\0'; r = UPNPCOMMAND_SUCCESS; } p = GetValueFromNameValueList(&pdata, "NewProtocol"); if(p && protocol) { strncpy(protocol, p, 4); protocol[3] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewInternalClient"); if(p && intClient) { strncpy(intClient, p, 16); intClient[15] = '\0'; r = 0; } p = GetValueFromNameValueList(&pdata, "NewInternalPort"); if(p && intPort) { strncpy(intPort, p, 6); intPort[5] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewEnabled"); if(p && enabled) { strncpy(enabled, p, 4); enabled[3] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription"); if(p && desc) { strncpy(desc, p, 80); desc[79] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewLeaseDuration"); if(p && duration) { strncpy(duration, p, 16); duration[15] = '\0'; } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { r = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &r); } ClearNameValueList(&pdata); free(GetPortMappingArgs); return r; } MINIUPNP_LIBSPEC int UPNP_GetPortMappingNumberOfEntries(const char * controlURL, const char * servicetype, unsigned int * numEntries) { struct NameValueParserData pdata; char * buffer; int bufsize; char* p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetPortMappingNumberOfEntries", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } #ifdef DEBUG DisplayNameValueList(buffer, bufsize); #endif ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "NewPortMappingNumberOfEntries"); if(numEntries && p) { *numEntries = 0; sscanf(p, "%u", numEntries); ret = UPNPCOMMAND_SUCCESS; } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } /* UPNP_GetSpecificPortMappingEntry retrieves an existing port mapping * the result is returned in the intClient and intPort strings * please provide 16 and 6 bytes of data */ MINIUPNP_LIBSPEC int UPNP_GetSpecificPortMappingEntry(const char * controlURL, const char * servicetype, const char * extPort, const char * proto, const char * remoteHost, char * intClient, char * intPort, char * desc, char * enabled, char * leaseDuration) { struct NameValueParserData pdata; struct UPNParg * GetPortMappingArgs; char * buffer; int bufsize; char * p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!intPort || !intClient || !extPort || !proto) return UPNPCOMMAND_INVALID_ARGS; GetPortMappingArgs = calloc(4, sizeof(struct UPNParg)); GetPortMappingArgs[0].elt = "NewRemoteHost"; GetPortMappingArgs[0].val = remoteHost; GetPortMappingArgs[1].elt = "NewExternalPort"; GetPortMappingArgs[1].val = extPort; GetPortMappingArgs[2].elt = "NewProtocol"; GetPortMappingArgs[2].val = proto; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetSpecificPortMappingEntry", GetPortMappingArgs, &bufsize))) { free(GetPortMappingArgs); return UPNPCOMMAND_HTTP_ERROR; } /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "NewInternalClient"); if(p) { strncpy(intClient, p, 16); intClient[15] = '\0'; ret = UPNPCOMMAND_SUCCESS; } else intClient[0] = '\0'; p = GetValueFromNameValueList(&pdata, "NewInternalPort"); if(p) { strncpy(intPort, p, 6); intPort[5] = '\0'; } else intPort[0] = '\0'; p = GetValueFromNameValueList(&pdata, "NewEnabled"); if(p && enabled) { strncpy(enabled, p, 4); enabled[3] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription"); if(p && desc) { strncpy(desc, p, 80); desc[79] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewLeaseDuration"); if(p && leaseDuration) { strncpy(leaseDuration, p, 16); leaseDuration[15] = '\0'; } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); free(GetPortMappingArgs); return ret; } /* UPNP_GetListOfPortMappings() * * Possible UPNP Error codes : * 606 Action not Authorized * 730 PortMappingNotFound - no port mapping is found in the specified range. * 733 InconsistantParameters - NewStartPort and NewEndPort values are not * consistent. */ MINIUPNP_LIBSPEC int UPNP_GetListOfPortMappings(const char * controlURL, const char * servicetype, const char * startPort, const char * endPort, const char * protocol, const char * numberOfPorts, struct PortMappingParserData * data) { struct NameValueParserData pdata; struct UPNParg * GetListOfPortMappingsArgs; const char * p; char * buffer; int bufsize; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!startPort || !endPort || !protocol) return UPNPCOMMAND_INVALID_ARGS; GetListOfPortMappingsArgs = calloc(6, sizeof(struct UPNParg)); GetListOfPortMappingsArgs[0].elt = "NewStartPort"; GetListOfPortMappingsArgs[0].val = startPort; GetListOfPortMappingsArgs[1].elt = "NewEndPort"; GetListOfPortMappingsArgs[1].val = endPort; GetListOfPortMappingsArgs[2].elt = "NewProtocol"; GetListOfPortMappingsArgs[2].val = protocol; GetListOfPortMappingsArgs[3].elt = "NewManage"; GetListOfPortMappingsArgs[3].val = "1"; GetListOfPortMappingsArgs[4].elt = "NewNumberOfPorts"; GetListOfPortMappingsArgs[4].val = numberOfPorts?numberOfPorts:"1000"; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetListOfPortMappings", GetListOfPortMappingsArgs, &bufsize))) { free(GetListOfPortMappingsArgs); return UPNPCOMMAND_HTTP_ERROR; } free(GetListOfPortMappingsArgs); /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; /*p = GetValueFromNameValueList(&pdata, "NewPortListing");*/ /*if(p) { printf("NewPortListing : %s\n", p); }*/ /*printf("NewPortListing(%d chars) : %s\n", pdata.portListingLength, pdata.portListing);*/ if(pdata.portListing) { /*struct PortMapping * pm; int i = 0;*/ ParsePortListing(pdata.portListing, pdata.portListingLength, data); ret = UPNPCOMMAND_SUCCESS; /* for(pm = data->head.lh_first; pm != NULL; pm = pm->entries.le_next) { printf("%2d %s %5hu->%s:%-5hu '%s' '%s'\n", i, pm->protocol, pm->externalPort, pm->internalClient, pm->internalPort, pm->description, pm->remoteHost); i++; } */ /*FreePortListing(&data);*/ } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); /*printf("%.*s", bufsize, buffer);*/ return ret; } /* IGD:2, functions for service WANIPv6FirewallControl:1 */ MINIUPNP_LIBSPEC int UPNP_GetFirewallStatus(const char * controlURL, const char * servicetype, int * firewallEnabled, int * inboundPinholeAllowed) { struct NameValueParserData pdata; char * buffer; int bufsize; char * fe, *ipa, *p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!firewallEnabled || !inboundPinholeAllowed) return UPNPCOMMAND_INVALID_ARGS; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetFirewallStatus", 0, &bufsize); if(!buffer) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; fe = GetValueFromNameValueList(&pdata, "FirewallEnabled"); ipa = GetValueFromNameValueList(&pdata, "InboundPinholeAllowed"); if(ipa && fe) ret = UPNPCOMMAND_SUCCESS; if(fe) *firewallEnabled = my_atoui(fe); /*else *firewallEnabled = 0;*/ if(ipa) *inboundPinholeAllowed = my_atoui(ipa); /*else *inboundPinholeAllowed = 0;*/ p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } MINIUPNP_LIBSPEC int UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, const char * remoteHost, const char * remotePort, const char * intClient, const char * intPort, const char * proto, int * opTimeout) { struct UPNParg * GetOutboundPinholeTimeoutArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; char * p; int ret; if(!intPort || !intClient || !proto || !remotePort || !remoteHost) return UPNPCOMMAND_INVALID_ARGS; GetOutboundPinholeTimeoutArgs = calloc(6, sizeof(struct UPNParg)); GetOutboundPinholeTimeoutArgs[0].elt = "RemoteHost"; GetOutboundPinholeTimeoutArgs[0].val = remoteHost; GetOutboundPinholeTimeoutArgs[1].elt = "RemotePort"; GetOutboundPinholeTimeoutArgs[1].val = remotePort; GetOutboundPinholeTimeoutArgs[2].elt = "Protocol"; GetOutboundPinholeTimeoutArgs[2].val = proto; GetOutboundPinholeTimeoutArgs[3].elt = "InternalPort"; GetOutboundPinholeTimeoutArgs[3].val = intPort; GetOutboundPinholeTimeoutArgs[4].elt = "InternalClient"; GetOutboundPinholeTimeoutArgs[4].val = intClient; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetOutboundPinholeTimeout", GetOutboundPinholeTimeoutArgs, &bufsize); if(!buffer) return UPNPCOMMAND_HTTP_ERROR; ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { ret = UPNPCOMMAND_SUCCESS; p = GetValueFromNameValueList(&pdata, "OutboundPinholeTimeout"); if(p) *opTimeout = my_atoui(p); } ClearNameValueList(&pdata); free(GetOutboundPinholeTimeoutArgs); return ret; } MINIUPNP_LIBSPEC int UPNP_AddPinhole(const char * controlURL, const char * servicetype, const char * remoteHost, const char * remotePort, const char * intClient, const char * intPort, const char * proto, const char * leaseTime, char * uniqueID) { struct UPNParg * AddPinholeArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; char * p; int ret; if(!intPort || !intClient || !proto || !remoteHost || !remotePort || !leaseTime) return UPNPCOMMAND_INVALID_ARGS; AddPinholeArgs = calloc(7, sizeof(struct UPNParg)); /* RemoteHost can be wilcarded */ if(strncmp(remoteHost, "empty", 5)==0) { AddPinholeArgs[0].elt = "RemoteHost"; AddPinholeArgs[0].val = ""; } else { AddPinholeArgs[0].elt = "RemoteHost"; AddPinholeArgs[0].val = remoteHost; } AddPinholeArgs[1].elt = "RemotePort"; AddPinholeArgs[1].val = remotePort; AddPinholeArgs[2].elt = "Protocol"; AddPinholeArgs[2].val = proto; AddPinholeArgs[3].elt = "InternalPort"; AddPinholeArgs[3].val = intPort; if(strncmp(intClient, "empty", 5)==0) { AddPinholeArgs[4].elt = "InternalClient"; AddPinholeArgs[4].val = ""; } else { AddPinholeArgs[4].elt = "InternalClient"; AddPinholeArgs[4].val = intClient; } AddPinholeArgs[5].elt = "LeaseTime"; AddPinholeArgs[5].val = leaseTime; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "AddPinhole", AddPinholeArgs, &bufsize); if(!buffer) return UPNPCOMMAND_HTTP_ERROR; ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "UniqueID"); if(p) { strncpy(uniqueID, p, 8); uniqueID[7] = '\0'; } resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { /*printf("AddPortMapping errorCode = '%s'\n", resVal);*/ ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); free(AddPinholeArgs); return ret; } MINIUPNP_LIBSPEC int UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, const char * uniqueID, const char * leaseTime) { struct UPNParg * UpdatePinholeArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; int ret; if(!uniqueID || !leaseTime) return UPNPCOMMAND_INVALID_ARGS; UpdatePinholeArgs = calloc(3, sizeof(struct UPNParg)); UpdatePinholeArgs[0].elt = "UniqueID"; UpdatePinholeArgs[0].val = uniqueID; UpdatePinholeArgs[1].elt = "NewLeaseTime"; UpdatePinholeArgs[1].val = leaseTime; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "UpdatePinhole", UpdatePinholeArgs, &bufsize); if(!buffer) return UPNPCOMMAND_HTTP_ERROR; ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { /*printf("AddPortMapping errorCode = '%s'\n", resVal); */ ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); free(UpdatePinholeArgs); return ret; } MINIUPNP_LIBSPEC int UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID) { /*struct NameValueParserData pdata;*/ struct UPNParg * DeletePinholeArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; int ret; if(!uniqueID) return UPNPCOMMAND_INVALID_ARGS; DeletePinholeArgs = calloc(2, sizeof(struct UPNParg)); DeletePinholeArgs[0].elt = "UniqueID"; DeletePinholeArgs[0].val = uniqueID; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "DeletePinhole", DeletePinholeArgs, &bufsize); if(!buffer) return UPNPCOMMAND_HTTP_ERROR; /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); free(DeletePinholeArgs); return ret; } MINIUPNP_LIBSPEC int UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, const char * uniqueID, int * isWorking) { struct NameValueParserData pdata; struct UPNParg * CheckPinholeWorkingArgs; char * buffer; int bufsize; char * p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!uniqueID) return UPNPCOMMAND_INVALID_ARGS; CheckPinholeWorkingArgs = calloc(4, sizeof(struct UPNParg)); CheckPinholeWorkingArgs[0].elt = "UniqueID"; CheckPinholeWorkingArgs[0].val = uniqueID; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "CheckPinholeWorking", CheckPinholeWorkingArgs, &bufsize); if(!buffer) return UPNPCOMMAND_HTTP_ERROR; ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "IsWorking"); if(p) { *isWorking=my_atoui(p); ret = UPNPCOMMAND_SUCCESS; } else *isWorking = 0; p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); free(CheckPinholeWorkingArgs); return ret; } MINIUPNP_LIBSPEC int UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, const char * uniqueID, int * packets) { struct NameValueParserData pdata; struct UPNParg * GetPinholePacketsArgs; char * buffer; int bufsize; char * p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!uniqueID) return UPNPCOMMAND_INVALID_ARGS; GetPinholePacketsArgs = calloc(4, sizeof(struct UPNParg)); GetPinholePacketsArgs[0].elt = "UniqueID"; GetPinholePacketsArgs[0].val = uniqueID; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetPinholePackets", GetPinholePacketsArgs, &bufsize); if(!buffer) return UPNPCOMMAND_HTTP_ERROR; ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "PinholePackets"); if(p) { *packets=my_atoui(p); ret = UPNPCOMMAND_SUCCESS; } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); free(GetPinholePacketsArgs); return ret; } miniupnpc-1.9.20140610/upnpreplyparse.c010064400017500000024000000101721215431657000167050ustar00nanardstaff/* $Id: upnpreplyparse.c,v 1.15 2013/06/06 21:36:40 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2013 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #include #include #include #include "upnpreplyparse.h" #include "minixml.h" static void NameValueParserStartElt(void * d, const char * name, int l) { struct NameValueParserData * data = (struct NameValueParserData *)d; data->topelt = 1; if(l>63) l = 63; memcpy(data->curelt, name, l); data->curelt[l] = '\0'; data->cdata = NULL; data->cdatalen = 0; } static void NameValueParserEndElt(void * d, const char * name, int l) { struct NameValueParserData * data = (struct NameValueParserData *)d; struct NameValue * nv; (void)name; (void)l; if(!data->topelt) return; if(strcmp(data->curelt, "NewPortListing") != 0) { int l; /* standard case. Limited to n chars strings */ l = data->cdatalen; nv = malloc(sizeof(struct NameValue)); if(l>=(int)sizeof(nv->value)) l = sizeof(nv->value) - 1; strncpy(nv->name, data->curelt, 64); nv->name[63] = '\0'; if(data->cdata != NULL) { memcpy(nv->value, data->cdata, l); nv->value[l] = '\0'; } else { nv->value[0] = '\0'; } LIST_INSERT_HEAD( &(data->head), nv, entries); } data->cdata = NULL; data->cdatalen = 0; data->topelt = 0; } static void NameValueParserGetData(void * d, const char * datas, int l) { struct NameValueParserData * data = (struct NameValueParserData *)d; if(strcmp(data->curelt, "NewPortListing") == 0) { /* specific case for NewPortListing which is a XML Document */ data->portListing = malloc(l + 1); if(!data->portListing) { /* malloc error */ return; } memcpy(data->portListing, datas, l); data->portListing[l] = '\0'; data->portListingLength = l; } else { /* standard case. */ data->cdata = datas; data->cdatalen = l; } } void ParseNameValue(const char * buffer, int bufsize, struct NameValueParserData * data) { struct xmlparser parser; LIST_INIT(&(data->head)); data->portListing = NULL; data->portListingLength = 0; /* init xmlparser object */ parser.xmlstart = buffer; parser.xmlsize = bufsize; parser.data = data; parser.starteltfunc = NameValueParserStartElt; parser.endeltfunc = NameValueParserEndElt; parser.datafunc = NameValueParserGetData; parser.attfunc = 0; parsexml(&parser); } void ClearNameValueList(struct NameValueParserData * pdata) { struct NameValue * nv; if(pdata->portListing) { free(pdata->portListing); pdata->portListing = NULL; pdata->portListingLength = 0; } while((nv = pdata->head.lh_first) != NULL) { LIST_REMOVE(nv, entries); free(nv); } } char * GetValueFromNameValueList(struct NameValueParserData * pdata, const char * Name) { struct NameValue * nv; char * p = NULL; for(nv = pdata->head.lh_first; (nv != NULL) && (p == NULL); nv = nv->entries.le_next) { if(strcmp(nv->name, Name) == 0) p = nv->value; } return p; } #if 0 /* useless now that minixml ignores namespaces by itself */ char * GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, const char * Name) { struct NameValue * nv; char * p = NULL; char * pname; for(nv = pdata->head.lh_first; (nv != NULL) && (p == NULL); nv = nv->entries.le_next) { pname = strrchr(nv->name, ':'); if(pname) pname++; else pname = nv->name; if(strcmp(pname, Name)==0) p = nv->value; } return p; } #endif /* debug all-in-one function * do parsing then display to stdout */ #ifdef DEBUG void DisplayNameValueList(char * buffer, int bufsize) { struct NameValueParserData pdata; struct NameValue * nv; ParseNameValue(buffer, bufsize, &pdata); for(nv = pdata.head.lh_first; nv != NULL; nv = nv->entries.le_next) { printf("%s = %s\n", nv->name, nv->value); } ClearNameValueList(&pdata); } #endif miniupnpc-1.9.20140610/upnpreplyparse.h010064400017500000024000000027561215431657000167230ustar00nanardstaff/* $Id: upnpreplyparse.h,v 1.17 2013/06/06 21:36:40 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2013 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #ifndef UPNPREPLYPARSE_H_INCLUDED #define UPNPREPLYPARSE_H_INCLUDED #if defined(NO_SYS_QUEUE_H) || defined(_WIN32) || defined(__HAIKU__) #include "bsdqueue.h" #else #include #endif #ifdef __cplusplus extern "C" { #endif struct NameValue { LIST_ENTRY(NameValue) entries; char name[64]; char value[128]; }; struct NameValueParserData { LIST_HEAD(listhead, NameValue) head; char curelt[64]; char * portListing; int portListingLength; int topelt; const char * cdata; int cdatalen; }; /* ParseNameValue() */ void ParseNameValue(const char * buffer, int bufsize, struct NameValueParserData * data); /* ClearNameValueList() */ void ClearNameValueList(struct NameValueParserData * pdata); /* GetValueFromNameValueList() */ char * GetValueFromNameValueList(struct NameValueParserData * pdata, const char * Name); #if 0 /* GetValueFromNameValueListIgnoreNS() */ char * GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, const char * Name); #endif /* DisplayNameValueList() */ #ifdef DEBUG void DisplayNameValueList(char * buffer, int bufsize); #endif #ifdef __cplusplus } #endif #endif miniupnpc-1.9.20140610/upnpcommands.h010064400017500000024000000323551234555371500163420ustar00nanardstaff/* $Id: upnpcommands.h,v 1.29 2014/06/10 09:44:08 nanard Exp $ */ /* Miniupnp project : http://miniupnp.free.fr/ * Author : Thomas Bernard * Copyright (c) 2005-2014 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided within this distribution */ #ifndef UPNPCOMMANDS_H_INCLUDED #define UPNPCOMMANDS_H_INCLUDED #include "upnpreplyparse.h" #include "portlistingparse.h" #include "declspec.h" #include "miniupnpctypes.h" /* MiniUPnPc return codes : */ #define UPNPCOMMAND_SUCCESS (0) #define UPNPCOMMAND_UNKNOWN_ERROR (-1) #define UPNPCOMMAND_INVALID_ARGS (-2) #define UPNPCOMMAND_HTTP_ERROR (-3) #define UPNPCOMMAND_INVALID_RESPONSE (-4) #ifdef __cplusplus extern "C" { #endif MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalBytesSent(const char * controlURL, const char * servicetype); MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalBytesReceived(const char * controlURL, const char * servicetype); MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalPacketsSent(const char * controlURL, const char * servicetype); MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalPacketsReceived(const char * controlURL, const char * servicetype); /* UPNP_GetStatusInfo() * status and lastconnerror are 64 byte buffers * Return values : * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * or a UPnP Error code */ MINIUPNP_LIBSPEC int UPNP_GetStatusInfo(const char * controlURL, const char * servicetype, char * status, unsigned int * uptime, char * lastconnerror); /* UPNP_GetConnectionTypeInfo() * argument connectionType is a 64 character buffer * Return Values : * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * or a UPnP Error code */ MINIUPNP_LIBSPEC int UPNP_GetConnectionTypeInfo(const char * controlURL, const char * servicetype, char * connectionType); /* UPNP_GetExternalIPAddress() call the corresponding UPNP method. * if the third arg is not null the value is copied to it. * at least 16 bytes must be available * * Return values : * 0 : SUCCESS * NON ZERO : ERROR Either an UPnP error code or an unknown error. * * possible UPnP Errors : * 402 Invalid Args - See UPnP Device Architecture section on Control. * 501 Action Failed - See UPnP Device Architecture section on Control. */ MINIUPNP_LIBSPEC int UPNP_GetExternalIPAddress(const char * controlURL, const char * servicetype, char * extIpAdd); /* UPNP_GetLinkLayerMaxBitRates() * call WANCommonInterfaceConfig:1#GetCommonLinkProperties * * return values : * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * or a UPnP Error Code. */ MINIUPNP_LIBSPEC int UPNP_GetLinkLayerMaxBitRates(const char* controlURL, const char* servicetype, unsigned int * bitrateDown, unsigned int * bitrateUp); /* UPNP_AddPortMapping() * if desc is NULL, it will be defaulted to "libminiupnpc" * remoteHost is usually NULL because IGD don't support it. * * Return values : * 0 : SUCCESS * NON ZERO : ERROR. Either an UPnP error code or an unknown error. * * List of possible UPnP errors for AddPortMapping : * errorCode errorDescription (short) - Description (long) * 402 Invalid Args - See UPnP Device Architecture section on Control. * 501 Action Failed - See UPnP Device Architecture section on Control. * 606 Action not authorized - The action requested REQUIRES authorization and * the sender was not authorized. * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be * wild-carded * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded * 718 ConflictInMappingEntry - The port mapping entry specified conflicts * with a mapping assigned previously to another client * 724 SamePortValuesRequired - Internal and External port values * must be the same * 725 OnlyPermanentLeasesSupported - The NAT implementation only supports * permanent lease times on port mappings * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard * and cannot be a specific IP address or DNS name * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and * cannot be a specific port value * 728 NoPortMapsAvailable - There are not enough free ports available to * complete port mapping. * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed * due to conflict with other mechanisms. * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded */ MINIUPNP_LIBSPEC int UPNP_AddPortMapping(const char * controlURL, const char * servicetype, const char * extPort, const char * inPort, const char * inClient, const char * desc, const char * proto, const char * remoteHost, const char * leaseDuration); /* UPNP_AddAnyPortMapping() * if desc is NULL, it will be defaulted to "libminiupnpc" * remoteHost is usually NULL because IGD don't support it. * * Return values : * 0 : SUCCESS * NON ZERO : ERROR. Either an UPnP error code or an unknown error. * * List of possible UPnP errors for AddPortMapping : * errorCode errorDescription (short) - Description (long) * 402 Invalid Args - See UPnP Device Architecture section on Control. * 501 Action Failed - See UPnP Device Architecture section on Control. * 606 Action not authorized - The action requested REQUIRES authorization and * the sender was not authorized. * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be * wild-carded * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded * 728 NoPortMapsAvailable - There are not enough free ports available to * complete port mapping. * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed * due to conflict with other mechanisms. * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded */ MINIUPNP_LIBSPEC int UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype, const char * extPort, const char * inPort, const char * inClient, const char * desc, const char * proto, const char * remoteHost, const char * leaseDuration, char * reservedPort); /* UPNP_DeletePortMapping() * Use same argument values as what was used for AddPortMapping(). * remoteHost is usually NULL because IGD don't support it. * Return Values : * 0 : SUCCESS * NON ZERO : error. Either an UPnP error code or an undefined error. * * List of possible UPnP errors for DeletePortMapping : * 402 Invalid Args - See UPnP Device Architecture section on Control. * 606 Action not authorized - The action requested REQUIRES authorization * and the sender was not authorized. * 714 NoSuchEntryInArray - The specified value does not exist in the array */ MINIUPNP_LIBSPEC int UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, const char * extPort, const char * proto, const char * remoteHost); /* UPNP_DeletePortRangeMapping() * Use same argument values as what was used for AddPortMapping(). * remoteHost is usually NULL because IGD don't support it. * Return Values : * 0 : SUCCESS * NON ZERO : error. Either an UPnP error code or an undefined error. * * List of possible UPnP errors for DeletePortMapping : * 606 Action not authorized - The action requested REQUIRES authorization * and the sender was not authorized. * 730 PortMappingNotFound - This error message is returned if no port * mapping is found in the specified range. * 733 InconsistentParameters - NewStartPort and NewEndPort values are not consistent. */ MINIUPNP_LIBSPEC int UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, const char * extPortStart, const char * extPortEnd, const char * proto, const char * manage); /* UPNP_GetPortMappingNumberOfEntries() * not supported by all routers */ MINIUPNP_LIBSPEC int UPNP_GetPortMappingNumberOfEntries(const char* controlURL, const char* servicetype, unsigned int * num); /* UPNP_GetSpecificPortMappingEntry() * retrieves an existing port mapping * params : * in extPort * in proto * in remoteHost * out intClient (16 bytes) * out intPort (6 bytes) * out desc (80 bytes) * out enabled (4 bytes) * out leaseDuration (16 bytes) * * return value : * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * or a UPnP Error Code. * * List of possible UPnP errors for _GetSpecificPortMappingEntry : * 402 Invalid Args - See UPnP Device Architecture section on Control. * 501 Action Failed - See UPnP Device Architecture section on Control. * 606 Action not authorized - The action requested REQUIRES authorization * and the sender was not authorized. * 714 NoSuchEntryInArray - The specified value does not exist in the array. */ MINIUPNP_LIBSPEC int UPNP_GetSpecificPortMappingEntry(const char * controlURL, const char * servicetype, const char * extPort, const char * proto, const char * remoteHost, char * intClient, char * intPort, char * desc, char * enabled, char * leaseDuration); /* UPNP_GetGenericPortMappingEntry() * params : * in index * out extPort (6 bytes) * out intClient (16 bytes) * out intPort (6 bytes) * out protocol (4 bytes) * out desc (80 bytes) * out enabled (4 bytes) * out rHost (64 bytes) * out duration (16 bytes) * * return value : * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * or a UPnP Error Code. * * Possible UPNP Error codes : * 402 Invalid Args - See UPnP Device Architecture section on Control. * 606 Action not authorized - The action requested REQUIRES authorization * and the sender was not authorized. * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds */ MINIUPNP_LIBSPEC int UPNP_GetGenericPortMappingEntry(const char * controlURL, const char * servicetype, const char * index, char * extPort, char * intClient, char * intPort, char * protocol, char * desc, char * enabled, char * rHost, char * duration); /* UPNP_GetListOfPortMappings() Available in IGD v2 * * * Possible UPNP Error codes : * 606 Action not Authorized * 730 PortMappingNotFound - no port mapping is found in the specified range. * 733 InconsistantParameters - NewStartPort and NewEndPort values are not * consistent. */ MINIUPNP_LIBSPEC int UPNP_GetListOfPortMappings(const char * controlURL, const char * servicetype, const char * startPort, const char * endPort, const char * protocol, const char * numberOfPorts, struct PortMappingParserData * data); /* IGD:2, functions for service WANIPv6FirewallControl:1 */ MINIUPNP_LIBSPEC int UPNP_GetFirewallStatus(const char * controlURL, const char * servicetype, int * firewallEnabled, int * inboundPinholeAllowed); MINIUPNP_LIBSPEC int UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, const char * remoteHost, const char * remotePort, const char * intClient, const char * intPort, const char * proto, int * opTimeout); MINIUPNP_LIBSPEC int UPNP_AddPinhole(const char * controlURL, const char * servicetype, const char * remoteHost, const char * remotePort, const char * intClient, const char * intPort, const char * proto, const char * leaseTime, char * uniqueID); MINIUPNP_LIBSPEC int UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, const char * uniqueID, const char * leaseTime); MINIUPNP_LIBSPEC int UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID); MINIUPNP_LIBSPEC int UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, const char * uniqueID, int * isWorking); MINIUPNP_LIBSPEC int UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, const char * uniqueID, int * packets); #ifdef __cplusplus } #endif #endif miniupnpc-1.9.20140610/Makefile.mingw010064400017500000024000000047271234555371300162450ustar00nanardstaff# $Id: Makefile.mingw,v 1.19 2014/06/10 09:48:11 nanard Exp $ # Miniupnp project. # http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ # (c) 2005-2014 Thomas Bernard # This Makefile is made for MinGW # CC = gcc #CFLAGS = -Wall -g -DDEBUG -D_WIN32_WINNT=0X501 CFLAGS = -Wall -Os -DNDEBUG -D_WIN32_WINNT=0X501 LDLIBS = -lws2_32 -liphlpapi # -lwsock32 # -liphlpapi is needed for GetBestRoute() and GetIpAddrTable() PYTHON=\utils\python25\python OBJS=miniwget.o minixml.o igd_desc_parse.o minisoap.o \ miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \ connecthostport.o portlistingparse.o receivedata.o OBJSDLL=$(addprefix dll/, $(OBJS)) all: init upnpc-static upnpc-shared testminixml libminiupnpc.a miniupnpc.dll init: mkdir dll echo init > init clean: del upnpc testminixml *.o del dll\*.o del *.exe del miniupnpc.dll del libminiupnpc.a libminiupnpc.a: $(OBJS) $(AR) cr $@ $? pythonmodule: libminiupnpc.a $(PYTHON) setupmingw32.py build --compiler=mingw32 $(PYTHON) setupmingw32.py install --skip-build miniupnpc.dll: libminiupnpc.a $(OBJSDLL) dllwrap -k --driver-name gcc \ --def miniupnpc.def \ --output-def miniupnpc.dll.def \ --implib miniupnpc.lib -o $@ \ $(OBJSDLL) $(LDLIBS) miniupnpc.lib: miniupnpc.dll echo $@ generated with $< dll/upnpc.o: upnpc.o echo $@ generated with $< .c.o: $(CC) $(CFLAGS) -DMINIUPNP_STATICLIB -c -o $@ $< $(CC) $(CFLAGS) -DMINIUPNP_EXPORTS -c -o dll/$@ $< upnpc.o: $(CC) $(CFLAGS) -DMINIUPNP_STATICLIB -c -o $@ $< $(CC) $(CFLAGS) -c -o dll/$@ $< # --enable-stdcall-fixup upnpc-static: upnpc.o libminiupnpc.a $(CC) -o $@ $^ $(LDLIBS) upnpc-shared: dll/upnpc.o miniupnpc.lib $(CC) -o $@ $^ $(LDLIBS) wingenminiupnpcstrings: wingenminiupnpcstrings.o wingenminiupnpcstrings.o: wingenminiupnpcstrings.c miniupnpcstrings.h: miniupnpcstrings.h.in wingenminiupnpcstrings wingenminiupnpcstrings $< $@ minixml.o: minixml.c minixml.h miniupnpcstrings.h upnpc.o: upnpc.c miniwget.h minisoap.h miniupnpc.h igd_desc_parse.h upnpreplyparse.h upnpcommands.h upnperrors.h miniwget.o: miniwget.c miniwget.h miniupnpcstrings.h connecthostport.h minisoap.o: minisoap.c minisoap.h miniupnpcstrings.h miniupnpc.o: miniupnpc.c miniupnpc.h minisoap.h miniwget.h minixml.h igd_desc_parse.o: igd_desc_parse.c igd_desc_parse.h testminixml: minixml.o igd_desc_parse.o testminixml.c upnpreplyparse.o: upnpreplyparse.c upnpreplyparse.h minixml.h upnpcommands.o: upnpcommands.c upnpcommands.h upnpreplyparse.h miniupnpc.h portlistingparse.h miniupnpc-1.9.20140610/bsdqueue.h010064400017500000024000000432671172522177000154510ustar00nanardstaff/* $OpenBSD: queue.h,v 1.31 2005/11/25 08:06:25 otto Exp $ */ /* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ /* * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)queue.h 8.5 (Berkeley) 8/20/94 */ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ /* * This file defines five types of data structures: singly-linked lists, * lists, simple queues, tail queues, and circular queues. * * * A singly-linked list is headed by a single forward pointer. The elements * are singly linked for minimum space and pointer manipulation overhead at * the expense of O(n) removal for arbitrary elements. New elements can be * added to the list after an existing element or at the head of the list. * Elements being removed from the head of the list should use the explicit * macro for this purpose for optimum efficiency. A singly-linked list may * only be traversed in the forward direction. Singly-linked lists are ideal * for applications with large datasets and few or no removals or for * implementing a LIFO queue. * * A list is headed by a single forward pointer (or an array of forward * pointers for a hash table header). The elements are doubly linked * so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before * or after an existing element or at the head of the list. A list * may only be traversed in the forward direction. * * A simple queue is headed by a pair of pointers, one the head of the * list and the other to the tail of the list. The elements are singly * linked to save space, so elements can only be removed from the * head of the list. New elements can be added to the list before or after * an existing element, at the head of the list, or at the end of the * list. A simple queue may only be traversed in the forward direction. * * A tail queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or * after an existing element, at the head of the list, or at the end of * the list. A tail queue may be traversed in either direction. * * A circle queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or after * an existing element, at the head of the list, or at the end of the list. * A circle queue may be traversed in either direction, but has a more * complex end of list detection. * * For details on the use of these macros, see the queue(3) manual page. */ #ifdef QUEUE_MACRO_DEBUG #define _Q_INVALIDATE(a) (a) = ((void *)-1) #else #define _Q_INVALIDATE(a) #endif /* * Singly-linked List definitions. */ #define SLIST_HEAD(name, type) \ struct name { \ struct type *slh_first; /* first element */ \ } #define SLIST_HEAD_INITIALIZER(head) \ { NULL } #ifdef SLIST_ENTRY #undef SLIST_ENTRY #endif #define SLIST_ENTRY(type) \ struct { \ struct type *sle_next; /* next element */ \ } /* * Singly-linked List access methods. */ #define SLIST_FIRST(head) ((head)->slh_first) #define SLIST_END(head) NULL #define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) #define SLIST_FOREACH(var, head, field) \ for((var) = SLIST_FIRST(head); \ (var) != SLIST_END(head); \ (var) = SLIST_NEXT(var, field)) #define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ for ((varp) = &SLIST_FIRST((head)); \ ((var) = *(varp)) != SLIST_END(head); \ (varp) = &SLIST_NEXT((var), field)) /* * Singly-linked List functions. */ #define SLIST_INIT(head) { \ SLIST_FIRST(head) = SLIST_END(head); \ } #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ (elm)->field.sle_next = (slistelm)->field.sle_next; \ (slistelm)->field.sle_next = (elm); \ } while (0) #define SLIST_INSERT_HEAD(head, elm, field) do { \ (elm)->field.sle_next = (head)->slh_first; \ (head)->slh_first = (elm); \ } while (0) #define SLIST_REMOVE_NEXT(head, elm, field) do { \ (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ } while (0) #define SLIST_REMOVE_HEAD(head, field) do { \ (head)->slh_first = (head)->slh_first->field.sle_next; \ } while (0) #define SLIST_REMOVE(head, elm, type, field) do { \ if ((head)->slh_first == (elm)) { \ SLIST_REMOVE_HEAD((head), field); \ } else { \ struct type *curelm = (head)->slh_first; \ \ while (curelm->field.sle_next != (elm)) \ curelm = curelm->field.sle_next; \ curelm->field.sle_next = \ curelm->field.sle_next->field.sle_next; \ _Q_INVALIDATE((elm)->field.sle_next); \ } \ } while (0) /* * List definitions. */ #define LIST_HEAD(name, type) \ struct name { \ struct type *lh_first; /* first element */ \ } #define LIST_HEAD_INITIALIZER(head) \ { NULL } #define LIST_ENTRY(type) \ struct { \ struct type *le_next; /* next element */ \ struct type **le_prev; /* address of previous next element */ \ } /* * List access methods */ #define LIST_FIRST(head) ((head)->lh_first) #define LIST_END(head) NULL #define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) #define LIST_NEXT(elm, field) ((elm)->field.le_next) #define LIST_FOREACH(var, head, field) \ for((var) = LIST_FIRST(head); \ (var)!= LIST_END(head); \ (var) = LIST_NEXT(var, field)) /* * List functions. */ #define LIST_INIT(head) do { \ LIST_FIRST(head) = LIST_END(head); \ } while (0) #define LIST_INSERT_AFTER(listelm, elm, field) do { \ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ (listelm)->field.le_next->field.le_prev = \ &(elm)->field.le_next; \ (listelm)->field.le_next = (elm); \ (elm)->field.le_prev = &(listelm)->field.le_next; \ } while (0) #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.le_prev = (listelm)->field.le_prev; \ (elm)->field.le_next = (listelm); \ *(listelm)->field.le_prev = (elm); \ (listelm)->field.le_prev = &(elm)->field.le_next; \ } while (0) #define LIST_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.le_next = (head)->lh_first) != NULL) \ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ (head)->lh_first = (elm); \ (elm)->field.le_prev = &(head)->lh_first; \ } while (0) #define LIST_REMOVE(elm, field) do { \ if ((elm)->field.le_next != NULL) \ (elm)->field.le_next->field.le_prev = \ (elm)->field.le_prev; \ *(elm)->field.le_prev = (elm)->field.le_next; \ _Q_INVALIDATE((elm)->field.le_prev); \ _Q_INVALIDATE((elm)->field.le_next); \ } while (0) #define LIST_REPLACE(elm, elm2, field) do { \ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ (elm2)->field.le_next->field.le_prev = \ &(elm2)->field.le_next; \ (elm2)->field.le_prev = (elm)->field.le_prev; \ *(elm2)->field.le_prev = (elm2); \ _Q_INVALIDATE((elm)->field.le_prev); \ _Q_INVALIDATE((elm)->field.le_next); \ } while (0) /* * Simple queue definitions. */ #define SIMPLEQ_HEAD(name, type) \ struct name { \ struct type *sqh_first; /* first element */ \ struct type **sqh_last; /* addr of last next element */ \ } #define SIMPLEQ_HEAD_INITIALIZER(head) \ { NULL, &(head).sqh_first } #define SIMPLEQ_ENTRY(type) \ struct { \ struct type *sqe_next; /* next element */ \ } /* * Simple queue access methods. */ #define SIMPLEQ_FIRST(head) ((head)->sqh_first) #define SIMPLEQ_END(head) NULL #define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) #define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) #define SIMPLEQ_FOREACH(var, head, field) \ for((var) = SIMPLEQ_FIRST(head); \ (var) != SIMPLEQ_END(head); \ (var) = SIMPLEQ_NEXT(var, field)) /* * Simple queue functions. */ #define SIMPLEQ_INIT(head) do { \ (head)->sqh_first = NULL; \ (head)->sqh_last = &(head)->sqh_first; \ } while (0) #define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ (head)->sqh_last = &(elm)->field.sqe_next; \ (head)->sqh_first = (elm); \ } while (0) #define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.sqe_next = NULL; \ *(head)->sqh_last = (elm); \ (head)->sqh_last = &(elm)->field.sqe_next; \ } while (0) #define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ (head)->sqh_last = &(elm)->field.sqe_next; \ (listelm)->field.sqe_next = (elm); \ } while (0) #define SIMPLEQ_REMOVE_HEAD(head, field) do { \ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ (head)->sqh_last = &(head)->sqh_first; \ } while (0) /* * Tail queue definitions. */ #define TAILQ_HEAD(name, type) \ struct name { \ struct type *tqh_first; /* first element */ \ struct type **tqh_last; /* addr of last next element */ \ } #define TAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).tqh_first } #define TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ } /* * tail queue access methods */ #define TAILQ_FIRST(head) ((head)->tqh_first) #define TAILQ_END(head) NULL #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_LAST(head, headname) \ (*(((struct headname *)((head)->tqh_last))->tqh_last)) /* XXX */ #define TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) #define TAILQ_EMPTY(head) \ (TAILQ_FIRST(head) == TAILQ_END(head)) #define TAILQ_FOREACH(var, head, field) \ for((var) = TAILQ_FIRST(head); \ (var) != TAILQ_END(head); \ (var) = TAILQ_NEXT(var, field)) #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ for((var) = TAILQ_LAST(head, headname); \ (var) != TAILQ_END(head); \ (var) = TAILQ_PREV(var, headname, field)) /* * Tail queue functions. */ #define TAILQ_INIT(head) do { \ (head)->tqh_first = NULL; \ (head)->tqh_last = &(head)->tqh_first; \ } while (0) #define TAILQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ (head)->tqh_first->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (head)->tqh_first = (elm); \ (elm)->field.tqe_prev = &(head)->tqh_first; \ } while (0) #define TAILQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.tqe_next = NULL; \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ (head)->tqh_last = &(elm)->field.tqe_next; \ } while (0) #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ (elm)->field.tqe_next->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (listelm)->field.tqe_next = (elm); \ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ } while (0) #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ (elm)->field.tqe_next = (listelm); \ *(listelm)->field.tqe_prev = (elm); \ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ } while (0) #define TAILQ_REMOVE(head, elm, field) do { \ if (((elm)->field.tqe_next) != NULL) \ (elm)->field.tqe_next->field.tqe_prev = \ (elm)->field.tqe_prev; \ else \ (head)->tqh_last = (elm)->field.tqe_prev; \ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ _Q_INVALIDATE((elm)->field.tqe_prev); \ _Q_INVALIDATE((elm)->field.tqe_next); \ } while (0) #define TAILQ_REPLACE(head, elm, elm2, field) do { \ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ (elm2)->field.tqe_next->field.tqe_prev = \ &(elm2)->field.tqe_next; \ else \ (head)->tqh_last = &(elm2)->field.tqe_next; \ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ *(elm2)->field.tqe_prev = (elm2); \ _Q_INVALIDATE((elm)->field.tqe_prev); \ _Q_INVALIDATE((elm)->field.tqe_next); \ } while (0) /* * Circular queue definitions. */ #define CIRCLEQ_HEAD(name, type) \ struct name { \ struct type *cqh_first; /* first element */ \ struct type *cqh_last; /* last element */ \ } #define CIRCLEQ_HEAD_INITIALIZER(head) \ { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } #define CIRCLEQ_ENTRY(type) \ struct { \ struct type *cqe_next; /* next element */ \ struct type *cqe_prev; /* previous element */ \ } /* * Circular queue access methods */ #define CIRCLEQ_FIRST(head) ((head)->cqh_first) #define CIRCLEQ_LAST(head) ((head)->cqh_last) #define CIRCLEQ_END(head) ((void *)(head)) #define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) #define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) #define CIRCLEQ_EMPTY(head) \ (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) #define CIRCLEQ_FOREACH(var, head, field) \ for((var) = CIRCLEQ_FIRST(head); \ (var) != CIRCLEQ_END(head); \ (var) = CIRCLEQ_NEXT(var, field)) #define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ for((var) = CIRCLEQ_LAST(head); \ (var) != CIRCLEQ_END(head); \ (var) = CIRCLEQ_PREV(var, field)) /* * Circular queue functions. */ #define CIRCLEQ_INIT(head) do { \ (head)->cqh_first = CIRCLEQ_END(head); \ (head)->cqh_last = CIRCLEQ_END(head); \ } while (0) #define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm)->field.cqe_next; \ (elm)->field.cqe_prev = (listelm); \ if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ (head)->cqh_last = (elm); \ else \ (listelm)->field.cqe_next->field.cqe_prev = (elm); \ (listelm)->field.cqe_next = (elm); \ } while (0) #define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm); \ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ (head)->cqh_first = (elm); \ else \ (listelm)->field.cqe_prev->field.cqe_next = (elm); \ (listelm)->field.cqe_prev = (elm); \ } while (0) #define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ (elm)->field.cqe_next = (head)->cqh_first; \ (elm)->field.cqe_prev = CIRCLEQ_END(head); \ if ((head)->cqh_last == CIRCLEQ_END(head)) \ (head)->cqh_last = (elm); \ else \ (head)->cqh_first->field.cqe_prev = (elm); \ (head)->cqh_first = (elm); \ } while (0) #define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.cqe_next = CIRCLEQ_END(head); \ (elm)->field.cqe_prev = (head)->cqh_last; \ if ((head)->cqh_first == CIRCLEQ_END(head)) \ (head)->cqh_first = (elm); \ else \ (head)->cqh_last->field.cqe_next = (elm); \ (head)->cqh_last = (elm); \ } while (0) #define CIRCLEQ_REMOVE(head, elm, field) do { \ if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ (head)->cqh_last = (elm)->field.cqe_prev; \ else \ (elm)->field.cqe_next->field.cqe_prev = \ (elm)->field.cqe_prev; \ if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ (head)->cqh_first = (elm)->field.cqe_next; \ else \ (elm)->field.cqe_prev->field.cqe_next = \ (elm)->field.cqe_next; \ _Q_INVALIDATE((elm)->field.cqe_prev); \ _Q_INVALIDATE((elm)->field.cqe_next); \ } while (0) #define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ CIRCLEQ_END(head)) \ (head).cqh_last = (elm2); \ else \ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ CIRCLEQ_END(head)) \ (head).cqh_first = (elm2); \ else \ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ _Q_INVALIDATE((elm)->field.cqe_prev); \ _Q_INVALIDATE((elm)->field.cqe_next); \ } while (0) #endif /* !_SYS_QUEUE_H_ */ miniupnpc-1.9.20140610/Changelog.txt010064400017500000024000000344411234555371300161110ustar00nanardstaff$Id: Changelog.txt,v 1.195 2014/06/10 09:43:40 nanard Exp $ miniUPnP client Changelog. 2014/06/10: rename LIBSPEC to MINIUPNP_LIBSPEC 2014/05/15: Add support for IGD2 AddAnyPortMapping and DeletePortMappingRange 2014/02/05: handle EINPROGRESS after connect() 2014/02/03: minixml now handle XML comments VERSION 1.9 : released 2014/01/31 2014/01/31: added argument remoteHost to UPNP_GetSpecificPortMappingEntry() increment API_VERSION to 10 2013/12/09: --help and -h arguments in upnpc.c 2013/10/07: fixed potential buffer overrun in miniwget.c Modified UPNP_GetValidIGD() to check for ExternalIpAddress 2013/08/01: define MAXHOSTNAMELEN if not already done 2013/06/06: update upnpreplyparse to allow larger values (128 chars instead of 64) 2013/05/14: Update upnpreplyparse to take into account "empty" elements validate upnpreplyparse.c code with "make check" 2013/05/03: Fix Solaris build thanks to Maciej MaÅ‚ecki 2013/04/27: Fix testminiwget.sh for BSD 2013/03/23: Fixed Makefile for *BSD 2013/03/11: Update Makefile to use JNAerator version 0.11 2013/02/11: Fix testminiwget.sh for use with dash Use $(DESTDIR) in Makefile VERSION 1.8 : released 2013/02/06 2012/10/16: fix testminiwget with no IPv6 support 2012/09/27: Rename all include guards to not clash with C99 (7.1.3 Reserved identifiers). 2012/08/30: Added -e option to upnpc program (set description for port mappings) 2012/08/29: Python 3 support (thanks to Christopher Foo) 2012/08/11: Fix a memory link in UPNP_GetValidIGD() Try to handle scope id in link local IPv6 URL under MS Windows 2012/07/20: Disable HAS_IP_MREQN on DragonFly BSD 2012/06/28: GetUPNPUrls() now inserts scope into link-local IPv6 addresses 2012/06/23: More error return checks in upnpc.c #define MINIUPNPC_GET_SRC_ADDR enables receivedata() to get scope_id parseURL() now parses IPv6 addresses scope new parameter for miniwget() : IPv6 address scope increment API_VERSION to 9 2012/06/20: fixed CMakeLists.txt 2012/05/29 Improvements in testminiwget.sh VERSION 1.7 : released 2012/05/24 2012/05/01: Cleanup settings of CFLAGS in Makefile Fix signed/unsigned integer comparaisons 2012/04/20: Allow to specify protocol with TCP or UDP for -A option 2012/04/09: Only try to fetch XML description once in UPNP_GetValidIGD() Added -ansi flag to compilation, and fixed C++ comments to ANSI C comments. 2012/04/05: minor improvements to minihttptestserver.c 2012/03/15: upnperrors.c returns valid error string for unrecognized error codes 2012/03/08: make minihttptestserver listen on loopback interface instead of 0.0.0.0 2012/01/25: Maven installation thanks to Alexey Kuznetsov 2012/01/21: Replace WIN32 macro by _WIN32 2012/01/19: Fixes in java wrappers thanks to Alexey Kuznetsov : https://github.com/axet/miniupnp/tree/fix-javatest/miniupnpc Make and install .deb packages (python) thanks to Alexey Kuznetsov : https://github.com/axet/miniupnp/tree/feature-debbuild/miniupnpc 2012/01/07: The multicast interface can now be specified by name with IPv4. 2012/01/02: Install man page 2011/11/25: added header to Port Mappings list in upnpc.c 2011/10/09: Makefile : make clean now removes jnaerator generated files. MINIUPNPC_VERSION in miniupnpc.h (updated by make) 2011/09/12: added rootdescURL to UPNPUrls structure. VERSION 1.6 : released 2011/07/25 2011/07/25: Update doc for version 1.6 release 2011/06/18: Fix for windows in miniwget.c 2011/06/04: display remote host in port mapping listing 2011/06/03: Fix in make install : there were missing headers 2011/05/26: Fix the socket leak in miniwget thanks to Richard Marsh. Permit to add leaseduration in -a command. Display lease duration. 2011/05/15: Try both LinkLocal and SiteLocal multicast address for SSDP in IPv6 2011/05/09: add a test in testminiwget.sh. more error checking in miniwget.c 2011/05/06: Adding some tool to test and validate miniwget.c simplified and debugged miniwget.c 2011/04/11: moving ReceiveData() to a receivedata.c file. parsing presentation url adding IGD v2 WANIPv6FirewallControl commands 2011/04/10: update of miniupnpcmodule.c comments in miniwget.c, update in testminiwget Adding errors codes from IGD v2 new functions in upnpc.c for IGD v2 2011/04/09: Support for litteral ip v6 address in miniwget 2011/04/08: Adding support for urn:schemas-upnp-org:service:WANIPv6FirewallControl:1 Updating APIVERSION Supporting IPV6 in upnpDiscover() Adding a -6 option to upnpc command line tool 2011/03/18: miniwget/parseURL() : return an error when url param is null. fixing GetListOfPortMappings() 2011/03/14: upnpDiscover() now reporting an error code. improvements in comments. 2011/03/11: adding miniupnpcstrings.h.cmake and CMakeLists.txt files. 2011/02/15: Implementation of GetListOfPortMappings() 2011/02/07: updates to minixml to support character data starting with spaces minixml now support CDATA upnpreplyparse treats specificaly change in simpleUPnPcommand to return the buffer (simplification) 2011/02/06: Added leaseDuration argument to AddPortMapping() Starting to implement GetListOfPortMappings() 2011/01/11: updating wingenminiupnpcstrings.c 2011/01/04: improving updateminiupnpcstrings.sh VERSION 1.5 : released 2011/01/01 2010/12/21: use NO_GETADDRINFO macro to disable the use of getaddrinfo/freeaddrinfo 2010/12/11: Improvements on getHTTPResponse() code. 2010/12/09: new code for miniwget that handle Chunked transfer encoding using getHTTPResponse() in SOAP call code Adding MANIFEST.in for 'python setup.py bdist_rpm' 2010/11/25: changes to minissdpc.c to compile under Win32. see http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=729 2010/09/17: Various improvement to Makefile from MichaÅ‚ Górny 2010/08/05: Adding the script "external-ip.sh" from Reuben Hawkins 2010/06/09: update to python module to match modification made on 2010/04/05 update to Java test code to match modification made on 2010/04/05 all UPNP_* function now return an error if the SOAP request failed at HTTP level. 2010/04/17: Using GetBestRoute() under win32 in order to find the right interface to use. 2010/04/12: Retrying with HTTP/1.1 if HTTP/1.0 failed. see http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1703 2010/04/07: avoid returning duplicates in upnpDiscover() 2010/04/05: Create a connecthostport.h/.c with connecthostport() function and use it in miniwget and miniupnpc. Use getnameinfo() instead of inet_ntop or inet_ntoa Work to make miniupnpc IPV6 compatible... Add java test code. Big changes in order to support device having both WANIPConnection and WANPPPConnection. 2010/04/04: Use getaddrinfo() instead of gethostbyname() in miniwget. 2010/01/06: #define _DARWIN_C_SOURCE for Mac OS X 2009/12/19: Improve MinGW32 build 2009/12/11: adding a MSVC9 project to build the static library and executable 2009/12/10: Fixing some compilation stuff for Windows/MinGW 2009/12/07: adaptations in Makefile and updateminiupnpcstring.sh for AmigaOS some fixes for Windows when using virtual ethernet adapters (it is the case with VMWare installed). 2009/12/04: some fixes for AmigaOS compilation Changed HTTP version to HTTP/1.0 for Soap too (to prevent chunked transfer encoding) 2009/12/03: updating printIDG and testigddescparse.c for debug. modifications to compile under AmigaOS adding a testminiwget program Changed miniwget to advertise itself as HTTP/1.0 to prevent chunked transfer encoding 2009/11/26: fixing updateminiupnpcstrings.sh to take into account which command that does not return an error code. VERSION 1.4 : released 2009/10/30 2009/10/16: using Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS in python module. 2009/10/10: Some fixes for compilation under Solaris compilation fixes : http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1464 2009/09/21: fixing the code to ignore EINTR during connect() calls. 2009/08/07: Set socket timeout for connect() Some cleanup in miniwget.c 2009/08/04: remove multiple redirections with -d in upnpc.c Print textual error code in upnpc.c Ignore EINTR during the connect() and poll() calls. 2009/07/29: fix in updateminiupnpcstrings.sh if OS name contains "/" Sending a correct value for MX: field in SSDP request 2009/07/20: Change the Makefile to compile under Mac OS X Fixed a stackoverflow in getDevicesFromMiniSSDPD() 2009/07/09: Compile under Haiku generate miniupnpcstrings.h.in from miniupnpcstrings.h 2009/06/04: patching to compile under CygWin and cross compile for minGW VERSION 1.3 : 2009/04/17: updating python module Use strtoull() when using C99 2009/02/28: Fixed miniwget.c for compiling under sun 2008/12/18: cleanup in Makefile (thanks to Paul de Weerd) minissdpc.c : win32 compatibility miniupnpc.c : changed xmlns prefix from 'm' to 'u' Removed NDEBUG (using DEBUG) 2008/10/14: Added the ExternalHost argument to DeletePortMapping() 2008/10/11: Added the ExternalHost argument to AddPortMapping() Put a correct User-Agent: header in HTTP requests. VERSION 1.2 : 2008/10/07: Update docs 2008/09/25: Integrated sameport patch from Dario Meloni : Added a "sameport" argument to upnpDiscover(). 2008/07/18: small modif to make Clang happy :) 2008/07/17: #define SOAPPREFIX "s" in miniupnpc.c in order to remove SOAP-ENV... 2008/07/14: include declspec.h in installation (to /usr/include/miniupnpc) VERSION 1.1 : 2008/07/04: standard options for install/ln instead of gnu-specific stuff. 2008/07/03: now builds a .dll and .lib with win32. (mingw32) 2008/04/28: make install now install the binary of the upnpc tool 2008/04/27: added testupnpigd.py added error strings for miniupnpc "internal" errors improved python module error/exception reporting. 2008/04/23: Completely rewrite igd_desc_parse.c in order to be compatible with Linksys WAG200G Added testigddescparse updated python module VERSION 1.0 : 2008/02/21: put some #ifdef DEBUG around DisplayNameValueList() 2008/02/18: Improved error reporting in upnpcommands.c UPNP_GetStatusInfo() returns LastConnectionError 2008/02/16: better error handling in minisoap.c improving display of "valid IGD found" in upnpc.c 2008/02/03: Fixing UPNP_GetValidIGD() improved make install :) 2007/12/22: Adding upnperrors.c/h to provide a strupnperror() function used to translate UPnP error codes to string. 2007/12/19: Fixing getDevicesFromMiniSSDPD() improved error reporting of UPnP functions 2007/12/18: It is now possible to specify a different location for MiniSSDPd socket. working with MiniSSDPd is now more efficient. python module improved. 2007/12/16: improving error reporting 2007/12/13: Try to improve compatibility by using HTTP/1.0 instead of 1.1 and XML a bit different for SOAP. 2007/11/25: fixed select() call for linux 2007/11/15: Added -fPIC to CFLAG for better shared library code. 2007/11/02: Fixed a potential socket leak in miniwget2() 2007/10/16: added a parameter to upnpDiscover() in order to allow the use of another interface than the default multicast interface. 2007/10/12: Fixed the creation of symbolic link in Makefile 2007/10/08: Added man page 2007/10/02: fixed memory bug in GetUPNPUrls() 2007/10/01: fixes in the Makefile Added UPNP_GetIGDFromUrl() and adapted the sample program accordingly. Added SONAME in the shared library to please debian :) fixed MS Windows compilation (minissdpd is not available under MS Windows). 2007/09/25: small change to Makefile to be able to install in a different location (default is /usr) 2007/09/24: now compiling both shared and static library 2007/09/19: Cosmetic changes on upnpc.c 2007/09/02: adapting to new miniSSDPd (release version ?) 2007/08/31: Usage of miniSSDPd to skip discovery process. 2007/08/27: fixed python module to allow compilation with Python older than Python 2.4 2007/06/12: Added a python module. 2007/05/19: Fixed compilation under MinGW 2007/05/15: fixed a memory leak in AddPortMapping() Added testupnpreplyparse executable to check the parsing of upnp soap messages minixml now ignore namespace prefixes. 2007/04/26: upnpc now displays external ip address with -s or -l 2007/04/11: changed MINIUPNPC_URL_MAXSIZE to 128 to accomodate the "BT Voyager 210" 2007/03/19: cleanup in miniwget.c 2007/03/01: Small typo fix... 2007/01/30: Now parsing the HTTP header from SOAP responses in order to get content-length value. 2007/01/29: Fixed the Soap Query to speedup the HTTP request. added some Win32 DLL stuff... 2007/01/27: Fixed some WIN32 compatibility issues 2006/12/14: Added UPNPIGD_IsConnected() function in miniupnp.c/.h Added UPNP_GetValidIGD() in miniupnp.c/.h cleaned upnpc.c main(). now using UPNP_GetValidIGD() 2006/12/07: Version 1.0-RC1 released 2006/12/03: Minor changes to compile under SunOS/Solaris 2006/11/30: made a minixml parser validator program updated minixml to handle attributes correctly 2006/11/22: Added a -r option to the upnpc sample thanks to Alexander Hubmann. 2006/11/19: Cleanup code to make it more ANSI C compliant 2006/11/10: detect and display local lan address. 2006/11/04: Packets and Bytes Sent/Received are now unsigned int. 2006/11/01: Bug fix thanks to Giuseppe D'Angelo 2006/10/31: C++ compatibility for .h files. Added a way to get ip Address on the LAN used to reach the IGD. 2006/10/25: Added M-SEARCH to the services in the discovery process. 2006/10/22: updated the Makefile to use makedepend, added a "make install" update Makefile 2006/10/20: fixing the description url parsing thanks to patch sent by Wayne Dawe. Fixed/translated some comments. Implemented a better discover process, first looking for IGD then for root devices (as some devices only reply to M-SEARCH for root devices). 2006/09/02: added freeUPNPDevlist() function. 2006/08/04: More command line arguments checking 2006/08/01: Added the .bat file to compile under Win32 with minGW32 2006/07/31: Fixed the rootdesc parser (igd_desc_parse.c) 2006/07/20: parseMSEARCHReply() is now returning the ST: line as well starting changes to detect several UPnP devices on the network 2006/07/19: using GetCommonLinkProperties to get down/upload bitrate miniupnpc-1.9.20140610/minixmlvalid.c010064400017500000024000000067161175004160500163150ustar00nanardstaff/* $Id: minixmlvalid.c,v 1.6 2012/05/01 16:24:07 nanard Exp $ */ /* MiniUPnP Project * http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/ * minixmlvalid.c : * validation program for the minixml parser * * (c) 2006-2011 Thomas Bernard */ #include #include #include #include "minixml.h" /* xml event structure */ struct event { enum { ELTSTART, ELTEND, ATT, CHARDATA } type; const char * data; int len; }; struct eventlist { int n; struct event * events; }; /* compare 2 xml event lists * return 0 if the two lists are equals */ int evtlistcmp(struct eventlist * a, struct eventlist * b) { int i; struct event * ae, * be; if(a->n != b->n) { printf("event number not matching : %d != %d\n", a->n, b->n); /*return 1;*/ } for(i=0; in; i++) { ae = a->events + i; be = b->events + i; if( (ae->type != be->type) ||(ae->len != be->len) ||memcmp(ae->data, be->data, ae->len)) { printf("Found a difference : %d '%.*s' != %d '%.*s'\n", ae->type, ae->len, ae->data, be->type, be->len, be->data); return 1; } } return 0; } /* Test data */ static const char xmldata[] = "\n" " " "character data" " \n \t" "" "\nstuff !\n ]]> \n\n" " \tchardata1 chardata2 " ""; static const struct event evtref[] = { {ELTSTART, "xmlroot", 7}, {ELTSTART, "elt1", 4}, /* attributes */ {CHARDATA, "character data", 14}, {ELTEND, "elt1", 4}, {ELTSTART, "elt1b", 5}, {ELTSTART, "elt1", 4}, {CHARDATA, " stuff !\n ", 16}, {ELTEND, "elt1", 4}, {ELTSTART, "elt2a", 5}, {ELTSTART, "elt2b", 5}, {CHARDATA, "chardata1", 9}, {ELTEND, "elt2b", 5}, {ELTSTART, "elt2b", 5}, {CHARDATA, " chardata2 ", 11}, {ELTEND, "elt2b", 5}, {ELTEND, "elt2a", 5}, {ELTEND, "xmlroot", 7} }; void startelt(void * data, const char * p, int l) { struct eventlist * evtlist = data; struct event * evt; evt = evtlist->events + evtlist->n; /*printf("startelt : %.*s\n", l, p);*/ evt->type = ELTSTART; evt->data = p; evt->len = l; evtlist->n++; } void endelt(void * data, const char * p, int l) { struct eventlist * evtlist = data; struct event * evt; evt = evtlist->events + evtlist->n; /*printf("endelt : %.*s\n", l, p);*/ evt->type = ELTEND; evt->data = p; evt->len = l; evtlist->n++; } void chardata(void * data, const char * p, int l) { struct eventlist * evtlist = data; struct event * evt; evt = evtlist->events + evtlist->n; /*printf("chardata : '%.*s'\n", l, p);*/ evt->type = CHARDATA; evt->data = p; evt->len = l; evtlist->n++; } int testxmlparser(const char * xml, int size) { int r; struct eventlist evtlist; struct eventlist evtlistref; struct xmlparser parser; evtlist.n = 0; evtlist.events = malloc(sizeof(struct event)*100); memset(&parser, 0, sizeof(parser)); parser.xmlstart = xml; parser.xmlsize = size; parser.data = &evtlist; parser.starteltfunc = startelt; parser.endeltfunc = endelt; parser.datafunc = chardata; parsexml(&parser); printf("%d events\n", evtlist.n); /* compare */ evtlistref.n = sizeof(evtref)/sizeof(struct event); evtlistref.events = (struct event *)evtref; r = evtlistcmp(&evtlistref, &evtlist); free(evtlist.events); return r; } int main(int argc, char * * argv) { int r; (void)argc; (void)argv; r = testxmlparser(xmldata, sizeof(xmldata)-1); if(r) printf("minixml validation test failed\n"); return r; } miniupnpc-1.9.20140610/declspec.h010064400017500000024000000007701234555371300154120ustar00nanardstaff#ifndef DECLSPEC_H_INCLUDED #define DECLSPEC_H_INCLUDED #if defined(_WIN32) && !defined(MINIUPNP_STATICLIB) /* for windows dll */ #ifdef MINIUPNP_EXPORTS #define MINIUPNP_LIBSPEC __declspec(dllexport) #else #define MINIUPNP_LIBSPEC __declspec(dllimport) #endif #else #if defined(__GNUC__) && __GNUC__ >= 4 /* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */ #define MINIUPNP_LIBSPEC __attribute__ ((visibility ("default"))) #else #define MINIUPNP_LIBSPEC #endif #endif #endif miniupnpc-1.9.20140610/mingw32make.bat010064400017500000024000000003241131314053500162520ustar00nanardstaff@mingw32-make -f Makefile.mingw %1 @if errorlevel 1 goto end @if not exist upnpc-static.exe goto end @strip upnpc-static.exe @upx --best upnpc-static.exe @strip upnpc-shared.exe @upx --best upnpc-shared.exe :end miniupnpc-1.9.20140610/testupnpreplyparse.c010064400017500000024000000037721227272130200176070ustar00nanardstaff/* $Id: testupnpreplyparse.c,v 1.4 2014/01/27 11:45:19 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #include #include #include #include "upnpreplyparse.h" int test_parsing(const char * buf, int len, FILE * f) { char line[1024]; struct NameValueParserData pdata; int ok = 1; ParseNameValue(buf, len, &pdata); /* check result */ if(f != NULL) { while(fgets(line, sizeof(line), f)) { char * value; char * equal; char * parsedvalue; int l; l = strlen(line); while((l > 0) && ((line[l-1] == '\r') || (line[l-1] == '\n'))) line[--l] = '\0'; /* skip empty lines */ if(l == 0) continue; equal = strchr(line, '='); if(equal == NULL) { fprintf(stderr, "Warning, line does not contain '=' : %s\n", line); continue; } *equal = '\0'; value = equal + 1; parsedvalue = GetValueFromNameValueList(&pdata, line); if((parsedvalue == NULL) || (strcmp(parsedvalue, value) != 0)) { fprintf(stderr, "Element <%s> : expecting value '%s', got '%s'\n", line, value, parsedvalue ? parsedvalue : ""); ok = 0; } } } ClearNameValueList(&pdata); return ok; } int main(int argc, char * * argv) { FILE * f; char buffer[4096]; int l; int ok; if(argc<2) { fprintf(stderr, "Usage: %s file.xml [file.namevalues]\n", argv[0]); return 1; } f = fopen(argv[1], "r"); if(!f) { fprintf(stderr, "Error : can not open file %s\n", argv[1]); return 2; } l = fread(buffer, 1, sizeof(buffer)-1, f); fclose(f); f = NULL; buffer[l] = '\0'; if(argc > 2) { f = fopen(argv[2], "r"); if(!f) { fprintf(stderr, "Error : can not open file %s\n", argv[2]); return 2; } } #ifdef DEBUG DisplayNameValueList(buffer, l); #endif ok = test_parsing(buffer, l, f); if(f) { fclose(f); } return ok ? 0 : 3; } miniupnpc-1.9.20140610/miniupnpcmodule.c010064400017500000024000000425421234555371500170400ustar00nanardstaff/* $Id: miniupnpcmodule.c,v 1.24 2014/06/10 09:48:11 nanard Exp $*/ /* Project : miniupnp * Author : Thomas BERNARD * website : http://miniupnp.tuxfamily.org/ * copyright (c) 2007-2014 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENCE file. */ #include #define MINIUPNP_STATICLIB #include "structmember.h" #include "miniupnpc.h" #include "upnpcommands.h" #include "upnperrors.h" /* for compatibility with Python < 2.4 */ #ifndef Py_RETURN_NONE #define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None #endif #ifndef Py_RETURN_TRUE #define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True #endif #ifndef Py_RETURN_FALSE #define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False #endif /* for compatibility with Python < 3.0 */ #ifndef PyVarObject_HEAD_INIT #define PyVarObject_HEAD_INIT(type, size) \ PyObject_HEAD_INIT(type) size, #endif #ifndef Py_TYPE #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) #endif typedef struct { PyObject_HEAD /* Type-specific fields go here. */ struct UPNPDev * devlist; struct UPNPUrls urls; struct IGDdatas data; unsigned int discoverdelay; /* value passed to upnpDiscover() */ char lanaddr[40]; /* our ip address on the LAN */ char * multicastif; char * minissdpdsocket; } UPnPObject; static PyMemberDef UPnP_members[] = { {"lanaddr", T_STRING_INPLACE, offsetof(UPnPObject, lanaddr), READONLY, "ip address on the LAN" }, {"discoverdelay", T_UINT, offsetof(UPnPObject, discoverdelay), 0/*READWRITE*/, "value in ms used to wait for SSDP responses" }, /* T_STRING is allways readonly :( */ {"multicastif", T_STRING, offsetof(UPnPObject, multicastif), 0, "IP of the network interface to be used for multicast operations" }, {"minissdpdsocket", T_STRING, offsetof(UPnPObject, multicastif), 0, "path of the MiniSSDPd unix socket" }, {NULL} }; static void UPnPObject_dealloc(UPnPObject *self) { freeUPNPDevlist(self->devlist); FreeUPNPUrls(&self->urls); Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject * UPnP_discover(UPnPObject *self) { struct UPNPDev * dev; int i; PyObject *res = NULL; if(self->devlist) { freeUPNPDevlist(self->devlist); self->devlist = 0; } Py_BEGIN_ALLOW_THREADS self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/, 0/* multicast if*/, 0/*minissdpd socket*/, 0/*sameport flag*/, 0/*ip v6*/, 0/*error */); Py_END_ALLOW_THREADS /* Py_RETURN_NONE ??? */ for(dev = self->devlist, i = 0; dev; dev = dev->pNext) i++; res = Py_BuildValue("i", i); return res; } static PyObject * UPnP_selectigd(UPnPObject *self) { int r; Py_BEGIN_ALLOW_THREADS r = UPNP_GetValidIGD(self->devlist, &self->urls, &self->data, self->lanaddr, sizeof(self->lanaddr)); Py_END_ALLOW_THREADS if(r) { return Py_BuildValue("s", self->urls.controlURL); } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, "No UPnP device discovered"); return NULL; } } static PyObject * UPnP_totalbytesent(UPnPObject *self) { UNSIGNED_INTEGER i; Py_BEGIN_ALLOW_THREADS i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF, self->data.CIF.servicetype); Py_END_ALLOW_THREADS return Py_BuildValue("I", i); } static PyObject * UPnP_totalbytereceived(UPnPObject *self) { UNSIGNED_INTEGER i; Py_BEGIN_ALLOW_THREADS i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF, self->data.CIF.servicetype); Py_END_ALLOW_THREADS return Py_BuildValue("I", i); } static PyObject * UPnP_totalpacketsent(UPnPObject *self) { UNSIGNED_INTEGER i; Py_BEGIN_ALLOW_THREADS i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF, self->data.CIF.servicetype); Py_END_ALLOW_THREADS return Py_BuildValue("I", i); } static PyObject * UPnP_totalpacketreceived(UPnPObject *self) { UNSIGNED_INTEGER i; Py_BEGIN_ALLOW_THREADS i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF, self->data.CIF.servicetype); Py_END_ALLOW_THREADS return Py_BuildValue("I", i); } static PyObject * UPnP_statusinfo(UPnPObject *self) { char status[64]; char lastconnerror[64]; unsigned int uptime = 0; int r; status[0] = '\0'; lastconnerror[0] = '\0'; Py_BEGIN_ALLOW_THREADS r = UPNP_GetStatusInfo(self->urls.controlURL, self->data.first.servicetype, status, &uptime, lastconnerror); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror); } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } } static PyObject * UPnP_connectiontype(UPnPObject *self) { char connectionType[64]; int r; connectionType[0] = '\0'; Py_BEGIN_ALLOW_THREADS r = UPNP_GetConnectionTypeInfo(self->urls.controlURL, self->data.first.servicetype, connectionType); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { return Py_BuildValue("s", connectionType); } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } } static PyObject * UPnP_externalipaddress(UPnPObject *self) { char externalIPAddress[40]; int r; externalIPAddress[0] = '\0'; Py_BEGIN_ALLOW_THREADS r = UPNP_GetExternalIPAddress(self->urls.controlURL, self->data.first.servicetype, externalIPAddress); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { return Py_BuildValue("s", externalIPAddress); } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } } /* AddPortMapping(externalPort, protocol, internalHost, internalPort, desc, * remoteHost) * protocol is 'UDP' or 'TCP' */ static PyObject * UPnP_addportmapping(UPnPObject *self, PyObject *args) { char extPort[6]; unsigned short ePort; char inPort[6]; unsigned short iPort; const char * proto; const char * host; const char * desc; const char * remoteHost; const char * leaseDuration = "0"; int r; if (!PyArg_ParseTuple(args, "HssHss", &ePort, &proto, &host, &iPort, &desc, &remoteHost)) return NULL; Py_BEGIN_ALLOW_THREADS sprintf(extPort, "%hu", ePort); sprintf(inPort, "%hu", iPort); r = UPNP_AddPortMapping(self->urls.controlURL, self->data.first.servicetype, extPort, inPort, host, desc, proto, remoteHost, leaseDuration); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { Py_RETURN_TRUE; } else { // TODO: RAISE an Exception. See upnpcommands.h for errors codes. // upnperrors.c //Py_RETURN_FALSE; /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } } /* AddAnyPortMapping(externalPort, protocol, internalHost, internalPort, desc, * remoteHost) * protocol is 'UDP' or 'TCP' */ static PyObject * UPnP_addanyportmapping(UPnPObject *self, PyObject *args) { char extPort[6]; unsigned short ePort; char inPort[6]; unsigned short iPort; char reservedPort[6]; const char * proto; const char * host; const char * desc; const char * remoteHost; const char * leaseDuration = "0"; int r; if (!PyArg_ParseTuple(args, "HssHss", &ePort, &proto, &host, &iPort, &desc, &remoteHost)) return NULL; Py_BEGIN_ALLOW_THREADS sprintf(extPort, "%hu", ePort); sprintf(inPort, "%hu", iPort); r = UPNP_AddAnyPortMapping(self->urls.controlURL, self->data.first.servicetype, extPort, inPort, host, desc, proto, remoteHost, leaseDuration, reservedPort); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { return Py_BuildValue("i", atoi(reservedPort)); } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } } /* DeletePortMapping(extPort, proto, removeHost='') * proto = 'UDP', 'TCP' */ static PyObject * UPnP_deleteportmapping(UPnPObject *self, PyObject *args) { char extPort[6]; unsigned short ePort; const char * proto; const char * remoteHost = ""; int r; if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost)) return NULL; Py_BEGIN_ALLOW_THREADS sprintf(extPort, "%hu", ePort); r = UPNP_DeletePortMapping(self->urls.controlURL, self->data.first.servicetype, extPort, proto, remoteHost); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { Py_RETURN_TRUE; } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } } /* DeletePortMappingRange(extPort, proto, removeHost='') * proto = 'UDP', 'TCP' */ static PyObject * UPnP_deleteportmappingrange(UPnPObject *self, PyObject *args) { char extPortStart[6]; unsigned short ePortStart; char extPortEnd[6]; unsigned short ePortEnd; const char * proto; unsigned char manage; char manageStr[1]; int r; if(!PyArg_ParseTuple(args, "HHsb", &ePortStart, &ePortEnd, &proto, &manage)) return NULL; Py_BEGIN_ALLOW_THREADS sprintf(extPortStart, "%hu", ePortStart); sprintf(extPortEnd, "%hu", ePortEnd); sprintf(manageStr, "%hhu", manage); r = UPNP_DeletePortMappingRange(self->urls.controlURL, self->data.first.servicetype, extPortStart, extPortEnd, proto, manageStr); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { Py_RETURN_TRUE; } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } } static PyObject * UPnP_getportmappingnumberofentries(UPnPObject *self) { unsigned int n = 0; int r; Py_BEGIN_ALLOW_THREADS r = UPNP_GetPortMappingNumberOfEntries(self->urls.controlURL, self->data.first.servicetype, &n); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { return Py_BuildValue("I", n); } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } } /* GetSpecificPortMapping(ePort, proto, remoteHost='') * proto = 'UDP' or 'TCP' */ static PyObject * UPnP_getspecificportmapping(UPnPObject *self, PyObject *args) { char extPort[6]; unsigned short ePort; const char * proto; const char * remoteHost = ""; char intClient[40]; char intPort[6]; unsigned short iPort; char desc[80]; char enabled[4]; char leaseDuration[16]; if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost)) return NULL; extPort[0] = '\0'; intClient[0] = '\0'; intPort[0] = '\0'; desc[0] = '\0'; enabled[0] = '\0'; leaseDuration[0] = '\0'; Py_BEGIN_ALLOW_THREADS sprintf(extPort, "%hu", ePort); UPNP_GetSpecificPortMappingEntry(self->urls.controlURL, self->data.first.servicetype, extPort, proto, remoteHost, intClient, intPort, desc, enabled, leaseDuration); Py_END_ALLOW_THREADS if(intClient[0]) { iPort = (unsigned short)atoi(intPort); return Py_BuildValue("(s,H,s,O,i)", intClient, iPort, desc, PyBool_FromLong(atoi(enabled)), atoi(leaseDuration)); } else { Py_RETURN_NONE; } } /* GetGenericPortMapping(index) */ static PyObject * UPnP_getgenericportmapping(UPnPObject *self, PyObject *args) { int i, r; char index[8]; char intClient[40]; char intPort[6]; unsigned short iPort; char extPort[6]; unsigned short ePort; char protocol[4]; char desc[80]; char enabled[6]; char rHost[64]; char duration[16]; /* lease duration */ unsigned int dur; if(!PyArg_ParseTuple(args, "i", &i)) return NULL; Py_BEGIN_ALLOW_THREADS snprintf(index, sizeof(index), "%d", i); rHost[0] = '\0'; enabled[0] = '\0'; duration[0] = '\0'; desc[0] = '\0'; extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0'; r = UPNP_GetGenericPortMappingEntry(self->urls.controlURL, self->data.first.servicetype, index, extPort, intClient, intPort, protocol, desc, enabled, rHost, duration); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { ePort = (unsigned short)atoi(extPort); iPort = (unsigned short)atoi(intPort); dur = (unsigned int)strtoul(duration, 0, 0); return Py_BuildValue("(H,s,(s,H),s,s,s,I)", ePort, protocol, intClient, iPort, desc, enabled, rHost, dur); } else { Py_RETURN_NONE; } } /* miniupnpc.UPnP object Method Table */ static PyMethodDef UPnP_methods[] = { {"discover", (PyCFunction)UPnP_discover, METH_NOARGS, "discover UPnP IGD devices on the network" }, {"selectigd", (PyCFunction)UPnP_selectigd, METH_NOARGS, "select a valid UPnP IGD among discovered devices" }, {"totalbytesent", (PyCFunction)UPnP_totalbytesent, METH_NOARGS, "return the total number of bytes sent by UPnP IGD" }, {"totalbytereceived", (PyCFunction)UPnP_totalbytereceived, METH_NOARGS, "return the total number of bytes received by UPnP IGD" }, {"totalpacketsent", (PyCFunction)UPnP_totalpacketsent, METH_NOARGS, "return the total number of packets sent by UPnP IGD" }, {"totalpacketreceived", (PyCFunction)UPnP_totalpacketreceived, METH_NOARGS, "return the total number of packets received by UPnP IGD" }, {"statusinfo", (PyCFunction)UPnP_statusinfo, METH_NOARGS, "return status and uptime" }, {"connectiontype", (PyCFunction)UPnP_connectiontype, METH_NOARGS, "return IGD WAN connection type" }, {"externalipaddress", (PyCFunction)UPnP_externalipaddress, METH_NOARGS, "return external IP address" }, {"addportmapping", (PyCFunction)UPnP_addportmapping, METH_VARARGS, "add a port mapping" }, {"addanyportmapping", (PyCFunction)UPnP_addanyportmapping, METH_VARARGS, "add a port mapping, IGD to select alternative if necessary" }, {"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS, "delete a port mapping" }, {"deleteportmappingrange", (PyCFunction)UPnP_deleteportmappingrange, METH_VARARGS, "delete a range of port mappings" }, {"getportmappingnumberofentries", (PyCFunction)UPnP_getportmappingnumberofentries, METH_NOARGS, "-- non standard --" }, {"getspecificportmapping", (PyCFunction)UPnP_getspecificportmapping, METH_VARARGS, "get details about a specific port mapping entry" }, {"getgenericportmapping", (PyCFunction)UPnP_getgenericportmapping, METH_VARARGS, "get all details about the port mapping at index" }, {NULL} /* Sentinel */ }; static PyTypeObject UPnPType = { PyVarObject_HEAD_INIT(NULL, 0) /*ob_size*/ "miniupnpc.UPnP", /*tp_name*/ sizeof(UPnPObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)UPnPObject_dealloc,/*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash */ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ "UPnP objects", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ UPnP_methods, /* tp_methods */ UPnP_members, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0,/*(initproc)UPnP_init,*/ /* tp_init */ 0, /* tp_alloc */ #ifndef _WIN32 PyType_GenericNew,/*UPnP_new,*/ /* tp_new */ #else 0, #endif }; /* module methods */ static PyMethodDef miniupnpc_methods[] = { {NULL} /* Sentinel */ }; #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "miniupnpc", /* m_name */ "miniupnpc module.", /* m_doc */ -1, /* m_size */ miniupnpc_methods, /* m_methods */ NULL, /* m_reload */ NULL, /* m_traverse */ NULL, /* m_clear */ NULL, /* m_free */ }; #endif #ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ #define PyMODINIT_FUNC void #endif PyMODINIT_FUNC #if PY_MAJOR_VERSION >= 3 PyInit_miniupnpc(void) #else initminiupnpc(void) #endif { PyObject* m; #ifdef _WIN32 UPnPType.tp_new = PyType_GenericNew; #endif if (PyType_Ready(&UPnPType) < 0) return; #if PY_MAJOR_VERSION >= 3 m = PyModule_Create(&moduledef); #else m = Py_InitModule3("miniupnpc", miniupnpc_methods, "miniupnpc module."); #endif Py_INCREF(&UPnPType); PyModule_AddObject(m, "UPnP", (PyObject *)&UPnPType); #if PY_MAJOR_VERSION >= 3 return m; #endif } miniupnpc-1.9.20140610/pymoduletest.py010064400017500000024000000025411107515756700165730ustar00nanardstaff#! /usr/bin/python # MiniUPnP project # Author : Thomas Bernard # This Sample code is public domain. # website : http://miniupnp.tuxfamily.org/ # import the python miniupnpc module import miniupnpc import sys # create the object u = miniupnpc.UPnP() print 'inital(default) values :' print ' discoverdelay', u.discoverdelay print ' lanaddr', u.lanaddr print ' multicastif', u.multicastif print ' minissdpdsocket', u.minissdpdsocket u.discoverdelay = 200; #u.minissdpdsocket = '../minissdpd/minissdpd.sock' # discovery process, it usualy takes several seconds (2 seconds or more) print 'Discovering... delay=%ums' % u.discoverdelay print u.discover(), 'device(s) detected' # select an igd try: u.selectigd() except Exception, e: print 'Exception :', e sys.exit(1) # display information about the IGD and the internet connection print 'local ip address :', u.lanaddr print 'external ip address :', u.externalipaddress() print u.statusinfo(), u.connectiontype() #print u.addportmapping(64000, 'TCP', # '192.168.1.166', 63000, 'port mapping test', '') #print u.deleteportmapping(64000, 'TCP') port = 0 proto = 'UDP' # list the redirections : i = 0 while True: p = u.getgenericportmapping(i) if p==None: break print i, p (port, proto, (ihost,iport), desc, c, d, e) = p #print port, desc i = i + 1 print u.getspecificportmapping(port, proto) miniupnpc-1.9.20140610/setup.py010064400017500000024000000015611233650314400151610ustar00nanardstaff#! /usr/bin/python # $Id: setup.py,v 1.10 2014/05/19 22:31:52 nanard Exp $ # the MiniUPnP Project (c) 2007-2014 Thomas Bernard # http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/ # # python script to build the miniupnpc module under unix # # replace libminiupnpc.a by libminiupnpc.so for shared library usage from distutils.core import setup, Extension from distutils import sysconfig sysconfig.get_config_vars()["OPT"] = '' sysconfig.get_config_vars()["CFLAGS"] = '' setup(name="miniupnpc", version=open('VERSION').read().strip(), author='Thomas BERNARD', author_email='miniupnp@free.fr', license=open('LICENSE').read(), url='http://miniupnp.free.fr/', description='miniUPnP client', ext_modules=[ Extension(name="miniupnpc", sources=["miniupnpcmodule.c"], extra_objects=["libminiupnpc.a"]) ]) miniupnpc-1.9.20140610/setupmingw32.py010064400017500000024000000015721233650314400163720ustar00nanardstaff#! /usr/bin/python # $Id: setupmingw32.py,v 1.9 2014/05/19 22:31:52 nanard Exp $ # the MiniUPnP Project (c) 2007-2014 Thomas Bernard # http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/ # # python script to build the miniupnpc module under windows (using mingw32) # from distutils.core import setup, Extension from distutils import sysconfig sysconfig.get_config_vars()["OPT"] = '' sysconfig.get_config_vars()["CFLAGS"] = '' setup(name="miniupnpc", version=open('VERSION').read().strip(), author='Thomas BERNARD', author_email='miniupnp@free.fr', license=open('LICENSE').read(), url='http://miniupnp.free.fr/', description='miniUPnP client', ext_modules=[ Extension(name="miniupnpc", sources=["miniupnpcmodule.c"], libraries=["ws2_32", "iphlpapi"], extra_objects=["libminiupnpc.a"]) ]) miniupnpc-1.9.20140610/minissdpc.h010064400017500000024000000007461203340733500156140ustar00nanardstaff/* $Id: minissdpc.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */ /* Project: miniupnp * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author: Thomas Bernard * Copyright (c) 2005-2007 Thomas Bernard * This software is subjects to the conditions detailed * in the LICENCE file provided within this distribution */ #ifndef MINISSDPC_H_INCLUDED #define MINISSDPC_H_INCLUDED struct UPNPDev * getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath); #endif miniupnpc-1.9.20140610/minissdpc.c010064400017500000024000000061521232542712300156050ustar00nanardstaff/* $Id: minissdpc.c,v 1.17 2014/04/14 15:18:38 nanard Exp $ */ /* Project : miniupnp * Web : http://miniupnp.free.fr/ * Author : Thomas BERNARD * copyright (c) 2005-2012 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENCE file. */ /*#include */ #include #include #include #include #include #if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) #ifdef _WIN32 #include #include #include #include #include #endif #if defined(__amigaos__) || defined(__amigaos4__) #include #endif #if defined(__amigaos__) #define uint16_t unsigned short #endif /* Hack */ #define UNIX_PATH_LEN 108 struct sockaddr_un { uint16_t sun_family; char sun_path[UNIX_PATH_LEN]; }; #else #include #include #endif #include "minissdpc.h" #include "miniupnpc.h" #include "codelength.h" struct UPNPDev * getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) { struct UPNPDev * tmp; struct UPNPDev * devlist = NULL; unsigned char buffer[4*1024]; /* is that enough ? */ ssize_t n; unsigned char * p; unsigned char * url; unsigned int i; unsigned int urlsize, stsize, usnsize, l; int s; struct sockaddr_un addr; s = socket(AF_UNIX, SOCK_STREAM, 0); if(s < 0) { /*syslog(LOG_ERR, "socket(unix): %m");*/ perror("socket(unix)"); return NULL; } addr.sun_family = AF_UNIX; strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path)); /* TODO : check if we need to handle the EINTR */ if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) { /*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/ close(s); return NULL; } stsize = strlen(devtype); buffer[0] = 1; /* request type 1 : request devices/services by type */ p = buffer + 1; l = stsize; CODELENGTH(l, p); if(p + stsize > buffer + sizeof(buffer)) { /* devtype is too long ! */ close(s); return NULL; } memcpy(p, devtype, stsize); p += stsize; if(write(s, buffer, p - buffer) < 0) { /*syslog(LOG_ERR, "write(): %m");*/ perror("minissdpc.c: write()"); close(s); return NULL; } n = read(s, buffer, sizeof(buffer)); if(n<=0) { perror("minissdpc.c: read()"); close(s); return NULL; } p = buffer + 1; for(i = 0; i < buffer[0]; i++) { if(p+2>=buffer+sizeof(buffer)) break; DECODELENGTH(urlsize, p); if(p+urlsize+2>=buffer+sizeof(buffer)) break; url = p; p += urlsize; DECODELENGTH(stsize, p); if(p+stsize+2>=buffer+sizeof(buffer)) break; tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize); tmp->pNext = devlist; tmp->descURL = tmp->buffer; tmp->st = tmp->buffer + 1 + urlsize; memcpy(tmp->buffer, url, urlsize); tmp->buffer[urlsize] = '\0'; memcpy(tmp->buffer + urlsize + 1, p, stsize); p += stsize; tmp->buffer[urlsize+1+stsize] = '\0'; devlist = tmp; /* added for compatibility with recent versions of MiniSSDPd * >= 2007/12/19 */ DECODELENGTH(usnsize, p); p += usnsize; if(p>buffer + sizeof(buffer)) break; } close(s); return devlist; } miniupnpc-1.9.20140610/man3/miniupnpc.3010064400017500000024000000053241210614426300163720ustar00nanardstaff.TH MINIUPNPC 3 .SH NAME miniupnpc \- UPnP client library .SH SYNOPSIS .SH DESCRIPTION The miniupnpc library implement the UPnP protocol defined to dialog with Internet Gateway Devices. It also has the ability to use data gathered by minissdpd(1) about UPnP devices up on the network in order to skip the long UPnP device discovery process. .PP At first, upnpDiscover(3) has to be used to discover UPnP IGD present on the network. Then UPNP_GetValidIGD(3) to select the right one. Alternatively, UPNP_GetIGDFromUrl(3) could be used to bypass discovery process if the root description url of the device to use is known. Then all the UPNP_* functions can be used, such as UPNP_GetConnectionTypeInfo(3), UPNP_AddPortMapping(3), etc... .SH "HEADER FILES" .IP miniupnpc.h That's the main header file for the miniupnpc library API. It contains all the functions and structures related to device discovery. .IP upnpcommands.h This header file contain the UPnP IGD methods that are accessible through the miniupnpc API. The name of the C functions are matching the UPnP methods names. ie: GetGenericPortMappingEntry is UPNP_GetGenericPortMappingEntry. .SH "API FUNCTIONS" .IP "struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport, int ipv6, int * error);" execute the discovery process. delay (in millisecond) is the maximum time for waiting any device response. If available, device list will be obtained from MiniSSDPd. Default path for minissdpd socket will be used if minissdpdsock argument is NULL. If multicastif is not NULL, it will be used instead of the default multicast interface for sending SSDP discover packets. If sameport is not null, SSDP packets will be sent from the source port 1900 (same as destination port) otherwise system assign a source port. If ipv6 is not 0, IPv6 is used instead of IPv4 for the discovery process. .IP "void freeUPNPDevlist(struct UPNPDev * devlist);" free the list returned by upnpDiscover(). .IP "int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen);" browse the list of device returned by upnpDiscover(), find a live UPnP internet gateway device and fill structures passed as arguments with data used for UPNP methods invokation. .IP "int UPNP_GetIGDFromUrl(const char * rootdescurl, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen);" permit to bypass the upnpDiscover() call if the xml root description URL of the UPnP IGD is known. Fill structures passed as arguments with data used for UPNP methods invokation. .IP "void GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, const char *);" .IP "void FreeUPNPUrls(struct UPNPUrls *);" .SH "SEE ALSO" minissdpd(1) .SH BUGS miniupnpc-1.9.20140610/upnperrors.h010064400017500000024000000011411234555371500160420ustar00nanardstaff/* $Id: upnperrors.h,v 1.5 2014/06/10 09:41:48 nanard Exp $ */ /* (c) 2007 Thomas Bernard * All rights reserved. * MiniUPnP Project. * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * This software is subjet to the conditions detailed in the * provided LICENCE file. */ #ifndef UPNPERRORS_H_INCLUDED #define UPNPERRORS_H_INCLUDED #include "declspec.h" #ifdef __cplusplus extern "C" { #endif /* strupnperror() * Return a string description of the UPnP error code * or NULL for undefinded errors */ MINIUPNP_LIBSPEC const char * strupnperror(int err); #ifdef __cplusplus } #endif #endif miniupnpc-1.9.20140610/upnperrors.c010064400017500000024000000041401234555371500160370ustar00nanardstaff/* $Id: upnperrors.c,v 1.8 2014/06/10 09:41:48 nanard Exp $ */ /* Project : miniupnp * Author : Thomas BERNARD * copyright (c) 2007 Thomas Bernard * All Right reserved. * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * This software is subjet to the conditions detailed in the * provided LICENCE file. */ #include #include "upnperrors.h" #include "upnpcommands.h" #include "miniupnpc.h" const char * strupnperror(int err) { const char * s = NULL; switch(err) { case UPNPCOMMAND_SUCCESS: s = "Success"; break; case UPNPCOMMAND_UNKNOWN_ERROR: s = "Miniupnpc Unknown Error"; break; case UPNPCOMMAND_INVALID_ARGS: s = "Miniupnpc Invalid Arguments"; break; case UPNPCOMMAND_INVALID_RESPONSE: s = "Miniupnpc Invalid response"; break; case UPNPDISCOVER_SOCKET_ERROR: s = "Miniupnpc Socket error"; break; case UPNPDISCOVER_MEMORY_ERROR: s = "Miniupnpc Memory allocation error"; break; case 401: s = "Invalid Action"; break; case 402: s = "Invalid Args"; break; case 501: s = "Action Failed"; break; case 606: s = "Action not authorized"; break; case 701: s = "PinholeSpaceExhausted"; break; case 702: s = "FirewallDisabled"; break; case 703: s = "InboundPinholeNotAllowed"; break; case 704: s = "NoSuchEntry"; break; case 705: s = "ProtocolNotSupported"; break; case 706: s = "InternalPortWildcardingNotAllowed"; break; case 707: s = "ProtocolWildcardingNotAllowed"; break; case 708: s = "WildcardNotPermittedInSrcIP"; break; case 709: s = "NoPacketSent"; break; case 713: s = "SpecifiedArrayIndexInvalid"; break; case 714: s = "NoSuchEntryInArray"; break; case 715: s = "WildCardNotPermittedInSrcIP"; break; case 716: s = "WildCardNotPermittedInExtPort"; break; case 718: s = "ConflictInMappingEntry"; break; case 724: s = "SamePortValuesRequired"; break; case 725: s = "OnlyPermanentLeasesSupported"; break; case 726: s = "RemoteHostOnlySupportsWildcard"; break; case 727: s = "ExternalPortOnlySupportsWildcard"; break; default: s = "UnknownError"; break; } return s; } miniupnpc-1.9.20140610/testigddescparse.c010064400017500000024000000030471177712566400171700ustar00nanardstaff/* $Id: testigddescparse.c,v 1.4 2012/06/28 18:52:12 nanard Exp $ */ /* Project : miniupnp * http://miniupnp.free.fr/ * Author : Thomas Bernard * Copyright (c) 2008-2012 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ #include #include #include #include "igd_desc_parse.h" #include "minixml.h" #include "miniupnpc.h" int test_igd_desc_parse(char * buffer, int len) { struct IGDdatas igd; struct xmlparser parser; struct UPNPUrls urls; memset(&igd, 0, sizeof(struct IGDdatas)); memset(&parser, 0, sizeof(struct xmlparser)); parser.xmlstart = buffer; parser.xmlsize = len; parser.data = &igd; parser.starteltfunc = IGDstartelt; parser.endeltfunc = IGDendelt; parser.datafunc = IGDdata; parsexml(&parser); printIGD(&igd); GetUPNPUrls(&urls, &igd, "http://fake/desc/url/file.xml", 0); printf("ipcondescURL='%s'\n", urls.ipcondescURL); printf("controlURL='%s'\n", urls.controlURL); printf("controlURL_CIF='%s'\n", urls.controlURL_CIF); FreeUPNPUrls(&urls); return 0; } int main(int argc, char * * argv) { FILE * f; char * buffer; int len; int r = 0; if(argc<2) { fprintf(stderr, "Usage: %s file.xml\n", argv[0]); return 1; } f = fopen(argv[1], "r"); if(!f) { fprintf(stderr, "Cannot open %s for reading.\n", argv[1]); return 1; } fseek(f, 0, SEEK_END); len = ftell(f); fseek(f, 0, SEEK_SET); buffer = malloc(len); fread(buffer, 1, len, f); fclose(f); r = test_igd_desc_parse(buffer, len); free(buffer); return r; } miniupnpc-1.9.20140610/testupnpigd.py010075500017500000024000000044741107407761000164020ustar00nanardstaff#! /usr/bin/python # $Id: testupnpigd.py,v 1.4 2008/10/11 10:27:20 nanard Exp $ # MiniUPnP project # Author : Thomas Bernard # This Sample code is public domain. # website : http://miniupnp.tuxfamily.org/ # import the python miniupnpc module import miniupnpc import socket import BaseHTTPServer # function definition def list_redirections(): i = 0 while True: p = u.getgenericportmapping(i) if p==None: break print i, p i = i + 1 #define the handler class for HTTP connections class handler_class(BaseHTTPServer.BaseHTTPRequestHandler): def do_GET(self): self.send_response(200) self.end_headers() self.wfile.write("OK MON GARS") # create the object u = miniupnpc.UPnP() #print 'inital(default) values :' #print ' discoverdelay', u.discoverdelay #print ' lanaddr', u.lanaddr #print ' multicastif', u.multicastif #print ' minissdpdsocket', u.minissdpdsocket u.discoverdelay = 200; try: print 'Discovering... delay=%ums' % u.discoverdelay ndevices = u.discover() print ndevices, 'device(s) detected' # select an igd u.selectigd() # display information about the IGD and the internet connection print 'local ip address :', u.lanaddr externalipaddress = u.externalipaddress() print 'external ip address :', externalipaddress print u.statusinfo(), u.connectiontype() #instanciate a HTTPd object. The port is assigned by the system. httpd = BaseHTTPServer.HTTPServer((u.lanaddr, 0), handler_class) eport = httpd.server_port # find a free port for the redirection r = u.getspecificportmapping(eport, 'TCP') while r != None and eport < 65536: eport = eport + 1 r = u.getspecificportmapping(eport, 'TCP') print 'trying to redirect %s port %u TCP => %s port %u TCP' % (externalipaddress, eport, u.lanaddr, httpd.server_port) b = u.addportmapping(eport, 'TCP', u.lanaddr, httpd.server_port, 'UPnP IGD Tester port %u' % eport, '') if b: print 'Success. Now waiting for some HTTP request on http://%s:%u' % (externalipaddress ,eport) try: httpd.handle_request() httpd.server_close() except KeyboardInterrupt, details: print "CTRL-C exception!", details b = u.deleteportmapping(eport, 'TCP') if b: print 'Successfully deleted port mapping' else: print 'Failed to remove port mapping' else: print 'Failed' httpd.server_close() except Exception, e: print 'Exception :', e miniupnpc-1.9.20140610/miniupnpc.def010064400017500000024000000016361227272130100161300ustar00nanardstaffLIBRARY ; miniupnpc library miniupnpc EXPORTS ; miniupnpc upnpDiscover freeUPNPDevlist parserootdesc UPNP_GetValidIGD UPNP_GetIGDFromUrl GetUPNPUrls FreeUPNPUrls ; miniwget miniwget miniwget_getaddr ; upnpcommands UPNP_GetTotalBytesSent UPNP_GetTotalBytesReceived UPNP_GetTotalPacketsSent UPNP_GetTotalPacketsReceived UPNP_GetStatusInfo UPNP_GetConnectionTypeInfo UPNP_GetExternalIPAddress UPNP_GetLinkLayerMaxBitRates UPNP_AddPortMapping UPNP_DeletePortMapping UPNP_GetPortMappingNumberOfEntries UPNP_GetSpecificPortMappingEntry UPNP_GetGenericPortMappingEntry UPNP_GetListOfPortMappings UPNP_AddPinhole UPNP_CheckPinholeWorking UPNP_UpdatePinhole UPNP_GetPinholePackets UPNP_DeletePinhole UPNP_GetFirewallStatus UPNP_GetOutboundPinholeTimeout ; upnperrors strupnperror ; portlistingparse ParsePortListing FreePortListing miniupnpc-1.9.20140610/codelength.h010064400017500000024000000021251203340733500157300ustar00nanardstaff/* $Id: codelength.h,v 1.4 2012/09/27 15:40:29 nanard Exp $ */ /* Project : miniupnp * Author : Thomas BERNARD * copyright (c) 2005-2011 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENCE file. */ #ifndef CODELENGTH_H_INCLUDED #define CODELENGTH_H_INCLUDED /* Encode length by using 7bit per Byte : * Most significant bit of each byte specifies that the * following byte is part of the code */ #define DECODELENGTH(n, p) n = 0; \ do { n = (n << 7) | (*p & 0x7f); } \ while((*(p++)&0x80) && (n<(1<<25))); #define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \ n = 0; \ do { \ if((p) >= (p_limit)) break; \ n = (n << 7) | (*(p) & 0x7f); \ } while((*((p)++)&0x80) && (n<(1<<25))); #define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \ if(n>=2097152) *(p++) = (n >> 21) | 0x80; \ if(n>=16384) *(p++) = (n >> 14) | 0x80; \ if(n>=128) *(p++) = (n >> 7) | 0x80; \ *(p++) = n & 0x7f; #endif miniupnpc-1.9.20140610/miniupnpcstrings.h.in010064400017500000024000000007571210144722100176400ustar00nanardstaff/* $Id: miniupnpcstrings.h.in,v 1.5 2012/10/16 16:48:26 nanard Exp $ */ /* Project: miniupnp * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author: Thomas Bernard * Copyright (c) 2005-2011 Thomas Bernard * This software is subjects to the conditions detailed * in the LICENCE file provided within this distribution */ #ifndef MINIUPNPCSTRINGS_H_INCLUDED #define MINIUPNPCSTRINGS_H_INCLUDED #define OS_STRING "OS/version" #define MINIUPNPC_VERSION_STRING "version" #endif miniupnpc-1.9.20140610/updateminiupnpcstrings.sh010075500017500000024000000027201152033016000206110ustar00nanardstaff#! /bin/sh # $Id: updateminiupnpcstrings.sh,v 1.7 2011/01/04 11:41:53 nanard Exp $ # project miniupnp : http://miniupnp.free.fr/ # (c) 2009 Thomas Bernard FILE=miniupnpcstrings.h TMPFILE=miniupnpcstrings.h.tmp TEMPLATE_FILE=${FILE}.in # detecting the OS name and version OS_NAME=`uname -s` OS_VERSION=`uname -r` if [ -f /etc/debian_version ]; then OS_NAME=Debian OS_VERSION=`cat /etc/debian_version` fi # use lsb_release (Linux Standard Base) when available LSB_RELEASE=`which lsb_release` if [ 0 -eq $? -a -x "${LSB_RELEASE}" ]; then OS_NAME=`${LSB_RELEASE} -i -s` OS_VERSION=`${LSB_RELEASE} -r -s` case $OS_NAME in Debian) #OS_VERSION=`${LSB_RELEASE} -c -s` ;; Ubuntu) #OS_VERSION=`${LSB_RELEASE} -c -s` ;; esac fi # on AmigaOS 3, uname -r returns "unknown", so we use uname -v if [ "$OS_NAME" = "AmigaOS" ]; then if [ "$OS_VERSION" = "unknown" ]; then OS_VERSION=`uname -v` fi fi echo "Detected OS [$OS_NAME] version [$OS_VERSION]" MINIUPNPC_VERSION=`cat VERSION` echo "MiniUPnPc version [${MINIUPNPC_VERSION}]" EXPR="s|OS_STRING \".*\"|OS_STRING \"${OS_NAME}/${OS_VERSION}\"|" #echo $EXPR test -f ${FILE}.in echo "setting OS_STRING macro value to ${OS_NAME}/${OS_VERSION} in $FILE." sed -e "$EXPR" < $TEMPLATE_FILE > $TMPFILE EXPR="s|MINIUPNPC_VERSION_STRING \".*\"|MINIUPNPC_VERSION_STRING \"${MINIUPNPC_VERSION}\"|" echo "setting MINIUPNPC_VERSION_STRING macro value to ${MINIUPNPC_VERSION} in $FILE." sed -e "$EXPR" < $TMPFILE > $FILE rm $TMPFILE miniupnpc-1.9.20140610/VERSION010064400017500000024000000000041227272130000145010ustar00nanardstaff1.9 miniupnpc-1.9.20140610/testminiwget.c010064400017500000024000000025751177217435200163540ustar00nanardstaff/* $Id: testminiwget.c,v 1.4 2012/06/23 22:35:59 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2005-2012 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ #include #include #include "miniwget.h" /** * This program uses the miniwget / miniwget_getaddr function * from miniwget.c in order to retreive a web ressource using * a GET HTTP method, and store it in a file. */ int main(int argc, char * * argv) { void * data; int size, writtensize; FILE *f; char addr[64]; if(argc < 3) { fprintf(stderr, "Usage:\t%s url file\n", argv[0]); fprintf(stderr, "Example:\t%s http://www.google.com/ out.html\n", argv[0]); return 1; } data = miniwget_getaddr(argv[1], &size, addr, sizeof(addr), 0); if(!data) { fprintf(stderr, "Error fetching %s\n", argv[1]); return 1; } printf("local address : %s\n", addr); printf("got %d bytes\n", size); f = fopen(argv[2], "wb"); if(!f) { fprintf(stderr, "Cannot open file %s for writing\n", argv[2]); free(data); return 1; } writtensize = fwrite(data, 1, size, f); if(writtensize != size) { fprintf(stderr, "Could only write %d bytes out of %d to %s\n", writtensize, size, argv[2]); } else { printf("%d bytes written to %s\n", writtensize, argv[2]); } fclose(f); free(data); return 0; } miniupnpc-1.9.20140610/msvc/miniupnpc.sln010064400017500000024000000027031131024352600171320ustar00nanardstaff Microsoft Visual Studio Solution File, Format Version 10.00 # Visual C++ Express 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniupnpc", "miniupnpc.vcproj", "{D28CE435-CB33-4BAE-8A52-C6EF915956F5}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "upnpc-static", "upnpc-static.vcproj", "{469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}" ProjectSection(ProjectDependencies) = postProject {D28CE435-CB33-4BAE-8A52-C6EF915956F5} = {D28CE435-CB33-4BAE-8A52-C6EF915956F5} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Debug|Win32.ActiveCfg = Debug|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Debug|Win32.Build.0 = Debug|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Release|Win32.ActiveCfg = Release|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Release|Win32.Build.0 = Release|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Debug|Win32.ActiveCfg = Debug|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Debug|Win32.Build.0 = Debug|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Release|Win32.ActiveCfg = Release|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal miniupnpc-1.9.20140610/msvc/miniupnpc.vcproj010064400017500000024000000115631234555371500176620ustar00nanardstaff miniupnpc-1.9.20140610/msvc/upnpc-static.vcproj010064400017500000024000000076631234555371500203000ustar00nanardstaff miniupnpc-1.9.20140610/wingenminiupnpcstrings.c010064400017500000024000000052551172522177000204460ustar00nanardstaff/* $Id: wingenminiupnpcstrings.c,v 1.3 2012/03/05 19:42:48 nanard Exp $ */ /* Project: miniupnp * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author: Thomas Bernard * Copyright (c) 2005-2009 Thomas Bernard * This software is subjects to the conditions detailed * in the LICENSE file provided within this distribution */ #include #include /* This program display the Windows version and is used to * generate the miniupnpcstrings.h * wingenminiupnpcstrings miniupnpcstrings.h.in miniupnpcstrings.h */ int main(int argc, char * * argv) { char buffer[256]; OSVERSIONINFO osvi; FILE * fin; FILE * fout; int n; char miniupnpcVersion[32]; /* dwMajorVersion : The major version number of the operating system. For more information, see Remarks. dwMinorVersion : The minor version number of the operating system. For more information, see Remarks. dwBuildNumber : The build number of the operating system. dwPlatformId The operating system platform. This member can be the following value. szCSDVersion A null-terminated string, such as "Service Pack 3", that indicates the latest Service Pack installed on the system. If no Service Pack has been installed, the string is empty. */ ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osvi); printf("Windows %lu.%lu Build %lu %s\n", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber, (const char *)&(osvi.szCSDVersion)); fin = fopen("VERSION", "r"); fgets(miniupnpcVersion, sizeof(miniupnpcVersion), fin); fclose(fin); for(n = 0; n < sizeof(miniupnpcVersion); n++) { if(miniupnpcVersion[n] < ' ') miniupnpcVersion[n] = '\0'; } printf("MiniUPnPc version %s\n", miniupnpcVersion); if(argc >= 3) { fin = fopen(argv[1], "r"); if(!fin) { fprintf(stderr, "Cannot open %s for reading.\n", argv[1]); return 1; } fout = fopen(argv[2], "w"); if(!fout) { fprintf(stderr, "Cannot open %s for writing.\n", argv[2]); return 1; } n = 0; while(fgets(buffer, sizeof(buffer), fin)) { if(0 == memcmp(buffer, "#define OS_STRING \"OS/version\"", 30)) { sprintf(buffer, "#define OS_STRING \"MSWindows/%ld.%ld.%ld\"\n", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber); } else if(0 == memcmp(buffer, "#define MINIUPNPC_VERSION_STRING \"version\"", 42)) { sprintf(buffer, "#define MINIUPNPC_VERSION_STRING \"%s\"\n", miniupnpcVersion); } /*fputs(buffer, stdout);*/ fputs(buffer, fout); n++; } fclose(fin); fclose(fout); printf("%d lines written to %s.\n", n, argv[2]); } return 0; } miniupnpc-1.9.20140610/connecthostport.c010064400017500000024000000151541231626121100170440ustar00nanardstaff/* $Id: connecthostport.c,v 1.13 2014/03/31 12:36:36 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2010-2014 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ /* use getaddrinfo() or gethostbyname() * uncomment the following line in order to use gethostbyname() */ #ifdef NO_GETADDRINFO #define USE_GETHOSTBYNAME #endif #include #include #ifdef _WIN32 #include #include #include #define MAXHOSTNAMELEN 64 #define snprintf _snprintf #define herror #define socklen_t int #else /* #ifdef _WIN32 */ #include #include #include #include #define closesocket close #include #include /* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions * during the connect() call */ #define MINIUPNPC_IGNORE_EINTR #ifndef USE_GETHOSTBYNAME #include #include #include #endif /* #ifndef USE_GETHOSTBYNAME */ #endif /* #else _WIN32 */ /* definition of PRINT_SOCKET_ERROR */ #ifdef _WIN32 #define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); #else #define PRINT_SOCKET_ERROR(x) perror(x) #endif #if defined(__amigaos__) || defined(__amigaos4__) #define herror(A) printf("%s\n", A) #endif #include "connecthostport.h" #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif /* connecthostport() * return a socket connected (TCP) to the host and port * or -1 in case of error */ int connecthostport(const char * host, unsigned short port, unsigned int scope_id) { int s, n; #ifdef USE_GETHOSTBYNAME struct sockaddr_in dest; struct hostent *hp; #else /* #ifdef USE_GETHOSTBYNAME */ char tmp_host[MAXHOSTNAMELEN+1]; char port_str[8]; struct addrinfo *ai, *p; struct addrinfo hints; #endif /* #ifdef USE_GETHOSTBYNAME */ #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT struct timeval timeout; #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ #ifdef USE_GETHOSTBYNAME hp = gethostbyname(host); if(hp == NULL) { herror(host); return -1; } memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr)); memset(dest.sin_zero, 0, sizeof(dest.sin_zero)); s = socket(PF_INET, SOCK_STREAM, 0); if(s < 0) { PRINT_SOCKET_ERROR("socket"); return -1; } #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT /* setting a 3 seconds timeout for the connect() call */ timeout.tv_sec = 3; timeout.tv_usec = 0; if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } timeout.tv_sec = 3; timeout.tv_usec = 0; if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ dest.sin_family = AF_INET; dest.sin_port = htons(port); n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in)); #ifdef MINIUPNPC_IGNORE_EINTR /* EINTR The system call was interrupted by a signal that was caught * EINPROGRESS The socket is nonblocking and the connection cannot * be completed immediately. */ while(n < 0 && (errno == EINTR || errno = EINPROGRESS)) { socklen_t len; fd_set wset; int err; FD_ZERO(&wset); FD_SET(s, &wset); if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) continue; /*len = 0;*/ /*n = getpeername(s, NULL, &len);*/ len = sizeof(err); if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { PRINT_SOCKET_ERROR("getsockopt"); closesocket(s); return -1; } if(err != 0) { errno = err; n = -1; } } #endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ if(n<0) { PRINT_SOCKET_ERROR("connect"); closesocket(s); return -1; } #else /* #ifdef USE_GETHOSTBYNAME */ /* use getaddrinfo() instead of gethostbyname() */ memset(&hints, 0, sizeof(hints)); /* hints.ai_flags = AI_ADDRCONFIG; */ #ifdef AI_NUMERICSERV hints.ai_flags = AI_NUMERICSERV; #endif hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */ /* hints.ai_protocol = IPPROTO_TCP; */ snprintf(port_str, sizeof(port_str), "%hu", port); if(host[0] == '[') { /* literal ip v6 address */ int i, j; for(i = 0, j = 1; host[j] && (host[j] != ']') && i < MAXHOSTNAMELEN; i++, j++) { tmp_host[i] = host[j]; if(0 == memcmp(host+j, "%25", 3)) /* %25 is just url encoding for '%' */ j+=2; /* skip "25" */ } tmp_host[i] = '\0'; } else { strncpy(tmp_host, host, MAXHOSTNAMELEN); } tmp_host[MAXHOSTNAMELEN] = '\0'; n = getaddrinfo(tmp_host, port_str, &hints, &ai); if(n != 0) { #ifdef _WIN32 fprintf(stderr, "getaddrinfo() error : %d\n", n); #else fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n)); #endif return -1; } s = -1; for(p = ai; p; p = p->ai_next) { s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if(s < 0) continue; if(p->ai_addr->sa_family == AF_INET6 && scope_id > 0) { struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *)p->ai_addr; addr6->sin6_scope_id = scope_id; } #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT /* setting a 3 seconds timeout for the connect() call */ timeout.tv_sec = 3; timeout.tv_usec = 0; if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } timeout.tv_sec = 3; timeout.tv_usec = 0; if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ n = connect(s, p->ai_addr, p->ai_addrlen); #ifdef MINIUPNPC_IGNORE_EINTR /* EINTR The system call was interrupted by a signal that was caught * EINPROGRESS The socket is nonblocking and the connection cannot * be completed immediately. */ while(n < 0 && (errno == EINTR || errno == EINPROGRESS)) { socklen_t len; fd_set wset; int err; FD_ZERO(&wset); FD_SET(s, &wset); if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) continue; /*len = 0;*/ /*n = getpeername(s, NULL, &len);*/ len = sizeof(err); if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { PRINT_SOCKET_ERROR("getsockopt"); closesocket(s); freeaddrinfo(ai); return -1; } if(err != 0) { errno = err; n = -1; } } #endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ if(n < 0) { closesocket(s); continue; } else { break; } } freeaddrinfo(ai); if(s < 0) { PRINT_SOCKET_ERROR("socket"); return -1; } if(n < 0) { PRINT_SOCKET_ERROR("connect"); return -1; } #endif /* #ifdef USE_GETHOSTBYNAME */ return s; } miniupnpc-1.9.20140610/connecthostport.h010064400017500000024000000011171203340733500170500ustar00nanardstaff/* $Id: connecthostport.h,v 1.3 2012/09/27 15:42:10 nanard Exp $ */ /* Project: miniupnp * http://miniupnp.free.fr/ * Author: Thomas Bernard * Copyright (c) 2010-2012 Thomas Bernard * This software is subjects to the conditions detailed * in the LICENCE file provided within this distribution */ #ifndef CONNECTHOSTPORT_H_INCLUDED #define CONNECTHOSTPORT_H_INCLUDED /* connecthostport() * return a socket connected (TCP) to the host and port * or -1 in case of error */ int connecthostport(const char * host, unsigned short port, unsigned int scope_id); #endif miniupnpc-1.9.20140610/java/JavaBridgeTest.java010064400017500000024000000114551227272130300200720ustar00nanardstaffimport java.nio.ByteBuffer; import java.nio.IntBuffer; import fr.free.miniupnp.*; /** * * @author syuu */ public class JavaBridgeTest { public static void main(String[] args) { int UPNP_DELAY = 2000; MiniupnpcLibrary miniupnpc = MiniupnpcLibrary.INSTANCE; UPNPDev devlist = null; UPNPUrls urls = new UPNPUrls(); IGDdatas data = new IGDdatas(); ByteBuffer lanaddr = ByteBuffer.allocate(16); ByteBuffer intClient = ByteBuffer.allocate(16); ByteBuffer intPort = ByteBuffer.allocate(6); ByteBuffer desc = ByteBuffer.allocate(80); ByteBuffer enabled = ByteBuffer.allocate(4); ByteBuffer leaseDuration = ByteBuffer.allocate(16); int ret; int i; if(args.length < 2) { System.err.println("Usage : java [...] JavaBridgeTest port protocol"); System.out.println(" port is numeric, protocol is TCP or UDP"); return; } devlist = miniupnpc.upnpDiscover(UPNP_DELAY, (String) null, (String) null, 0, 0, IntBuffer.allocate(1)); if (devlist != null) { System.out.println("List of UPNP devices found on the network :"); for (UPNPDev device = devlist; device != null; device = device.pNext) { System.out.println("desc: " + device.descURL.getString(0) + " st: " + device.st.getString(0)); } if ((i = miniupnpc.UPNP_GetValidIGD(devlist, urls, data, lanaddr, 16)) != 0) { switch (i) { case 1: System.out.println("Found valid IGD : " + urls.controlURL.getString(0)); break; case 2: System.out.println("Found a (not connected?) IGD : " + urls.controlURL.getString(0)); System.out.println("Trying to continue anyway"); break; case 3: System.out.println("UPnP device found. Is it an IGD ? : " + urls.controlURL.getString(0)); System.out.println("Trying to continue anyway"); break; default: System.out.println("Found device (igd ?) : " + urls.controlURL.getString(0)); System.out.println("Trying to continue anyway"); } System.out.println("Local LAN ip address : " + new String(lanaddr.array())); ByteBuffer externalAddress = ByteBuffer.allocate(16); miniupnpc.UPNP_GetExternalIPAddress(urls.controlURL.getString(0), new String(data.first.servicetype), externalAddress); System.out.println("ExternalIPAddress = " + new String(externalAddress.array())); ret = miniupnpc.UPNP_AddPortMapping( urls.controlURL.getString(0), // controlURL new String(data.first.servicetype), // servicetype args[0], // external Port args[0], // internal Port new String(lanaddr.array()), // internal client "added via miniupnpc/JAVA !", // description args[1], // protocol UDP or TCP null, // remote host (useless) "0"); // leaseDuration if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS) System.out.println("AddPortMapping() failed with code " + ret); ret = miniupnpc.UPNP_GetSpecificPortMappingEntry( urls.controlURL.getString(0), new String(data.first.servicetype), args[0], args[1], null, intClient, intPort, desc, enabled, leaseDuration); if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS) System.out.println("GetSpecificPortMappingEntry() failed with code " + ret); System.out.println("InternalIP:Port = " + new String(intClient.array()) + ":" + new String(intPort.array()) + " (" + new String(desc.array()) + ")"); ret = miniupnpc.UPNP_DeletePortMapping( urls.controlURL.getString(0), new String(data.first.servicetype), args[0], args[1], null); if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS) System.out.println("DelPortMapping() failed with code " + ret); miniupnpc.FreeUPNPUrls(urls); } else { System.out.println("No valid UPNP Internet Gateway Device found."); } miniupnpc.freeUPNPDevlist(devlist); } else { System.out.println("No IGD UPnP Device found on the network !\n"); } } } miniupnpc-1.9.20140610/java/testjava.sh010075500017500000024000000002561170636161400165540ustar00nanardstaff#!/bin/bash JAVA=java JAVAC=javac CP=$(for i in *.jar; do echo -n $i:; done). $JAVAC -cp $CP JavaBridgeTest.java || exit 1 $JAVA -cp $CP JavaBridgeTest 12345 UDP || exit 1 miniupnpc-1.9.20140610/java/testjava.bat010075500017500000024000000003641210132026500166730ustar00nanardstaff@echo off set JAVA=java set JAVAC=javac REM notice the semicolon for Windows. Write once, run ... oh nevermind set CP=miniupnpc_win32.jar;. %JAVAC% -cp "%CP%" JavaBridgeTest.java || exit 1 %JAVA% -cp "%CP%" JavaBridgeTest 12345 UDP || exit 1 miniupnpc-1.9.20140610/external-ip.sh010075500017500000024000000002311142653250500162310ustar00nanardstaff#!/bin/sh # $Id: external-ip.sh,v 1.1 2010/08/05 12:57:41 nanard Exp $ # (c) 2010 Reuben Hawkins upnpc -s | grep ExternalIPAddress | sed 's/[^0-9\.]//g' miniupnpc-1.9.20140610/MANIFEST.in010064400017500000024000000001351150020330200151620ustar00nanardstaffinclude README include miniupnpcmodule.c include setup.py include *.h include libminiupnpc.a miniupnpc-1.9.20140610/portlistingparse.c010064400017500000024000000067261176112215300172320ustar00nanardstaff/* $Id: portlistingparse.c,v 1.6 2012/05/29 10:26:51 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2011 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #include #include #include "portlistingparse.h" #include "minixml.h" /* list of the elements */ static const struct { const portMappingElt code; const char * const str; } elements[] = { { PortMappingEntry, "PortMappingEntry"}, { NewRemoteHost, "NewRemoteHost"}, { NewExternalPort, "NewExternalPort"}, { NewProtocol, "NewProtocol"}, { NewInternalPort, "NewInternalPort"}, { NewInternalClient, "NewInternalClient"}, { NewEnabled, "NewEnabled"}, { NewDescription, "NewDescription"}, { NewLeaseTime, "NewLeaseTime"}, { PortMappingEltNone, NULL} }; /* Helper function */ static UNSIGNED_INTEGER atoui(const char * p, int l) { UNSIGNED_INTEGER r = 0; while(l > 0 && *p) { if(*p >= '0' && *p <= '9') r = r*10 + (*p - '0'); else break; p++; l--; } return r; } /* Start element handler */ static void startelt(void * d, const char * name, int l) { int i; struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; pdata->curelt = PortMappingEltNone; for(i = 0; elements[i].str; i++) { if(memcmp(name, elements[i].str, l) == 0) { pdata->curelt = elements[i].code; break; } } if(pdata->curelt == PortMappingEntry) { struct PortMapping * pm; pm = calloc(1, sizeof(struct PortMapping)); LIST_INSERT_HEAD( &(pdata->head), pm, entries); } } /* End element handler */ static void endelt(void * d, const char * name, int l) { struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; (void)name; (void)l; pdata->curelt = PortMappingEltNone; } /* Data handler */ static void data(void * d, const char * data, int l) { struct PortMapping * pm; struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; pm = pdata->head.lh_first; if(!pm) return; if(l > 63) l = 63; switch(pdata->curelt) { case NewRemoteHost: memcpy(pm->remoteHost, data, l); pm->remoteHost[l] = '\0'; break; case NewExternalPort: pm->externalPort = (unsigned short)atoui(data, l); break; case NewProtocol: if(l > 3) l = 3; memcpy(pm->protocol, data, l); pm->protocol[l] = '\0'; break; case NewInternalPort: pm->internalPort = (unsigned short)atoui(data, l); break; case NewInternalClient: memcpy(pm->internalClient, data, l); pm->internalClient[l] = '\0'; break; case NewEnabled: pm->enabled = (unsigned char)atoui(data, l); break; case NewDescription: memcpy(pm->description, data, l); pm->description[l] = '\0'; break; case NewLeaseTime: pm->leaseTime = atoui(data, l); break; default: break; } } /* Parse the PortMappingList XML document for IGD version 2 */ void ParsePortListing(const char * buffer, int bufsize, struct PortMappingParserData * pdata) { struct xmlparser parser; memset(pdata, 0, sizeof(struct PortMappingParserData)); LIST_INIT(&(pdata->head)); /* init xmlparser */ parser.xmlstart = buffer; parser.xmlsize = bufsize; parser.data = pdata; parser.starteltfunc = startelt; parser.endeltfunc = endelt; parser.datafunc = data; parser.attfunc = 0; parsexml(&parser); } void FreePortListing(struct PortMappingParserData * pdata) { struct PortMapping * pm; while((pm = pdata->head.lh_first) != NULL) { LIST_REMOVE(pm, entries); free(pm); } } miniupnpc-1.9.20140610/portlistingparse.h010064400017500000024000000036141234555371500172430ustar00nanardstaff/* $Id: portlistingparse.h,v 1.8 2014/06/10 09:44:18 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2011-2012 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #ifndef PORTLISTINGPARSE_H_INCLUDED #define PORTLISTINGPARSE_H_INCLUDED #include "declspec.h" /* for the definition of UNSIGNED_INTEGER */ #include "miniupnpctypes.h" #if defined(NO_SYS_QUEUE_H) || defined(_WIN32) || defined(__HAIKU__) #include "bsdqueue.h" #else #include #endif #ifdef __cplusplus extern "C" { #endif /* sample of PortMappingEntry : 202.233.2.1 2345 TCP 2345 192.168.1.137 1 dooom 345 */ typedef enum { PortMappingEltNone, PortMappingEntry, NewRemoteHost, NewExternalPort, NewProtocol, NewInternalPort, NewInternalClient, NewEnabled, NewDescription, NewLeaseTime } portMappingElt; struct PortMapping { LIST_ENTRY(PortMapping) entries; UNSIGNED_INTEGER leaseTime; unsigned short externalPort; unsigned short internalPort; char remoteHost[64]; char internalClient[64]; char description[64]; char protocol[4]; unsigned char enabled; }; struct PortMappingParserData { LIST_HEAD(portmappinglisthead, PortMapping) head; portMappingElt curelt; }; MINIUPNP_LIBSPEC void ParsePortListing(const char * buffer, int bufsize, struct PortMappingParserData * pdata); MINIUPNP_LIBSPEC void FreePortListing(struct PortMappingParserData * pdata); #ifdef __cplusplus } #endif #endif miniupnpc-1.9.20140610/miniupnpctypes.h010064400017500000024000000011421203340734000166750ustar00nanardstaff/* $Id: miniupnpctypes.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */ /* Miniupnp project : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org * Author : Thomas Bernard * Copyright (c) 2011 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided within this distribution */ #ifndef MINIUPNPCTYPES_H_INCLUDED #define MINIUPNPCTYPES_H_INCLUDED #if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) #define UNSIGNED_INTEGER unsigned long long #define STRTOUI strtoull #else #define UNSIGNED_INTEGER unsigned int #define STRTOUI strtoul #endif #endif miniupnpc-1.9.20140610/CMakeLists.txt010064400017500000024000000140351234555371200162150ustar00nanardstaffcmake_minimum_required (VERSION 2.6) project (miniupnpc C) set (MINIUPNPC_VERSION 1.9) set (MINIUPNPC_API_VERSION 10) if (NOT CMAKE_BUILD_TYPE) if (WIN32) set (DEFAULT_BUILD_TYPE MinSizeRel) else (WIN32) set (DEFAULT_BUILD_TYPE RelWithDebInfo) endif(WIN32) set (CMAKE_BUILD_TYPE ${DEFAULT_BUILD_TYPE} CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) endif() option (UPNPC_BUILD_STATIC "Build static library" TRUE) option (UPNPC_BUILD_SHARED "Build shared library" TRUE) if (NOT WIN32) option (UPNPC_BUILD_TESTS "Build test executables" TRUE) endif (NOT WIN32) option (NO_GETADDRINFO "Define NO_GETADDRINFO" FALSE) mark_as_advanced (NO_GETADDRINFO) if (NO_GETADDRINFO) add_definitions (-DNO_GETADDRINFO) endif (NO_GETADDRINFO) if (NOT WIN32) add_definitions (-DMINIUPNPC_SET_SOCKET_TIMEOUT) add_definitions (-D_BSD_SOURCE -D_POSIX_C_SOURCE=1) else (NOT WIN32) add_definitions (-D_WIN32_WINNT=0x0501) # XP or higher for getnameinfo and friends endif (NOT WIN32) if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") add_definitions (-DMACOSX -D_DARWIN_C_SOURCE) endif () # Set compiler specific build flags if (CMAKE_COMPILER_IS_GNUC) # Set our own default flags at first run. if (NOT CONFIGURED) if (NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS") set (_PIC -fPIC) endif (CMAKE_SYSTEM_NAME STREQUAL "AmigaOS") set (CMAKE_C_FLAGS "${_PIC} -Wall $ENV{CFLAGS}" # CMAKE_C_FLAGS gets appended to the other C flags CACHE STRING "Flags used by the C compiler during normal builds." FORCE) set (CMAKE_C_FLAGS_DEBUG "-g -DDDEBUG" CACHE STRING "Flags used by the C compiler during debug builds." FORCE) set (CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG" CACHE STRING "Flags used by the C compiler during release builds." FORCE) set (CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g -DNDEBUG" CACHE STRING "Flags used by the C compiler during release builds." FORCE) set (CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG" CACHE STRING "Flags used by the C compiler during release builds." FORCE) endif (NOT CONFIGURED) endif () configure_file (${CMAKE_SOURCE_DIR}/miniupnpcstrings.h.cmake ${CMAKE_BINARY_DIR}/miniupnpcstrings.h) include_directories (${CMAKE_BINARY_DIR}) set (MINIUPNPC_SOURCES igd_desc_parse.c miniupnpc.c minixml.c minisoap.c miniwget.c upnpc.c upnpcommands.c upnpreplyparse.c upnperrors.c connecthostport.c portlistingparse.c receivedata.c ) if (NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS") set (MINIUPNPC_SOURCES ${MINIUPNPC_SOURCES} minissdpc.c) endif (NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS") if (WIN32) set_source_files_properties (${MINIUPNPC_SOURCES} PROPERTIES COMPILE_DEFINITIONS MINIUPNP_STATICLIB COMPILE_DEFINITIONS MINIUPNP_EXPORTS ) endif (WIN32) if (WIN32) find_library (WINSOCK2_LIBRARY NAMES ws2_32 WS2_32 Ws2_32) find_library (IPHLPAPI_LIBRARY NAMES iphlpapi) set (LDLIBS ${WINSOCK2_LIBRARY} ${IPHLPAPI_LIBRARY} ${LDLIBS}) #elseif (CMAKE_SYSTEM_NAME STREQUAL "Solaris") # find_library (SOCKET_LIBRARY NAMES socket) # find_library (NSL_LIBRARY NAMES nsl) # find_library (RESOLV_LIBRARY NAMES resolv) # set (LDLIBS ${SOCKET_LIBRARY} ${NSL_LIBRARY} ${RESOLV_LIBRARY} ${LDLIBS}) endif (WIN32) if (NOT UPNPC_BUILD_STATIC AND NOT UPNPC_BUILD_SHARED) message (FATAL "Both shared and static libraries are disabled!") endif (NOT UPNPC_BUILD_STATIC AND NOT UPNPC_BUILD_SHARED) if (UPNPC_BUILD_STATIC) add_library (upnpc-static STATIC ${MINIUPNPC_SOURCES}) set_target_properties (upnpc-static PROPERTIES OUTPUT_NAME "miniupnpc") target_link_libraries (upnpc-static ${LDLIBS}) set (UPNPC_INSTALL_TARGETS ${UPNPC_INSTALL_TARGETS} upnpc-static) set (UPNPC_LIBRARY_TARGET upnpc-static) endif (UPNPC_BUILD_STATIC) if (UPNPC_BUILD_SHARED) add_library (upnpc-shared SHARED ${MINIUPNPC_SOURCES}) set_target_properties (upnpc-shared PROPERTIES OUTPUT_NAME "miniupnpc") set_target_properties (upnpc-shared PROPERTIES VERSION ${MINIUPNPC_VERSION}) set_target_properties (upnpc-shared PROPERTIES SOVERSION ${MINIUPNPC_API_VERSION}) target_link_libraries (upnpc-shared ${LDLIBS}) set (UPNPC_INSTALL_TARGETS ${UPNPC_INSTALL_TARGETS} upnpc-shared) set (UPNPC_LIBRARY_TARGET upnpc-shared) endif (UPNPC_BUILD_SHARED) if (UPNPC_BUILD_TESTS) add_executable (testminixml testminixml.c minixml.c igd_desc_parse.c) target_link_libraries (testminixml ${LDLIBS}) add_executable (minixmlvalid minixmlvalid.c minixml.c) target_link_libraries (minixmlvalid ${LDLIBS}) add_executable (testupnpreplyparse testupnpreplyparse.c minixml.c upnpreplyparse.c) target_link_libraries (testupnpreplyparse ${LDLIBS}) add_executable (testigddescparse testigddescparse.c igd_desc_parse.c minixml.c miniupnpc.c miniwget.c minissdpc.c upnpcommands.c upnpreplyparse.c minisoap.c connecthostport.c portlistingparse.c receivedata.c ) target_link_libraries (testigddescparse ${LDLIBS}) add_executable (testminiwget testminiwget.c miniwget.c miniupnpc.c minisoap.c upnpcommands.c minissdpc.c upnpreplyparse.c minixml.c igd_desc_parse.c connecthostport.c portlistingparse.c receivedata.c ) target_link_libraries (testminiwget ${LDLIBS}) # set (UPNPC_INSTALL_TARGETS ${UPNPC_INSTALL_TARGETS} testminixml minixmlvalid testupnpreplyparse testigddescparse testminiwget) endif (UPNPC_BUILD_TESTS) install (TARGETS ${UPNPC_INSTALL_TARGETS} RUNTIME DESTINATION bin LIBRARY DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX} ) install (FILES miniupnpc.h miniwget.h upnpcommands.h igd_desc_parse.h upnpreplyparse.h upnperrors.h miniupnpctypes.h portlistingparse.h declspec.h DESTINATION include/miniupnpc ) set (CONFIGURED YES CACHE INTERNAL "") # vim: ts=2:sw=2 miniupnpc-1.9.20140610/miniupnpcstrings.h.cmake010064400017500000024000000002621210144722100203010ustar00nanardstaff#ifndef MINIUPNPCSTRINGS_H_INCLUDED #define MINIUPNPCSTRINGS_H_INCLUDED #define OS_STRING "${CMAKE_SYSTEM_NAME}" #define MINIUPNPC_VERSION_STRING "${MINIUPNPC_VERSION}" #endif miniupnpc-1.9.20140610/receivedata.c010064400017500000024000000054471222450375700161040ustar00nanardstaff/* $Id: receivedata.c,v 1.5 2013/10/07 09:48:36 nanard Exp $ */ /* Project : miniupnp * Website : http://miniupnp.free.fr/ * Author : Thomas Bernard * Copyright (c) 2011-2012 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ #include #ifdef _WIN32 #include #include #else #include #if defined(__amigaos__) && !defined(__amigaos4__) #define socklen_t int #else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ #include #endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ #include #include #if !defined(__amigaos__) && !defined(__amigaos4__) #include #endif #include #define MINIUPNPC_IGNORE_EINTR #endif #ifdef _WIN32 #define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); #else #define PRINT_SOCKET_ERROR(x) perror(x) #endif #include "receivedata.h" int receivedata(int socket, char * data, int length, int timeout, unsigned int * scope_id) { #if MINIUPNPC_GET_SRC_ADDR #ifdef DEBUG /* to shut up valgrind about uninit value */ struct sockaddr_storage src_addr = {0}; #else struct sockaddr_storage src_addr; #endif socklen_t src_addr_len = sizeof(src_addr); #endif int n; #if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) /* using poll */ struct pollfd fds[1]; /* for the poll */ #ifdef MINIUPNPC_IGNORE_EINTR do { #endif fds[0].fd = socket; fds[0].events = POLLIN; n = poll(fds, 1, timeout); #ifdef MINIUPNPC_IGNORE_EINTR } while(n < 0 && errno == EINTR); #endif if(n < 0) { PRINT_SOCKET_ERROR("poll"); return -1; } else if(n == 0) { /* timeout */ return 0; } #else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ /* using select under _WIN32 and amigaos */ fd_set socketSet; TIMEVAL timeval; FD_ZERO(&socketSet); FD_SET(socket, &socketSet); timeval.tv_sec = timeout / 1000; timeval.tv_usec = (timeout % 1000) * 1000; n = select(FD_SETSIZE, &socketSet, NULL, NULL, &timeval); if(n < 0) { PRINT_SOCKET_ERROR("select"); return -1; } else if(n == 0) { return 0; } #endif #if MINIUPNPC_GET_SRC_ADDR n = recvfrom(socket, data, length, 0, (struct sockaddr *)&src_addr, &src_addr_len); #else n = recv(socket, data, length, 0); #endif if(n<0) { PRINT_SOCKET_ERROR("recv"); } #if MINIUPNPC_GET_SRC_ADDR if (src_addr.ss_family == AF_INET6) { const struct sockaddr_in6 * src_addr6 = (struct sockaddr_in6 *)&src_addr; #ifdef DEBUG printf("scope_id=%u\n", src_addr6->sin6_scope_id); #endif if(scope_id) *scope_id = src_addr6->sin6_scope_id; } #endif return n; } miniupnpc-1.9.20140610/receivedata.h010064400017500000024000000013101203340734000160570ustar00nanardstaff/* $Id: receivedata.h,v 1.4 2012/09/27 15:42:10 nanard Exp $ */ /* Project: miniupnp * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author: Thomas Bernard * Copyright (c) 2011-2012 Thomas Bernard * This software is subjects to the conditions detailed * in the LICENCE file provided within this distribution */ #ifndef RECEIVEDATA_H_INCLUDED #define RECEIVEDATA_H_INCLUDED /* Reads data from the specified socket. * Returns the number of bytes read if successful, zero if no bytes were * read or if we timed out. Returns negative if there was an error. */ int receivedata(int socket, char * data, int length, int timeout, unsigned int * scope_id); #endif miniupnpc-1.9.20140610/minihttptestserver.c010064400017500000024000000347301231655315400176060ustar00nanardstaff/* $Id: minihttptestserver.c,v 1.16 2014/04/01 15:08:28 nanard Exp $ */ /* Project : miniUPnP * Author : Thomas Bernard * Copyright (c) 2011-2014 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ #include #include #include #include #include #include #include #include #include #include #include #include #define CRAP_LENGTH (2048) volatile sig_atomic_t quit = 0; volatile sig_atomic_t child_to_wait_for = 0; /** * signal handler for SIGCHLD (child status has changed) */ void handle_signal_chld(int sig) { (void)sig; /* printf("handle_signal_chld(%d)\n", sig); */ ++child_to_wait_for; } /** * signal handler for SIGINT (CRTL C) */ void handle_signal_int(int sig) { (void)sig; /* printf("handle_signal_int(%d)\n", sig); */ quit = 1; } /** * build a text/plain content of the specified length */ void build_content(char * p, int n) { char line_buffer[80]; int k; int i = 0; while(n > 0) { k = snprintf(line_buffer, sizeof(line_buffer), "%04d_ABCDEFGHIJKL_This_line_is_64_bytes_long_ABCDEFGHIJKL_%04d\r\n", i, i); if(k != 64) { fprintf(stderr, "snprintf() returned %d in build_content()\n", k); } ++i; if(n >= 64) { memcpy(p, line_buffer, 64); p += 64; n -= 64; } else { memcpy(p, line_buffer, n); p += n; n = 0; } } } /** * build crappy content */ void build_crap(char * p, int n) { static const char crap[] = "_CRAP_\r\n"; int i; while(n > 0) { i = sizeof(crap) - 1; if(i > n) i = n; memcpy(p, crap, i); p += i; n -= i; } } /** * build chunked response. * return a malloc'ed buffer */ char * build_chunked_response(int content_length, int * response_len) { char * response_buffer; char * content_buffer; int buffer_length; int i, n; /* allocate to have some margin */ buffer_length = 256 + content_length + (content_length >> 4); response_buffer = malloc(buffer_length); *response_len = snprintf(response_buffer, buffer_length, "HTTP/1.1 200 OK\r\n" "Content-Type: text/plain\r\n" "Transfer-Encoding: chunked\r\n" "\r\n"); /* build the content */ content_buffer = malloc(content_length); build_content(content_buffer, content_length); /* chunk it */ i = 0; while(i < content_length) { n = (rand() % 199) + 1; if(i + n > content_length) { n = content_length - i; } /* TODO : check buffer size ! */ *response_len += snprintf(response_buffer + *response_len, buffer_length - *response_len, "%x\r\n", n); memcpy(response_buffer + *response_len, content_buffer + i, n); *response_len += n; i += n; response_buffer[(*response_len)++] = '\r'; response_buffer[(*response_len)++] = '\n'; } /* the last chunk : "0\r\n" a empty body and then * the final "\r\n" */ memcpy(response_buffer + *response_len, "0\r\n\r\n", 5); *response_len += 5; free(content_buffer); printf("resp_length=%d buffer_length=%d content_length=%d\n", *response_len, buffer_length, content_length); return response_buffer; } /* favicon.ico generator */ #ifdef OLD_HEADER #define FAVICON_LENGTH (6 + 16 + 12 + 8 + 32 * 4) #else #define FAVICON_LENGTH (6 + 16 + 40 + 8 + 32 * 4) #endif void build_favicon_content(char * p, int n) { int i; if(n < FAVICON_LENGTH) return; /* header : 6 bytes */ *p++ = 0; *p++ = 0; *p++ = 1; /* type : ICO */ *p++ = 0; *p++ = 1; /* number of images in file */ *p++ = 0; /* image directory (1 entry) : 16 bytes */ *p++ = 16; /* width */ *p++ = 16; /* height */ *p++ = 2; /* number of colors in the palette. 0 = no palette */ *p++ = 0; /* reserved */ *p++ = 1; /* color planes */ *p++ = 0; /* " */ *p++ = 1; /* bpp */ *p++ = 0; /* " */ #ifdef OLD_HEADER *p++ = 12 + 8 + 32 * 4; /* bmp size */ #else *p++ = 40 + 8 + 32 * 4; /* bmp size */ #endif *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 6 + 16; /* bmp offset */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 0; /* " */ /* BMP */ #ifdef OLD_HEADER /* BITMAPCOREHEADER */ *p++ = 12; /* size of this header */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 16; /* width */ *p++ = 0; /* " */ *p++ = 16 * 2; /* height x 2 ! */ *p++ = 0; /* " */ *p++ = 1; /* color planes */ *p++ = 0; /* " */ *p++ = 1; /* bpp */ *p++ = 0; /* " */ #else /* BITMAPINFOHEADER */ *p++ = 40; /* size of this header */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 16; /* width */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 16 * 2; /* height x 2 ! */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 1; /* color planes */ *p++ = 0; /* " */ *p++ = 1; /* bpp */ *p++ = 0; /* " */ /* compression method, image size, ppm x, ppm y */ /* colors in the palette ? */ /* important colors */ for(i = 4 * 6; i > 0; --i) *p++ = 0; #endif /* palette */ *p++ = 0; /* b */ *p++ = 0; /* g */ *p++ = 0; /* r */ *p++ = 0; /* reserved */ *p++ = 255; /* b */ *p++ = 255; /* g */ *p++ = 255; /* r */ *p++ = 0; /* reserved */ /* pixel data */ for(i = 16; i > 0; --i) { if(i & 1) { *p++ = 0125; *p++ = 0125; } else { *p++ = 0252; *p++ = 0252; } *p++ = 0; *p++ = 0; } /* Opacity MASK */ for(i = 16 * 4; i > 0; --i) { *p++ = 0; } } enum modes { MODE_INVALID, MODE_CHUNKED, MODE_ADDCRAP, MODE_NORMAL, MODE_FAVICON }; const struct { const enum modes mode; const char * text; } modes_array[] = { {MODE_CHUNKED, "chunked"}, {MODE_ADDCRAP, "addcrap"}, {MODE_NORMAL, "normal"}, {MODE_FAVICON, "favicon.ico"}, {MODE_INVALID, NULL} }; /** * write the response with random behaviour ! */ void send_response(int c, const char * buffer, int len) { int n; while(len > 0) { n = (rand() % 99) + 1; if(n > len) n = len; n = write(c, buffer, n); if(n < 0) { if(errno != EINTR) { perror("write"); return; } /* if errno == EINTR, try again */ } else { len -= n; buffer += n; } usleep(10000); /* 10ms */ } } /** * handle the HTTP connection */ void handle_http_connection(int c) { char request_buffer[2048]; int request_len = 0; int headers_found = 0; int n, i; char request_method[16]; char request_uri[256]; char http_version[16]; char * p; char * response_buffer; int response_len; enum modes mode; int content_length = 16*1024; /* read the request */ while(request_len < (int)sizeof(request_buffer) && !headers_found) { n = read(c, request_buffer + request_len, sizeof(request_buffer) - request_len); if(n < 0) { if(errno == EINTR) continue; perror("read"); return; } else if(n==0) { /* remote host closed the connection */ break; } else { request_len += n; for(i = 0; i < request_len - 3; i++) { if(0 == memcmp(request_buffer + i, "\r\n\r\n", 4)) { /* found the end of headers */ headers_found = 1; break; } } } } if(!headers_found) { /* error */ printf("no HTTP header found in the request\n"); return; } printf("headers :\n%.*s", request_len, request_buffer); /* the request have been received, now parse the request line */ p = request_buffer; for(i = 0; i < (int)sizeof(request_method) - 1; i++) { if(*p == ' ' || *p == '\r') break; request_method[i] = *p; ++p; } request_method[i] = '\0'; while(*p == ' ') p++; for(i = 0; i < (int)sizeof(request_uri) - 1; i++) { if(*p == ' ' || *p == '\r') break; request_uri[i] = *p; ++p; } request_uri[i] = '\0'; while(*p == ' ') p++; for(i = 0; i < (int)sizeof(http_version) - 1; i++) { if(*p == ' ' || *p == '\r') break; http_version[i] = *p; ++p; } http_version[i] = '\0'; printf("Method = %s, URI = %s, %s\n", request_method, request_uri, http_version); /* check if the request method is allowed */ if(0 != strcmp(request_method, "GET")) { const char response405[] = "HTTP/1.1 405 Method Not Allowed\r\n" "Allow: GET\r\n\r\n"; const char * pc; /* 405 Method Not Allowed */ /* The response MUST include an Allow header containing a list * of valid methods for the requested resource. */ n = sizeof(response405) - 1; pc = response405; while(n > 0) { i = write(c, pc, n); if(i<0) { if(errno != EINTR) { perror("write"); return; } } else { n -= i; pc += i; } } return; } mode = MODE_INVALID; /* use the request URI to know what to do */ for(i = 0; modes_array[i].mode != MODE_INVALID; i++) { if(strstr(request_uri, modes_array[i].text)) { mode = modes_array[i].mode; /* found */ break; } } switch(mode) { case MODE_CHUNKED: response_buffer = build_chunked_response(content_length, &response_len); break; case MODE_ADDCRAP: response_len = content_length+256; response_buffer = malloc(response_len); if(!response_buffer) break; n = snprintf(response_buffer, response_len, "HTTP/1.1 200 OK\r\n" "Server: minihttptestserver\r\n" "Content-Type: text/plain\r\n" "Content-Length: %d\r\n" "\r\n", content_length); response_len = content_length+n+CRAP_LENGTH; response_buffer = realloc(response_buffer, response_len); build_content(response_buffer + n, content_length); build_crap(response_buffer + n + content_length, CRAP_LENGTH); break; case MODE_FAVICON: content_length = FAVICON_LENGTH; response_len = content_length + 256; response_buffer = malloc(response_len); if(!response_buffer) break; n = snprintf(response_buffer, response_len, "HTTP/1.1 200 OK\r\n" "Server: minihttptestserver\r\n" "Content-Type: image/vnd.microsoft.icon\r\n" "Content-Length: %d\r\n" "\r\n", content_length); /* image/x-icon */ build_favicon_content(response_buffer + n, content_length); response_len = content_length + n; break; default: response_len = content_length+256; response_buffer = malloc(response_len); if(!response_buffer) break; n = snprintf(response_buffer, response_len, "HTTP/1.1 200 OK\r\n" "Server: minihttptestserver\r\n" "Content-Type: text/plain\r\n" "\r\n"); response_len = content_length+n; response_buffer = realloc(response_buffer, response_len); build_content(response_buffer + n, response_len - n); } if(response_buffer) { send_response(c, response_buffer, response_len); free(response_buffer); } else { /* Error 500 */ } } /** */ int main(int argc, char * * argv) { int ipv6 = 0; int s, c, i; unsigned short port = 0; struct sockaddr_storage server_addr; socklen_t server_addrlen; struct sockaddr_storage client_addr; socklen_t client_addrlen; pid_t pid; int child = 0; int status; const char * expected_file_name = NULL; struct sigaction sa; for(i = 1; i < argc; i++) { if(argv[i][0] == '-') { switch(argv[i][1]) { case '6': ipv6 = 1; break; case 'e': /* write expected file ! */ expected_file_name = argv[++i]; break; case 'p': /* port */ if(++i < argc) { port = (unsigned short)atoi(argv[i]); } break; default: fprintf(stderr, "unknown command line switch '%s'\n", argv[i]); } } else { fprintf(stderr, "unkown command line argument '%s'\n", argv[i]); } } srand(time(NULL)); memset(&sa, 0, sizeof(struct sigaction)); /*signal(SIGCHLD, handle_signal_chld);*/ sa.sa_handler = handle_signal_chld; if(sigaction(SIGCHLD, &sa, NULL) < 0) { perror("sigaction"); return 1; } /*signal(SIGINT, handle_signal_int);*/ sa.sa_handler = handle_signal_int; if(sigaction(SIGINT, &sa, NULL) < 0) { perror("sigaction"); return 1; } s = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0); if(s < 0) { perror("socket"); return 1; } memset(&server_addr, 0, sizeof(struct sockaddr_storage)); memset(&client_addr, 0, sizeof(struct sockaddr_storage)); if(ipv6) { struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&server_addr; addr->sin6_family = AF_INET6; addr->sin6_port = htons(port); addr->sin6_addr = in6addr_loopback; } else { struct sockaddr_in * addr = (struct sockaddr_in *)&server_addr; addr->sin_family = AF_INET; addr->sin_port = htons(port); addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK); } if(bind(s, (struct sockaddr *)&server_addr, ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) < 0) { perror("bind"); return 1; } if(listen(s, 5) < 0) { perror("listen"); } if(port == 0) { server_addrlen = sizeof(struct sockaddr_storage); if(getsockname(s, (struct sockaddr *)&server_addr, &server_addrlen) < 0) { perror("getsockname"); return 1; } if(ipv6) { struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&server_addr; port = ntohs(addr->sin6_port); } else { struct sockaddr_in * addr = (struct sockaddr_in *)&server_addr; port = ntohs(addr->sin_port); } printf("Listening on port %hu\n", port); fflush(stdout); } /* write expected file */ if(expected_file_name) { FILE * f; f = fopen(expected_file_name, "wb"); if(f) { char * buffer; buffer = malloc(16*1024); build_content(buffer, 16*1024); i = fwrite(buffer, 1, 16*1024, f); if(i != 16*1024) { fprintf(stderr, "error writing to file %s : %dbytes written (out of %d)\n", expected_file_name, i, 16*1024); } free(buffer); fclose(f); } else { fprintf(stderr, "error opening file %s for writing\n", expected_file_name); } } /* fork() loop */ while(!child && !quit) { while(child_to_wait_for > 0) { pid = wait(&status); if(pid < 0) { perror("wait"); } else { printf("child(%d) terminated with status %d\n", pid, status); } --child_to_wait_for; } client_addrlen = sizeof(struct sockaddr_storage); c = accept(s, (struct sockaddr *)&client_addr, &client_addrlen); if(c < 0) { if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) continue; perror("accept"); return 1; } printf("accept...\n"); pid = fork(); if(pid < 0) { perror("fork"); return 1; } else if(pid == 0) { /* child */ child = 1; close(s); s = -1; handle_http_connection(c); } close(c); } if(s >= 0) { close(s); s = -1; } if(!child) { while(child_to_wait_for > 0) { pid = wait(&status); if(pid < 0) { perror("wait"); } else { printf("child(%d) terminated with status %d\n", pid, status); } --child_to_wait_for; } printf("Bye...\n"); } return 0; } miniupnpc-1.9.20140610/testminiwget.sh010075500017500000024000000042551224506010400165250ustar00nanardstaff#!/bin/sh # $Id: testminiwget.sh,v 1.10 2013/11/13 15:08:08 nanard Exp $ # project miniupnp : http://miniupnp.free.fr/ # (c) 2011-2012 Thomas Bernard # # test program for miniwget.c # is usually invoked by "make check" # # This test program : # 1 - launches a local HTTP server (minihttptestserver) # 2 - uses testminiwget to retreive data from this server # 3 - compares served and received data # 4 - kills the local HTTP server and exits # # The script was tested and works with ksh, bash # it should now also run with dash TMPD=`mktemp -d miniwgetXXXXXXXXXX` HTTPSERVEROUT="${TMPD}/httpserverout" EXPECTEDFILE="${TMPD}/expectedfile" DOWNLOADEDFILE="${TMPD}/downloadedfile" PORT= RET=0 case "$HAVE_IPV6" in n|no|0) ADDR=localhost SERVERARGS="" ;; *) ADDR="[::1]" SERVERARGS="-6" ;; esac #make minihttptestserver #make testminiwget # launching the test HTTP server ./minihttptestserver $SERVERARGS -e $EXPECTEDFILE > $HTTPSERVEROUT & SERVERPID=$! while [ -z "$PORT" ]; do sleep 1 PORT=`cat $HTTPSERVEROUT | sed 's/Listening on port \([0-9]*\)/\1/' ` done echo "Test HTTP server is listening on $PORT" URL1="http://$ADDR:$PORT/index.html" URL2="http://$ADDR:$PORT/chunked" URL3="http://$ADDR:$PORT/addcrap" echo "standard test ..." ./testminiwget $URL1 "${DOWNLOADEDFILE}.1" if cmp $EXPECTEDFILE "${DOWNLOADEDFILE}.1" ; then echo "ok" else echo "standard test FAILED" RET=1 fi echo "chunked transfert encoding test ..." ./testminiwget $URL2 "${DOWNLOADEDFILE}.2" if cmp $EXPECTEDFILE "${DOWNLOADEDFILE}.2" ; then echo "ok" else echo "chunked transfert encoding test FAILED" RET=1 fi echo "response too long test ..." ./testminiwget $URL3 "${DOWNLOADEDFILE}.3" if cmp $EXPECTEDFILE "${DOWNLOADEDFILE}.3" ; then echo "ok" else echo "response too long test FAILED" RET=1 fi # kill the test HTTP server kill $SERVERPID wait $SERVERPID # remove temporary files (for success cases) if [ $RET -eq 0 ]; then rm -f "${DOWNLOADEDFILE}.1" rm -f "${DOWNLOADEDFILE}.2" rm -f "${DOWNLOADEDFILE}.3" rm -f $EXPECTEDFILE $HTTPSERVEROUT rmdir ${TMPD} else echo "at least one of the test FAILED" echo "directory ${TMPD} is left intact" fi exit $RET miniupnpc-1.9.20140610/apiversions.txt010064400017500000024000000070521227272130000165460ustar00nanardstaff$Id: apiversions.txt,v 1.3 2014/01/31 13:14:32 nanard Exp $ Differences in API between miniUPnPc versions ====================== miniUPnPc version 1.9 ====================== API version 10 upnpcommands.h: added argument remoteHost to UPNP_GetSpecificPortMappingEntry() miniupnpc.h: updated macros : #define MINIUPNPC_VERSION "1.9" #define MINIUPNPC_API_VERSION 10 ====================== miniUPnPc version 1.8 ====================== API version 9 miniupnpc.h: updated macros : #define MINIUPNPC_VERSION "1.8" #define MINIUPNPC_API_VERSION 9 added "unsigned int scope_id;" to struct UPNPDev added scope_id argument to GetUPNPUrls() ====================== miniUPnPc version 1.7 ====================== API version 8 miniupnpc.h : add new macros : #define MINIUPNPC_VERSION "1.7" #define MINIUPNPC_API_VERSION 8 add rootdescURL to struct UPNPUrls ====================== miniUPnPc version 1.6 ====================== API version 8 Adding support for IPv6. igd_desc_parse.h : struct IGDdatas_service : add char presentationurl[MINIUPNPC_URL_MAXSIZE]; struct IGDdatas : add struct IGDdatas_service IPv6FC; miniupnpc.h : new macros : #define UPNPDISCOVER_SUCCESS (0) #define UPNPDISCOVER_UNKNOWN_ERROR (-1) #define UPNPDISCOVER_SOCKET_ERROR (-101) #define UPNPDISCOVER_MEMORY_ERROR (-102) simpleUPnPcommand() prototype changed (but is normaly not used by API users) add arguments ipv6 and error to upnpDiscover() : struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport, int ipv6, int * error); add controlURL_6FC member to struct UPNPUrls : struct UPNPUrls { char * controlURL; char * ipcondescURL; char * controlURL_CIF; char * controlURL_6FC; }; upnpcommands.h : add leaseDuration argument to UPNP_AddPortMapping() add desc, enabled and leaseDuration arguments to UPNP_GetSpecificPortMappingEntry() add UPNP_GetListOfPortMappings() function (IGDv2) add IGDv2 IPv6 related functions : UPNP_GetFirewallStatus() UPNP_GetOutboundPinholeTimeout() UPNP_AddPinhole() UPNP_UpdatePinhole() UPNP_DeletePinhole() UPNP_CheckPinholeWorking() UPNP_GetPinholePackets() ====================== miniUPnPc version 1.5 ====================== API version 5 new function : int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); new macro in upnpcommands.h : #define UPNPCOMMAND_HTTP_ERROR ====================== miniUPnPc version 1.4 ====================== Same API as version 1.3 ====================== miniUPnPc version 1.3 ====================== API version 4 Use UNSIGNED_INTEGER type for UPNP_GetTotalBytesSent(), UPNP_GetTotalBytesReceived(), UPNP_GetTotalPacketsSent(), UPNP_GetTotalPacketsReceived() Add remoteHost argument to UPNP_AddPortMapping() and UPNP_DeletePortMapping() ====================== miniUPnPc version 1.2 ====================== API version 3 added sameport argument to upnpDiscover() struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport); ====================== miniUPnPc Version 1.1 ====================== Same API as 1.0 ====================== miniUPnPc Version 1.0 ====================== API version 2 struct UPNPDev { struct UPNPDev * pNext; char * descURL; char * st; char buffer[2]; }; struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock); miniupnpc-1.9.20140610/testreplyparse/DeletePortMapping.namevalue010064400017500000024000000000631214451773100240170ustar00nanardstaffNewRemoteHost= NewExternalPort=123 NewProtocol=TCP miniupnpc-1.9.20140610/testreplyparse/DeletePortMapping.xml010064400017500000024000000005751214451773100226520ustar00nanardstaff 123 TCP miniupnpc-1.9.20140610/testreplyparse/GetExternalIPAddress.namevalue010064400017500000024000000000361214451773100244150ustar00nanardstaffNewExternalIPAddress=1.2.3.4 miniupnpc-1.9.20140610/testreplyparse/GetExternalIPAddress.xml010064400017500000024000000005371214451773100232460ustar00nanardstaff1.2.3.4 miniupnpc-1.9.20140610/testreplyparse/readme.txt010064400017500000024000000003151214451773100205330ustar00nanardstaffThis directory contains files used for validation of upnpreplyparse.c code. Each .xml file to parse should give the results which are in the .namevalue file. A .namevalue file contain name=value lines. miniupnpc-1.9.20140610/testupnpreplyparse.sh010075500017500000024000000003201214452022000177560ustar00nanardstaff#!/bin/sh for f in testreplyparse/*.xml ; do bf="`dirname $f`/`basename $f .xml`" if ./testupnpreplyparse $f $bf.namevalue ; then echo "$f : passed" else echo "$f : FAILED" exit 1 fi done exit 0 miniupnpc-1.9.20140610/testreplyparse/SetDefaultConnectionService.namevalue010064400017500000024000000001571215417747400260500ustar00nanardstaffNewDefaultConnectionService=uuid:c6c05a33-f704-48df-9910-e099b3471d81:WANConnectionDevice:1,INVALID_SERVICE_ID miniupnpc-1.9.20140610/testreplyparse/SetDefaultConnectionService.xml010064400017500000024000000007071215417747400246740ustar00nanardstaffuuid:c6c05a33-f704-48df-9910-e099b3471d81:WANConnectionDevice:1,INVALID_SERVICE_ID miniupnpc-1.9.20140610/testreplyparse/GetSpecificPortMappingEntryReq.namevalue010064400017500000024000000000651227144321300264700ustar00nanardstaffNewProtocol=UDP NewExternalPort=12345 NewRemoteHost= miniupnpc-1.9.20140610/testreplyparse/GetSpecificPortMappingEntryReq.xml010064400017500000024000000006171227144321300253160ustar00nanardstaff 12345UDP miniupnpc-1.9.20140610/testreplyparse/GetSpecificPortMappingEntryResp.namevalue010064400017500000024000000001761227144321300266550ustar00nanardstaffNewInternalPort=12345 NewInternalClient=192.168.10.110 NewEnabled=1 NewPortMappingDescription=libminiupnpc NewLeaseDuration=0 miniupnpc-1.9.20140610/testreplyparse/GetSpecificPortMappingEntryResp.xml010064400017500000024000000010311227144321300254670ustar00nanardstaff12345192.168.10.1101libminiupnpc0