From cffba15387cb7e8cde05886a35ee69c00a19782b Mon Sep 17 00:00:00 2001 From: Konstantin Tokarev Date: Thu, 23 Jul 2015 16:22:23 +0300 Subject: [PATCH] Split getDevicesFromMiniSSDPD into 4 steps to allow reuse of local socket. It allows allows client application to use event loop instead of blocking in read() while waiting for server reply. --- miniupnpc/minissdpc.c | 96 ++++++++++++++++++++++++++++++++----------- miniupnpc/minissdpc.h | 31 +++++++++++++- miniupnpc/miniupnpc.c | 2 +- 3 files changed, 102 insertions(+), 27 deletions(-) diff --git a/miniupnpc/minissdpc.c b/miniupnpc/minissdpc.c index 9ea82d7..fa54664 100644 --- a/miniupnpc/minissdpc.c +++ b/miniupnpc/minissdpc.c @@ -42,23 +42,28 @@ struct sockaddr_un { #include "codelength.h" struct UPNPDev * -getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) +getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error) { - struct UPNPDev * tmp; - struct UPNPDev * devlist = NULL; - unsigned char buffer[256]; - ssize_t n; - unsigned char * p; - unsigned char * url; - unsigned char * st; - unsigned int bufferindex; - unsigned int i, ndev; - unsigned int urlsize, stsize, usnsize, l; + struct UPNPDev * devlist; int s; - struct sockaddr_un addr; -#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT - struct timeval timeout; -#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ + int res; + + s = connectToMiniSSDPD(socketpath); + if (s < 0) { + if (error) + *error = s; + return NULL; + } + res = requestDevicesFromMiniSSDPD(s, devtype); + if (res < 0) { + if (error) + *error = res; + return NULL; + } + devlist = receiveDevicesFromMiniSSDPD(s, error); + disconnectFromMiniSSDPD(s); + return devlist; +} /* macros used to read from unix socket */ #define READ_BYTE_BUFFER(c) \ @@ -101,12 +106,21 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) bufferindex += lcopy; \ } +int +connectToMiniSSDPD(const char * socketpath) +{ + int s; + struct sockaddr_un addr; +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT + struct timeval timeout; +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ + s = socket(AF_UNIX, SOCK_STREAM, 0); if(s < 0) { /*syslog(LOG_ERR, "socket(unix): %m");*/ perror("socket(unix)"); - return NULL; + return MINISSDPC_SOCKET_ERROR; } #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT /* setting a 3 seconds timeout */ @@ -129,9 +143,26 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) { /*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/ - close(s); - return NULL; + return MINISSDPC_SOCKET_ERROR; } + return s; +} + +int +disconnectFromMiniSSDPD(int s) +{ + if (close(s) < 0) + return MINISSDPC_SOCKET_ERROR; + return MINISSDPC_SUCCESS; +} + +int +requestDevicesFromMiniSSDPD(int s, const char * devtype) +{ + unsigned char buffer[256]; + unsigned char * p; + unsigned int stsize, l; + stsize = strlen(devtype); if(stsize == 8 && 0 == memcmp(devtype, "ssdp:all", 8)) { @@ -150,8 +181,7 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) fprintf(stderr, "devtype is too long ! stsize=%u sizeof(buffer)=%u\n", stsize, (unsigned)sizeof(buffer)); #endif /* DEBUG */ - close(s); - return NULL; + return MINISSDPC_INVALID_INPUT; } memcpy(p, devtype, stsize); p += stsize; @@ -159,14 +189,31 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) { /*syslog(LOG_ERR, "write(): %m");*/ perror("minissdpc.c: write()"); - close(s); - return NULL; + return MINISSDPC_SOCKET_ERROR; } + return MINISSDPC_SUCCESS; +} + +struct UPNPDev * +receiveDevicesFromMiniSSDPD(int s, int * error) +{ + struct UPNPDev * tmp; + struct UPNPDev * devlist = NULL; + unsigned char buffer[256]; + ssize_t n; + unsigned char * p; + unsigned char * url; + unsigned char * st; + unsigned int bufferindex; + unsigned int i, ndev; + unsigned int urlsize, stsize, usnsize, l; + n = read(s, buffer, sizeof(buffer)); if(n<=0) { perror("minissdpc.c: read()"); - close(s); + if (error) + *error = MINISSDPC_SOCKET_ERROR; return NULL; } ndev = buffer[0]; @@ -244,7 +291,8 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) tmp->scope_id = 0; /* default value. scope_id is not available with MiniSSDPd */ devlist = tmp; } - close(s); + if (error) + *error = MINISSDPC_SUCCESS; return devlist; } diff --git a/miniupnpc/minissdpc.h b/miniupnpc/minissdpc.h index 2516f48..089106e 100644 --- a/miniupnpc/minissdpc.h +++ b/miniupnpc/minissdpc.h @@ -8,8 +8,35 @@ #ifndef MINISSDPC_H_INCLUDED #define MINISSDPC_H_INCLUDED -struct UPNPDev * -getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath); +#include "miniupnpc_declspec.h" + +/* error codes : */ +#define MINISSDPC_SUCCESS (0) +#define MINISSDPC_SOCKET_ERROR (-101) +#define MINISSDPC_INVALID_INPUT (-103) + +#ifdef __cplusplus +extern "C" { +#endif + +MINIUPNP_LIBSPEC struct UPNPDev * +getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error); + +MINIUPNP_LIBSPEC int +connectToMiniSSDPD(const char * socketpath); + +MINIUPNP_LIBSPEC int +disconnectFromMiniSSDPD(int fd); + +MINIUPNP_LIBSPEC int +requestDevicesFromMiniSSDPD(int fd, const char * devtype); + +MINIUPNP_LIBSPEC struct UPNPDev * +receiveDevicesFromMiniSSDPD(int fd, int * error); + +#ifdef __cplusplus +} +#endif #endif diff --git a/miniupnpc/miniupnpc.c b/miniupnpc/miniupnpc.c index 60fe02a..4c83b0a 100644 --- a/miniupnpc/miniupnpc.c +++ b/miniupnpc/miniupnpc.c @@ -394,7 +394,7 @@ upnpDiscoverDevices(const char * const deviceTypes[], struct UPNPDev * minissdpd_devlist; int only_rootdevice = 1; minissdpd_devlist = getDevicesFromMiniSSDPD(deviceTypes[deviceIndex], - minissdpdsock); + minissdpdsock, 0); if(minissdpd_devlist) { #ifdef DEBUG printf("returned by MiniSSDPD: %s\t%s\n",