miniupnpc-1.6/Makefile010064400017500000024000000151071160013363600142070ustar00nanardstaff# $Id: Makefile,v 1.81 2011/06/21 15:24:14 nanard Exp $ # MiniUPnP Project # http://miniupnp.free.fr/ # (c) 2005-2011 Thomas Bernard # to install use : # $ PREFIX=/tmp/dummylocation make install # or # $ INSTALLPREFIX=/usr/local make install # or # make install (will go to /usr/bin, /usr/lib, etc...) OS = $(shell uname -s) CC ?= gcc #AR = gar #CFLAGS = -O -Wall -g -DDEBUG CFLAGS ?= -O -Wall -DNDEBUG -DMINIUPNPC_SET_SOCKET_TIMEOUT -Wstrict-prototypes # -DNO_GETADDRINFO INSTALL = install SH = /bin/sh JAVA = java # see http://code.google.com/p/jnaerator/ JNAERATOR = jnaerator-0.9.3.jar #following libs are needed on Solaris #LDLIBS=-lsocket -lnsl -lresolv # APIVERSION is used to build SONAME APIVERSION = 8 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 portlistringparse.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 SHAREDLIBRARY = libminiupnpc.so SONAME = $(SHAREDLIBRARY).$(APIVERSION) 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 # install directories INSTALLPREFIX ?= $(PREFIX)/usr INSTALLDIRINC = $(INSTALLPREFIX)/include/miniupnpc INSTALLDIRLIB = $(INSTALLPREFIX)/lib INSTALLDIRBIN = $(INSTALLPREFIX)/bin FILESTOINSTALL = $(LIBRARY) $(EXECUTABLES) ifneq ($(OS), AmigaOS) FILESTOINSTALL := $(FILESTOINSTALL) $(SHAREDLIBRARY) endif .PHONY: install clean depend all check everything \ installpythonmodule # validateminixml validateminiwget all: $(LIBRARY) $(EXECUTABLES) check: validateminixml validateminiwget everything: all $(EXECUTABLES_ADDTESTS) pythonmodule: $(LIBRARY) miniupnpcmodule.c setup.py python setup.py build touch $@ installpythonmodule: pythonmodule python setup.py install validateminixml: minixmlvalid @echo "minixml validation test" ./minixmlvalid touch $@ validateminiwget: testminiwget minihttptestserver testminiwget.sh @echo "miniwget validation test" ./testminiwget.sh touch $@ clean: $(RM) $(LIBRARY) $(SHAREDLIBRARY) $(EXECUTABLES) $(OBJS) miniupnpcstrings.h # clean python stuff $(RM) pythonmodule validateminixml $(RM) -r build/ dist/ #python setup.py clean install: $(FILESTOINSTALL) $(INSTALL) -d $(INSTALLDIRINC) $(INSTALL) -m 644 $(HEADERS) $(INSTALLDIRINC) $(INSTALL) -d $(INSTALLDIRLIB) $(INSTALL) -m 644 $(LIBRARY) $(INSTALLDIRLIB) ifneq ($(OS), AmigaOS) $(INSTALL) -m 644 $(SHAREDLIBRARY) $(INSTALLDIRLIB)/$(SONAME) ln -fs $(SONAME) $(INSTALLDIRLIB)/$(SHAREDLIBRARY) endif $(INSTALL) -d $(INSTALLDIRBIN) ifeq ($(OS), AmigaOS) $(INSTALL) -m 755 upnpc-static $(INSTALLDIRBIN)/upnpc else $(INSTALL) -m 755 upnpc-shared $(INSTALLDIRBIN)/upnpc endif $(INSTALL) -m 755 external-ip.sh $(INSTALLDIRBIN)/external-ip cleaninstall: $(RM) -r $(INSTALLDIRINC) $(RM) $(INSTALLDIRLIB)/$(LIBRARY) $(RM) $(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 $@ $^ else $(CC) -shared $(LDFLAGS) -Wl,-soname,$(SONAME) -o $@ $^ endif upnpc-static: upnpc.o $(LIBRARY) $(LDLIBS) $(CC) $(LDFLAGS) -o $@ $^ upnpc-shared: upnpc.o $(SHAREDLIBRARY) $(LDLIBS) $(CC) $(LDFLAGS) -o $@ $^ testminixml: $(TESTMINIXMLOBJS) testminiwget: $(TESTMINIWGETOBJS) minixmlvalid: minixml.o minixmlvalid.o testupnpreplyparse: $(TESTUPNPREPLYPARSE) testigddescparse: $(TESTIGDDESCPARSE) miniupnpcstrings.h: miniupnpcstrings.h.in updateminiupnpcstrings.sh $(SH) updateminiupnpcstrings.sh jar: $(SHAREDLIBRARY) $(JAVA) -jar $(JNAERATOR) -library miniupnpc 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_$(OS).jar -v 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.6/igd_desc_parse.c010064400017500000024000000110121155054365100156430ustar00nanardstaff/* $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.6/igd_desc_parse.h010064400017500000024000000030241155054365100156540ustar00nanardstaff/* $Id: igd_desc_parse.h,v 1.10 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. * */ #ifndef __IGD_DESC_PARSE_H__ #define __IGD_DESC_PARSE_H__ /* 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.6/miniwget.c010064400017500000024000000320201157675713100145450ustar00nanardstaff/* $Id: miniwget.c,v 1.52 2011/06/17 22:59:42 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2005-2011 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 #define closesocket close /* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions * during the connect() call */ #define MINIUPNPC_IGNORE_EINTR #endif /* #else WIN32 */ #if defined(__sun) || defined(sun) #define MIN(x,y) (((x)<(y))?(x):(y)) #endif #include "miniupnpcstrings.h" #include "miniwget.h" #include "connecthostport.h" #include "receivedata.h" /* * 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; int header_buf_len = 2048; int header_buf_used = 0; char * content_buf; int content_buf_len = 2048; int content_buf_used = 0; char chunksize_buf[32]; 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)) > 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 < (header_buf_used-1) && (endofheaders == 0)) { if(header_buf[i] == '\r') { i++; if(header_buf[i] == '\n') { i++; if(i < header_buf_used && header_buf[i] == '\r') { i++; if(i < 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(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:(n - i); if((int)(content_buf_used + bytestocopy) > content_buf_len) { if(content_length >= content_buf_used + (int)bytestocopy) { content_buf_len = content_length; } else { content_buf_len = content_buf_used + (int)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 && (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 >= 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 && 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 * url, const char * host, unsigned short port, const char * path, int * size, char * addr_str, int addr_str_len, const char * httpversion) { char buf[2048]; int s; int n; int len; int sent; void * content; *size = 0; s = connecthostport(host, port); 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 * url, const char * host, unsigned short port, const char * path, int * size, char * addr_str, int addr_str_len) { char * respbuffer; respbuffer = miniwget3(url, host, port, path, size, addr_str, addr_str_len, "1.1"); /* respbuffer = miniwget3(url, host, port, path, size, addr_str, addr_str_len, "1.0"); if (*size == 0) { #ifdef DEBUG printf("Retrying with HTTP/1.1\n"); #endif free(respbuffer); respbuffer = miniwget3(url, host, port, path, size, addr_str, addr_str_len, "1.1"); } */ 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) { 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 */ p2 = strchr(p1, ']'); 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 short port; char * path; /* protocol://host:port/chemin */ char hostname[MAXHOSTNAMELEN+1]; *size = 0; if(!parseURL(url, hostname, &port, &path)) return NULL; #ifdef DEBUG printf("parsed url : hostname='%s' port=%hu path='%s'\n", hostname, port, path); #endif return miniwget2(url, hostname, port, path, size, 0, 0); } void * miniwget_getaddr(const char * url, int * size, char * addr, int addrlen) { unsigned short port; char * path; /* protocol://host:port/chemin */ char hostname[MAXHOSTNAMELEN+1]; *size = 0; if(addr) addr[0] = '\0'; if(!parseURL(url, hostname, &port, &path)) return NULL; #ifdef DEBUG printf("parsed url : hostname='%s' port=%hu path='%s'\n", hostname, port, path); #endif return miniwget2(url, hostname, port, path, size, addr, addrlen); } miniupnpc-1.6/miniwget.h010064400017500000024000000012011150020002000145060ustar00nanardstaff/* $Id: miniwget.h,v 1.6 2010/12/09 16:11:33 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 __MINIWGET_H__ #define __MINIWGET_H__ #include "declspec.h" #ifdef __cplusplus extern "C" { #endif LIBSPEC void * getHTTPResponse(int s, int * size); LIBSPEC void * miniwget(const char *, int *); LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int); int parseURL(const char *, char *, unsigned short *, char * *); #ifdef __cplusplus } #endif #endif miniupnpc-1.6/minixml.c010064400017500000024000000124041152377627000144000ustar00nanardstaff/* $Id: minixml.c,v 1.9 2011/02/07 13:44:57 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-2011, 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)[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.6/minixml.h010064400017500000024000000022211053354231500143700ustar00nanardstaff/* $Id: minixml.h,v 1.6 2006/11/30 11:47:21 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__ #define __MINIXML_H__ #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.6/upnpc.c010064400017500000024000000533551157676166500140740ustar00nanardstaff/* $Id: upnpc.c,v 1.88 2011/06/17 23:31:01 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2005-2011 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 #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; UPNP_GetConnectionTypeInfo(urls->controlURL, data->first.servicetype, connectionType); if(connectionType[0]) printf("Connection Type : %s\n", connectionType); else printf("GetConnectionTypeInfo failed.\n"); UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, status, &uptime, lastconnerr); printf("Status : %s, uptime=%us, LastConnectionError : %s\n", status, uptime, lastconnerr); timenow = time(NULL); timestarted = timenow - uptime; printf(" Time started : %s", ctime(×tarted)); UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype, &brDown, &brUp); 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() returned %d\n", r); if(externalIPAddress[0]) printf("ExternalIPAddress = %s\n", externalIPAddress); else printf("GetExternalIPAddress failed.\n"); } 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);*/ 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) { 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) { char externalIPAddress[40]; char intClient[40]; char intPort[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; } UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, externalIPAddress); if(externalIPAddress[0]) printf("ExternalIPAddress = %s\n", externalIPAddress); else printf("GetExternalIPAddress failed.\n"); r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype, eport, iport, iaddr, 0, 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, intClient, intPort, NULL/*desc*/, NULL/*enabled*/, duration); if(r!=UPNPCOMMAND_SUCCESS) printf("GetSpecificPortMappingEntry() failed with code %d (%s)\n", r, strupnperror(r)); if(intClient[0]) { 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); } /* 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; if(!intaddr || !remoteaddr || !iport || !eport || !proto || !lease_time) { fprintf(stderr, "Wrong arguments\n"); return; } /*proto = protofix(proto); if(!proto) { 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", intaddr, iport, remoteaddr, eport, r, strupnperror(r)); else { printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n", intaddr, iport, remoteaddr, eport, 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; #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) 2006-2011 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"); break; case 'd': for(i=0; i #include #include #include "minixml.h" #include "igd_desc_parse.h" #ifdef WIN32 #define NO_BZERO #endif #ifdef NO_BZERO #define bzero(p, n) memset(p, 0, n) #endif /* ---------------------------------------------------------------------- */ void printeltname1(void * d, const char * name, int l) { int i; 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.6/minisoap.h010064400017500000024000000007501136070252500145370ustar00nanardstaff/* $Id: minisoap.h,v 1.4 2010/04/12 20:39:41 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__ #define __MINISOAP_H__ /*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.6/miniupnpc.c010064400017500000024000000602371156404501300147210ustar00nanardstaff/* $Id: miniupnpc.c,v 1.95 2011/05/15 21:42:26 nanard Exp $ */ /* Project : miniupnp * Author : Thomas BERNARD * copyright (c) 2005-2011 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 #include #include #include #ifdef WIN32 /* Win32 Specific includes and defines */ #include #include #include #include #define snprintf _snprintf #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 #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 #define SOAPPREFIX "s" #define SERVICEPREFIX "u" #define SERVICEPREFIX2 'u' /* root description parsing */ 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)) return NULL; if(s<0) { s = connecthostport(hostname, port); if(s < 0) { 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; buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); /* 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"); } */ 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 */ ((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"); } } } /* Avant d'envoyer le paquet on bind pour recevoir la reponse */ 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; /* 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) { 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); 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'; devlist = tmp; } } } closesocket(sudp); return devlist; } /* freeUPNPDevlist() should be used to * free the chained list returned by upnpDiscover() */ 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... */ LIBSPEC void GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data, const char * descURL) { char * p; int n1, n2, n3, n4; n1 = strlen(data->urlbase); if(n1==0) n1 = strlen(descURL); 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); urls->ipcondescURL = (char *)malloc(n1); urls->controlURL = (char *)malloc(n2); urls->controlURL_CIF = (char *)malloc(n3); urls->controlURL_6FC = (char *)malloc(n4); /* maintenant on chope la desc du 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'; 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 } 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; } 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 : * 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. */ LIBSPEC int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen) { char * descXML; int descXMLsize = 0; struct UPNPDev * dev; int ndev = 0; int state; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ if(!devlist) { #ifdef DEBUG printf("Empty devlist\n"); #endif return 0; } for(state = 1; state <= 3; state++) { for(dev = devlist; dev; dev = dev->pNext) { /* we should choose an internet gateway device. * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */ descXML = miniwget_getaddr(dev->descURL, &descXMLsize, lanaddr, lanaddrlen); if(descXML) { ndev++; memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); parserootdesc(descXML, descXMLsize, data); free(descXML); descXML = NULL; if(0==strcmp(data->CIF.servicetype, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1") || state >= 3 ) { GetUPNPUrls(urls, data, dev->descURL); #ifdef DEBUG printf("UPNPIGD_IsConnected(%s) = %d\n", urls->controlURL, UPNPIGD_IsConnected(urls, data)); #endif if((state >= 2) || UPNPIGD_IsConnected(urls, data)) return state; 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); #ifdef DEBUG printf("UPNPIGD_IsConnected(%s) = %d\n", urls->controlURL, UPNPIGD_IsConnected(urls, data)); #endif if((state >= 2) || UPNPIGD_IsConnected(urls, data)) return state; FreeUPNPUrls(urls); } } memset(data, 0, sizeof(struct IGDdatas)); } #ifdef DEBUG else { printf("error getting XML description %s\n", dev->descURL); } #endif } } return 0; } /* 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); 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); return 1; } else { return 0; } } miniupnpc-1.6/miniupnpc.h010064400017500000024000000071231155054262400147260ustar00nanardstaff/* $Id: miniupnpc.h,v 1.23 2011/04/11 08:21:46 nanard Exp $ */ /* Project: miniupnp * http://miniupnp.free.fr/ * 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 __MINIUPNPC_H__ #define __MINIUPNPC_H__ #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) #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; 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. */ LIBSPEC struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport, int ipv6, int * error); /* freeUPNPDevlist() * free list returned by upnpDiscover() */ LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist); /* parserootdesc() : * parse root XML description of a UPnP device and fill the IGDdatas * structure. */ 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; }; /* 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. */ 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 */ LIBSPEC int UPNP_GetIGDFromUrl(const char * rootdescurl, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen); LIBSPEC void GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, const char *); LIBSPEC void FreeUPNPUrls(struct UPNPUrls *); /* return 0 or 1 */ LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); #ifdef __cplusplus } #endif #endif miniupnpc-1.6/README010064400017500000024000000036341156504333400134360ustar00nanardstaffProject: miniupnp Project web page: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ Author: Thomas Bernard Copyright (c) 2005-2011 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 * To compile, simply run 'gmake' (could be 'make' on your system). Under win32, to compile with MinGW, type "mingw32make.bat". 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 in 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.6/LICENSE010064400017500000024000000027111161332764700135640ustar00nanardstaffMiniUPnPc Copyright (c) 2005-2011, 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.6/upnpcommands.c010064400017500000024000000742101157245315200154250ustar00nanardstaff/* $Id: upnpcommands.c,v 1.37 2011/06/04 15:56:23 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2005-2011 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; } /* * */ 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; } /* * */ 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; } /* * */ 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; } /* * */ 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 */ 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 */ 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 */ 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. */ 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; } 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; } 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; } 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; } 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 */ LIBSPEC int UPNP_GetSpecificPortMappingEntry(const char * controlURL, const char * servicetype, const char * extPort, const char * proto, 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"; /* TODO : add remote host ? */ 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. */ 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 */ 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; } 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; } 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; } 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; } 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; } 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; } 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.6/upnpreplyparse.c010064400017500000024000000070361152626625600160220ustar00nanardstaff/* $Id: upnpreplyparse.c,v 1.11 2011/02/07 16:17:06 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2011 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; if(l>63) l = 63; memcpy(data->curelt, name, l); data->curelt[l] = '\0'; } static void NameValueParserGetData(void * d, const char * datas, int l) { struct NameValueParserData * data = (struct NameValueParserData *)d; struct NameValue * nv; 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. Limited to 63 chars strings */ nv = malloc(sizeof(struct NameValue)); if(l>63) l = 63; strncpy(nv->name, data->curelt, 64); nv->name[63] = '\0'; memcpy(nv->value, datas, l); nv->value[l] = '\0'; LIST_INSERT_HEAD( &(data->head), nv, entries); } } 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 = 0; 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.6/upnpreplyparse.h010064400017500000024000000026461152626625600160310ustar00nanardstaff/* $Id: upnpreplyparse.h,v 1.11 2011/02/07 16:17:06 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2011 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #ifndef __UPNPREPLYPARSE_H__ #define __UPNPREPLYPARSE_H__ #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[64]; }; struct NameValueParserData { LIST_HEAD(listhead, NameValue) head; char curelt[64]; char * portListing; int portListingLength; }; /* 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); /* GetValueFromNameValueListIgnoreNS() */ char * GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, const char * Name); /* DisplayNameValueList() */ #ifdef DEBUG void DisplayNameValueList(char * buffer, int bufsize); #endif #ifdef __cplusplus } #endif #endif miniupnpc-1.6/upnpcommands.h010064400017500000024000000226471155054313200154330ustar00nanardstaff/* $Id: upnpcommands.h,v 1.23 2011/04/11 09:14:00 nanard Exp $ */ /* Miniupnp project : http://miniupnp.free.fr/ * Author : Thomas Bernard * Copyright (c) 2005-2011 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided within this distribution */ #ifndef __UPNPCOMMANDS_H__ #define __UPNPCOMMANDS_H__ #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) #ifdef __cplusplus extern "C" { #endif LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalBytesSent(const char * controlURL, const char * servicetype); LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalBytesReceived(const char * controlURL, const char * servicetype); LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalPacketsSent(const char * controlURL, const char * servicetype); 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 */ 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 */ 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. */ 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. */ 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. * 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 */ 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_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. * 714 NoSuchEntryInArray - The specified value does not exist in the array */ LIBSPEC int UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, const char * extPort, const char * proto, const char * remoteHost); /* UPNP_GetPortMappingNumberOfEntries() * not supported by all routers */ 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 * 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. */ LIBSPEC int UPNP_GetSpecificPortMappingEntry(const char * controlURL, const char * servicetype, const char * extPort, const char * proto, 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. * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds */ 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. */ 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 */ LIBSPEC int UPNP_GetFirewallStatus(const char * controlURL, const char * servicetype, int * firewallEnabled, int * inboundPinholeAllowed); 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); 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); LIBSPEC int UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, const char * uniqueID, const char * leaseTime); LIBSPEC int UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID); LIBSPEC int UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, const char * uniqueID, int * isWorking); LIBSPEC int UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, const char * uniqueID, int * packets); #ifdef __cplusplus } #endif #endif miniupnpc-1.6/Makefile.mingw010064400017500000024000000047011155311462100153250ustar00nanardstaff# $Id: Makefile.mingw,v 1.16 2011/04/18 17:39:31 nanard Exp $ # Miniupnp project. # http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ # (c) 2005-2011 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 used for GetBestRoute() 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) -DSTATICLIB -c -o $@ $< $(CC) $(CFLAGS) -DMINIUPNP_EXPORTS -c -o dll/$@ $< upnpc.o: $(CC) $(CFLAGS) -DSTATICLIB -c -o $@ $< $(CC) $(CFLAGS) -c -o dll/$@ $< upnpc-static: upnpc.o libminiupnpc.a $(CC) -enable-stdcall-fixup -o $@ $^ $(LDLIBS) upnpc-shared: dll/upnpc.o miniupnpc.lib $(CC) -enable-stdcall-fixup -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.6/bsdqueue.h010064400017500000024000000432751045223002500145360ustar00nanardstaff/* $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.6/Changelog.txt010064400017500000024000000260471161332764700152170ustar00nanardstaff$Id: Changelog.txt,v 1.152 2011/07/25 18:02:11 nanard Exp $ miniUPnP client Changelog. 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.6/minixmlvalid.c010064400017500000024000000066631152377357100154330ustar00nanardstaff/* $Id: minixmlvalid.c,v 1.4 2011/02/07 13:44:57 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; r = testxmlparser(xmldata, sizeof(xmldata)-1); if(r) printf("minixml validation test failed\n"); return r; } miniupnpc-1.6/declspec.h010064400017500000024000000003701062430650200144750ustar00nanardstaff#ifndef __DECLSPEC_H__ #define __DECLSPEC_H__ #if defined(WIN32) && !defined(STATICLIB) #ifdef MINIUPNP_EXPORTS #define LIBSPEC __declspec(dllexport) #else #define LIBSPEC __declspec(dllimport) #endif #else #define LIBSPEC #endif #endif miniupnpc-1.6/mingw32make.bat010064400017500000024000000003241131314053500153530ustar00nanardstaff@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.6/testupnpreplyparse.c010064400017500000024000000016741075727434200167240ustar00nanardstaff/* $Id: testupnpreplyparse.c,v 1.2 2008/02/21 13:05:27 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2007 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #include #include #include "upnpreplyparse.h" void test_parsing(const char * buf, int len) { struct NameValueParserData pdata; ParseNameValue(buf, len, &pdata); ClearNameValueList(&pdata); } int main(int argc, char * * argv) { FILE * f; char buffer[4096]; int l; if(argc<2) { fprintf(stderr, "Usage: %s file.xml\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); buffer[l] = '\0'; #ifdef DEBUG DisplayNameValueList(buffer, l); #endif test_parsing(buffer, l); return 0; } miniupnpc-1.6/miniupnpcmodule.c010064400017500000024000000343541155054262400161350ustar00nanardstaff/* $Id: miniupnpcmodule.c,v 1.18 2011/04/10 11:21:23 nanard Exp $*/ /* Project : miniupnp * Author : Thomas BERNARD * website : http://miniupnp.tuxfamily.org/ * copyright (c) 2007-2009 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENCE file. */ #include #define 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 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); self->ob_type->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; } } /* 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; } } 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) * proto = 'UDP' or 'TCP' */ static PyObject * UPnP_getspecificportmapping(UPnPObject *self, PyObject *args) { char extPort[6]; unsigned short ePort; const char * proto; char intClient[40]; char intPort[6]; unsigned short iPort; char desc[80]; char enabled[4]; char leaseDuration[16]; if(!PyArg_ParseTuple(args, "Hs", &ePort, &proto)) 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, 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" }, {"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS, "delete a port mapping" }, {"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 = { PyObject_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 */ }; #ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ #define PyMODINIT_FUNC void #endif PyMODINIT_FUNC initminiupnpc(void) { PyObject* m; #ifdef WIN32 UPnPType.tp_new = PyType_GenericNew; #endif if (PyType_Ready(&UPnPType) < 0) return; m = Py_InitModule3("miniupnpc", miniupnpc_methods, "miniupnpc module."); Py_INCREF(&UPnPType); PyModule_AddObject(m, "UPnP", (PyObject *)&UPnPType); } miniupnpc-1.6/pymoduletest.py010064400017500000024000000025411107515756700156740ustar00nanardstaff#! /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.6/setup.py010064400017500000024000000010411152033016000142410ustar00nanardstaff#! /usr/bin/python # $Id: setup.py,v 1.6 2011/01/04 09:46:08 nanard Exp $ # the MiniUPnP Project (c) 2007-2011 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 setup(name="miniupnpc", version="1.5", ext_modules=[ Extension(name="miniupnpc", sources=["miniupnpcmodule.c"], extra_objects=["libminiupnpc.a"]) ]) miniupnpc-1.6/setupmingw32.py010064400017500000024000000010541156404501300154640ustar00nanardstaff#! /usr/bin/python # $Id: setupmingw32.py,v 1.5 2011/05/15 21:18:43 nanard Exp $ # the MiniUPnP Project (c) 2007-2011 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 setup(name="miniupnpc", version="1.5", ext_modules=[ Extension(name="miniupnpc", sources=["miniupnpcmodule.c"], libraries=["ws2_32", "iphlpapi"], extra_objects=["libminiupnpc.a"]) ]) miniupnpc-1.6/minissdpc.h010064400017500000024000000007341066603022500147120ustar00nanardstaff/* $Id: minissdpc.h,v 1.1 2007/08/31 15:15:33 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__ #define __MINISSDPC_H__ struct UPNPDev * getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath); #endif miniupnpc-1.6/minissdpc.c010064400017500000024000000060561150020002000146640ustar00nanardstaff/* $Id: minissdpc.c,v 1.14 2010/11/25 09:57:25 nanard Exp $ */ /* Project : miniupnp * Author : Thomas BERNARD * copyright (c) 2005-2009 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[2048]; 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.6/man3/miniupnpc.3010064400017500000024000000054171161332764700155110ustar00nanardstaff\" $Id: miniupnpc.3,v 1.3 2011/07/25 18:02:11 nanard Exp $ .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.6/upnperrors.h010064400017500000024000000011171103317130200151230ustar00nanardstaff/* $Id: upnperrors.h,v 1.2 2008/07/02 23:31:15 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__ #define __UPNPERRORS_H__ #include "declspec.h" #ifdef __cplusplus extern "C" { #endif /* strupnperror() * Return a string description of the UPnP error code * or NULL for undefinded errors */ LIBSPEC const char * strupnperror(int err); #ifdef __cplusplus } #endif #endif miniupnpc-1.6/upnperrors.c010064400017500000024000000037741155054262400151460ustar00nanardstaff/* $Id: upnperrors.c,v 1.5 2011/04/10 11:19:36 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 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 = NULL; } return s; } miniupnpc-1.6/testigddescparse.c010064400017500000024000000030451130574105700162520ustar00nanardstaff/* $Id: testigddescparse.c,v 1.2 2009/12/03 13:50:06 nanard Exp $ */ /* Project : miniupnp * http://miniupnp.free.fr/ * Author : Thomas Bernard * Copyright (c) 2008-2009 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"); 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.6/testupnpigd.py010075500017500000024000000044741107407761000155030ustar00nanardstaff#! /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.6/miniupnpc.def010064400017500000024000000016211155311462100152250ustar00nanardstaffLIBRARY ; miniupnpc library 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.6/codelength.h010064400017500000024000000016121107250552600150340ustar00nanardstaff/* $Id: codelength.h,v 1.1 2008/10/06 22:04:06 nanard Exp $ */ /* Project : miniupnp * Author : Thomas BERNARD * copyright (c) 2005-2008 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENCE file. */ #ifndef __CODELENGTH_H__ #define __CODELENGTH_H__ /* 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); #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.6/miniupnpcstrings.h.in010064400017500000024000000007451152033016000167330ustar00nanardstaff/* $Id: miniupnpcstrings.h.in,v 1.4 2011/01/04 11:41:53 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__ #define __MINIUPNPCSTRINGS_H__ #define OS_STRING "OS/version" #define MINIUPNPC_VERSION_STRING "version" #endif miniupnpc-1.6/updateminiupnpcstrings.sh010075500017500000024000000027201152033016000177120ustar00nanardstaff#! /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.6/VERSION010064400017500000024000000000041161332764700136200ustar00nanardstaff1.6 miniupnpc-1.6/testminiwget.c010064400017500000024000000026371156102140700154400ustar00nanardstaff/* $Id: testminiwget.c,v 1.3 2011/05/06 16:33:53 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2005-2011 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(argv[1], &size);*/ data = miniwget_getaddr(argv[1], &size, addr, sizeof(addr)); 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.6/msvc/miniupnpc.sln010064400017500000024000000027031131024352600162330ustar00nanardstaff 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.6/msvc/miniupnpc.vcproj010064400017500000024000000115411155311462100167440ustar00nanardstaff miniupnpc-1.6/msvc/upnpc-static.vcproj010064400017500000024000000076411136243111600173610ustar00nanardstaff miniupnpc-1.6/wingenminiupnpcstrings.c010064400017500000024000000052561152033016000175330ustar00nanardstaff/* $Id: wingenminiupnpcstrings.c,v 1.2 2011/01/11 15:31:13 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.6/connecthostport.c010064400017500000024000000133741155054262400161600ustar00nanardstaff/* $Id: connecthostport.c,v 1.5 2011/04/09 08:49:50 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2010-2011 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 #define closesocket close #include /* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions * during the connect() call */ #define MINIUPNPC_IGNORE_EINTR #ifndef USE_GETHOSTBYNAME #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" /* 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) { 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 while(n < 0 && errno == EINTR) { 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; for(i = 0; host[i+1] && (host[i+1] != ']') && i < MAXHOSTNAMELEN; i++) { tmp_host[i] = host[i+1]; } 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; #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 while(n < 0 && errno == EINTR) { 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.6/connecthostport.h010064400017500000024000000010251135621733700161570ustar00nanardstaff/* $Id: connecthostport.h,v 1.1 2010/04/04 23:21:03 nanard Exp $ */ /* Project: miniupnp * http://miniupnp.free.fr/ * Author: Thomas Bernard * Copyright (c) 2010 Thomas Bernard * This software is subjects to the conditions detailed * in the LICENCE file provided within this distribution */ #ifndef __CONNECTHOSTPORT_H__ #define __CONNECTHOSTPORT_H__ /* 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); #endif miniupnpc-1.6/java/JavaBridgeTest.java010064400017500000024000000113701153742240100171670ustar00nanardstaffimport java.nio.ByteBuffer; 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, null); 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], 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.6/java/testjava.sh010075500017500000024000000002201135635141700156450ustar00nanardstaff#! /bin/sh JAVA=java JAVAC=javac $JAVAC -cp miniupnpc_Linux.jar JavaBridgeTest.java $JAVA -cp miniupnpc_Linux.jar:. JavaBridgeTest 12345 UDP miniupnpc-1.6/external-ip.sh010075500017500000024000000002311142653250500153320ustar00nanardstaff#!/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.6/MANIFEST.in010064400017500000024000000001351150020330200142630ustar00nanardstaffinclude README include miniupnpcmodule.c include setup.py include *.h include libminiupnpc.a miniupnpc-1.6/portlistingparse.c010064400017500000024000000067001154063567100163340ustar00nanardstaff/* $Id: portlistingparse.c,v 1.4 2011/03/18 11:02:17 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; 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.6/portlistingparse.h010064400017500000024000000035551153030370000163260ustar00nanardstaff/* $Id: portlistingparse.h,v 1.4 2011/02/15 23:03:56 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 */ #ifndef __PORTLISTINGPARSE_H__ #define __PORTLISTINGPARSE_H__ #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; }; LIBSPEC void ParsePortListing(const char * buffer, int bufsize, struct PortMappingParserData * pdata); LIBSPEC void FreePortListing(struct PortMappingParserData * pdata); #ifdef __cplusplus } #endif #endif miniupnpc-1.6/miniupnpctypes.h010064400017500000024000000011301152645746000160110ustar00nanardstaff/* $Id: miniupnpctypes.h,v 1.1 2011/02/15 11:10:40 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__ #define __MINIUPNPCTYPES_H__ #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.6/CMakeLists.txt010064400017500000024000000136111155054262400153120ustar00nanardstaffcmake_minimum_required (VERSION 2.6) project (miniupnpc C) set (MINIUPNPC_VERSION 1.5) set (MINIUPNPC_API_VERSION 8) 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) 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 ) 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 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 ) 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 ) 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 declspec.h DESTINATION include/miniupnpc ) set (CONFIGURED YES CACHE INTERNAL "") # vim: ts=2:sw=2 miniupnpc-1.6/miniupnpcstrings.h.cmake010064400017500000024000000002501153636307100174120ustar00nanardstaff#ifndef __MINIUPNPCSTRINGS_H__ #define __MINIUPNPCSTRINGS_H__ #define OS_STRING "${CMAKE_SYSTEM_NAME}" #define MINIUPNPC_VERSION_STRING "${MINIUPNPC_VERSION}" #endif miniupnpc-1.6/receivedata.c010064400017500000024000000040541155053503300151670ustar00nanardstaff/* $Id: receivedata.c,v 1.1 2011/04/11 08:21:47 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2011 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 #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) { 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 n = recv(socket, data, length, 0); if(n<0) { PRINT_SOCKET_ERROR("recv"); } return n; } miniupnpc-1.6/receivedata.h010064400017500000024000000012021155053503300151640ustar00nanardstaff/* $Id: receivedata.h,v 1.1 2011/04/11 08:21:47 nanard Exp $ */ /* Project: miniupnp * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author: Thomas Bernard * Copyright (c) 2011 Thomas Bernard * This software is subjects to the conditions detailed * in the LICENCE file provided within this distribution */ #ifndef __RECEIVEDATA_H__ #define __RECEIVEDATA_H__ /* 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); #endif miniupnpc-1.6/minihttptestserver.c010064400017500000024000000252031156172604500167040ustar00nanardstaff/* $Id: minihttptestserver.c,v 1.6 2011/05/09 08:53:15 nanard Exp $ */ /* Project : miniUPnP * Author : Thomas Bernard * Copyright (c) 2011 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 #define CRAP_LENGTH (2048) volatile int quit = 0; volatile int child_to_wait_for = 0; /** * signal handler for SIGCHLD (child status has changed) */ void handle_signal_chld(int sig) { printf("handle_signal_chld(%d)\n", sig); ++child_to_wait_for; } /** * signal handler for SIGINT (CRTL C) */ #if 0 void handle_signal_int(int sig) { printf("handle_signal_int(%d)\n", sig); quit = 1; } #endif /** * 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'; } memcpy(response_buffer + *response_len, "0\r\n", 3); *response_len += 3; free(content_buffer); printf("resp_length=%d buffer_length=%d content_length=%d\n", *response_len, buffer_length, content_length); return response_buffer; } enum modes { MODE_INVALID, MODE_CHUNKED, MODE_ADDCRAP, MODE_NORMAL }; const struct { const enum modes mode; const char * text; } modes_array[] = { {MODE_CHUNKED, "chunked"}, {MODE_ADDCRAP, "addcrap"}, {MODE_NORMAL, "normal"}, {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) { perror("write"); return; } 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 < sizeof(request_buffer) && !headers_found) { n = read(c, request_buffer + request_len, sizeof(request_buffer) - request_len); if(n < 0) { 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 */ 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 < 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 < 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 < 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"; /* 405 Method Not Allowed */ /* The response MUST include an Allow header containing a list * of valid methods for the requested resource. */ write(c, response405, sizeof(response405) - 1); 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); 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; default: response_len = content_length+256; response_buffer = malloc(response_len); 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; 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)); signal(SIGCHLD, handle_signal_chld); #if 0 signal(SIGINT, handle_signal_int); #endif 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_any; } 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_ANY); } 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); fwrite(buffer, 1, 16*1024, f); free(buffer); fclose(f); } } /* 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; } /* TODO : add a select() call in order to handle the case * when a signal is caught */ client_addrlen = sizeof(struct sockaddr_storage); c = accept(s, (struct sockaddr *)&client_addr, &client_addrlen); if(c < 0) { 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.6/testminiwget.sh010075500017500000024000000034731156172604500156440ustar00nanardstaff#!/bin/sh # $Id: testminiwget.sh,v 1.4 2011/05/09 08:53:15 nanard Exp $ # project miniupnp : http://miniupnp.free.fr/ # (c) 2011 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 # HTTPSERVEROUT=/tmp/httpserverout EXPECTEDFILE=/tmp/expectedfile DOWNLOADEDFILE=/tmp/downloadedfile #ADDR=localhost ADDR="[::1]" PORT= RET=0 #make minihttptestserver #make testminiwget # launching the test HTTP server ./minihttptestserver -6 -e $EXPECTEDFILE > $HTTPSERVEROUT & while [ "$PORT" == "" ]; do 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 %1 wait %1 # 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 else echo "at least one of the test FAILED" fi exit $RET