diff --git a/miniupnpc/Changelog.txt b/miniupnpc/Changelog.txt index 93f0e66..174b103 100644 --- a/miniupnpc/Changelog.txt +++ b/miniupnpc/Changelog.txt @@ -1,6 +1,10 @@ $Id: Changelog.txt,v 1.206 2015/05/22 10:23:47 nanard Exp $ miniUPnP client Changelog. +2015/06/16: + update getDevicesFromMiniSSDPD() to process longer minissdpd + responses + 2015/05/22: add searchalltypes param to upnpDiscoverDevices() increments API_VERSION to 13 diff --git a/miniupnpc/codelength.h b/miniupnpc/codelength.h index 50d4606..ea0b005 100644 --- a/miniupnpc/codelength.h +++ b/miniupnpc/codelength.h @@ -1,7 +1,7 @@ /* $Id: codelength.h,v 1.3 2011/07/30 13:10:05 nanard Exp $ */ /* Project : miniupnp * Author : Thomas BERNARD - * copyright (c) 2005-2011 Thomas Bernard + * copyright (c) 2005-2015 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENCE file. */ #ifndef CODELENGTH_H_INCLUDED @@ -10,10 +10,30 @@ /* Encode length by using 7bit per Byte : * Most significant bit of each byte specifies that the * following byte is part of the code */ + +/* n : unsigned + * p : unsigned char * + */ #define DECODELENGTH(n, p) n = 0; \ do { n = (n << 7) | (*p & 0x7f); } \ while((*(p++)&0x80) && (n<(1<<25))); +/* n : unsigned + * READ : function/macro to read one byte (unsigned char) + */ +#define DECODELENGTH_READ(n, READ) \ + n = 0; \ + do { \ + unsigned char c; \ + READ(c); \ + n = (n << 7) | (c & 0x07f); \ + if(!(c&0x80)) break; \ + } while(n<(1<<25)); + +/* n : unsigned + * p : unsigned char * + * p_limit : unsigned char * + */ #define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \ n = 0; \ do { \ @@ -21,11 +41,14 @@ n = (n << 7) | (*(p) & 0x7f); \ } while((*((p)++)&0x80) && (n<(1<<25))); + +/* n : unsigned + * p : unsigned char * + */ #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 - +#endif /* CODELENGTH_H_INCLUDED */ diff --git a/miniupnpc/minissdpc.c b/miniupnpc/minissdpc.c index 017dabf..b4d3a8b 100644 --- a/miniupnpc/minissdpc.c +++ b/miniupnpc/minissdpc.c @@ -46,14 +46,59 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) { struct UPNPDev * tmp; struct UPNPDev * devlist = NULL; - unsigned char buffer[4*1024]; /* is that enough ? */ + unsigned char buffer[256]; ssize_t n; unsigned char * p; unsigned char * url; + unsigned int bufferindex; unsigned int i, ndev; unsigned int urlsize, stsize, usnsize, l; int s; struct sockaddr_un addr; +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT + struct timeval timeout; +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ + +/* macros used to read from unix socket */ +#define READ_BYTE_BUFFER(c) \ + if(bufferindex >= n) { \ + n = read(s, buffer, sizeof(buffer)); \ + if(n<=0) break; \ + bufferindex = 0; \ + } \ + c = buffer[bufferindex++]; + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif /* MIN */ + +#define READ_COPY_BUFFER(dst, len) \ + for(l = len, p = (unsigned char *)dst; l > 0; ) { \ + unsigned int lcopy; \ + if(bufferindex >= n) { \ + n = read(s, buffer, sizeof(buffer)); \ + if(n<=0) break; \ + bufferindex = 0; \ + } \ + lcopy = MIN(l, (n - bufferindex)); \ + memcpy(p, buffer + bufferindex, lcopy); \ + l -= lcopy; \ + p += lcopy; \ + bufferindex += lcopy; \ + } + +#define READ_DISCARD_BUFFER(len) \ + for(l = len; l > 0; ) { \ + unsigned int lcopy; \ + if(bufferindex >= n) { \ + n = read(s, buffer, sizeof(buffer)); \ + if(n<=0) break; \ + bufferindex = 0; \ + } \ + lcopy = MIN(l, (n - bufferindex)); \ + l -= lcopy; \ + bufferindex += lcopy; \ + } s = socket(AF_UNIX, SOCK_STREAM, 0); if(s < 0) @@ -62,6 +107,21 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) perror("socket(unix)"); return NULL; } +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT + /* setting a 3 seconds timeout */ + timeout.tv_sec = 3; + timeout.tv_usec = 0; + if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) + { + perror("setsockopt"); + } + timeout.tv_sec = 3; + timeout.tv_usec = 0; + if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) + { + perror("setsockopt"); + } +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ addr.sun_family = AF_UNIX; strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path)); /* TODO : check if we need to handle the EINTR */ @@ -85,6 +145,10 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) if(p + stsize > buffer + sizeof(buffer)) { /* devtype is too long ! */ +#ifdef DEBUG + fprintf(stderr, "devtype is too long ! stsize=%u sizeof(buffer)=%u\n", + stsize, (unsigned)sizeof(buffer)); +#endif /* DEBUG */ close(s); return NULL; } @@ -105,36 +169,66 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) return NULL; } ndev = buffer[0]; - p = buffer + 1; + bufferindex = 1; for(i = 0; i < ndev; i++) { - if(p+2>=buffer+sizeof(buffer)) + DECODELENGTH_READ(urlsize, READ_BYTE_BUFFER); + if(n<=0) { break; - DECODELENGTH(urlsize, p); - if(p+urlsize+2>=buffer+sizeof(buffer)) + } +#ifdef DEBUG + printf(" urlsize=%u", urlsize); +#endif /* DEBUG */ + url = malloc(urlsize); + if(url == NULL) { break; - url = p; - p += urlsize; - DECODELENGTH(stsize, p); - if(p+stsize+2>=buffer+sizeof(buffer)) + } + READ_COPY_BUFFER(url, urlsize); + if(n<=0) { + free(url); break; + } + DECODELENGTH_READ(stsize, READ_BYTE_BUFFER); + if(n<=0) { + free(url); + break; + } +#ifdef DEBUG + printf(" stsize=%u", stsize); +#endif /* DEBUG */ tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize); + if(tmp == NULL) { + free(url); + break; + } 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; + free(url); + url = NULL; + READ_COPY_BUFFER(tmp->buffer + urlsize + 1, stsize); + if(n<=0) { + free(tmp); + break; + } tmp->buffer[urlsize+1+stsize] = '\0'; tmp->scope_id = 0; /* default value. scope_id is not available with MiniSSDPd */ devlist = tmp; /* added for compatibility with recent versions of MiniSSDPd * >= 2007/12/19 */ - DECODELENGTH(usnsize, p); - p += usnsize; - if(p>buffer + sizeof(buffer)) + DECODELENGTH_READ(usnsize, READ_BYTE_BUFFER); + if(n<=0) { break; + } +#ifdef DEBUG + printf(" usnsize=%u\n", usnsize); +#endif /* DEBUG */ + READ_DISCARD_BUFFER(usnsize); + if(n<=0) { + break; + } } close(s); return devlist; diff --git a/miniupnpc/miniupnpc.c b/miniupnpc/miniupnpc.c index b08210e..87bde42 100644 --- a/miniupnpc/miniupnpc.c +++ b/miniupnpc/miniupnpc.c @@ -63,9 +63,6 @@ #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