peutipoix
Joined: 03 Jun 2009 Posts: 3
|
Posted: Tue Jun 30, 2009 7:17 am Post subject: |
|
|
Hi,
I experienced some annoyance when discovering IGD on my network.
The way I'm using it to get info on IGD is as follows (through python bindings):
1 - discover() : it calls upnpDiscover() and fills a UPnP control points list "devlist"
2 - selectigd() : UPNP_GetValidIGD() tries to get XML description data for every device in this devlist and detects which one has IGD state
3 - get IGD info with lanaddr(), externalipaddress(), connectiontype()...
My problem comes from a an UPnP-AV server embedded in a Synology NAS DS508.
Here is data sent back by the Synology UPnP-AV server:
Code: |
Location http://169.254.131.132:50001/
UDN uuid:13814000-1dd2-11b2-8000-01113203c37f
Type urn:schemas-upnp-org:device:MediaServer:1
Base URL http://169.254.131.132:50001/
Friendly Name SynologyDS508
Manufacturer Synology Inc
Manufacturer URL http://www.synology.com/
Model Description Synology Media Server
Model Name UPnP/AV 1.0 Compliant Media Server
Model Number
Model URL http://www.synology.com/
Serial Number 13814000-1dd2-11b2-8000-01113203c37f
UPC
|
Just have a look at the answered IP address in "Location" item, it does not correspond to an IP address from my local network 192.168.8.X
As this IP is not accessible (not "pingable"), when UPNP_GetValidIGD() calls miniwget_getaddr() to get XML description for this device, it waits on connect() until it falls in timeout... and it waits quite a long time, some dozens of seconds...
Of course, it affects Transmission's startup too, and it was quite irritating.
Well, I guess an easy workaround would be to disable UPnP-AV server on the Synology NAS... I do not know exactly why this kind of IP address is returned, so I consider this as a bug in Synology's server, but maybe it is not...
Personnally, I solved this problem using a non-blocking socket in miniwget_getaddr(), (cf patch below... ) and maybe it would improves miniupnpc robutness to add a reasonable timeout in miniwget_getaddr().
What do you think of this problem?
Regards,
Olivier
PS: miniupnp is a great job, thanks...
Here is a patch proposal for miniwget.c.
Sorry, I did not removed debug messages...
Code: |
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include "miniupnpcstrings.h"
+#define SOCKET_CONNECT_DELAY_SEC 2
+
+#define PRINT_SOCKET_ERROR(x, y) fprintf(stderr, "socket error %s: %s/n", x, y)
+
/* miniwget2() :
* */
static void *
@@ -41,7 +50,11 @@
int * size, char * addr_str, int addr_str_len)
{
char buf[2048];
- int s;
+ int s, res, valopt;
+ socklen_t lon;
+ long arg;
+ struct timeval tv;
+ fd_set myset;
struct sockaddr_in dest;
struct hostent *hp;
*size = 0;
@@ -57,16 +70,86 @@
s = socket(PF_INET, SOCK_STREAM, 0);
if(s < 0)
{
- perror("socket");
+ PRINT_SOCKET_ERROR("", "socket creation failed");
return NULL;
}
dest.sin_family = AF_INET;
dest.sin_port = htons(port);
- if(connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in))<0)
+
+ /* Set non-blocking socket */
+ if( (arg = fcntl(s, F_GETFL, NULL)) < 0)
+ {
+ PRINT_SOCKET_ERROR("in fcntl(..., F_GETFL)", strerror(errno));
+ closesocket(s);
+ return NULL;
+ }
+ arg |= O_NONBLOCK;
+ if( fcntl(s, F_SETFL, arg) < 0)
+ {
+ PRINT_SOCKET_ERROR("in fcntl(..., F_SETFL)", strerror(errno));
+ closesocket(s);
+ }
+
+ res = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in));
+ if( (res < 0) && (errno == EINPROGRESS) )
{
- perror("connect");
+ do
+ {
+ tv.tv_sec = SOCKET_CONNECT_DELAY_SEC;
+ tv.tv_usec = 0;
+ FD_ZERO(&myset);
+ FD_SET(s, &myset);
+ res = select(s+1, NULL, &myset, NULL, &tv);
+ if (res < 0 && errno != EINTR)
+ {
+ PRINT_SOCKET_ERROR("in select()", strerror(errno));
+ closesocket(s);
+ return NULL;
+ }
+ else if (res > 0)
+ {
+ /* Socket selected for write */
+ lon = sizeof(int);
+ if (getsockopt(s, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon) < 0)
+ {
+ PRINT_SOCKET_ERROR("in getsockopt()", strerror(errno));
+ closesocket(s);
+ return NULL;
+ }
+ /* Check the value returned... */
+ if (valopt)
+ {
+ PRINT_SOCKET_ERROR("in delayed connection()", strerror(valopt));
+ closesocket(s);
+ return NULL;
+ }
+ break;
+ }
+ else
+ {
+ PRINT_SOCKET_ERROR("timeout in select() - Cancelling!\n", "");
+ closesocket(s);
+ return NULL;
+ }
+ } while (1);
+ }
+ else
+ {
+ PRINT_SOCKET_ERROR("in connect()", strerror(errno));
+ }
+ /* Set to blocking mode again... */
+ if( (arg = fcntl(s, F_GETFL, NULL)) < 0)
+ {
+ PRINT_SOCKET_ERROR("in fcntl(..., F_GETFL)", strerror(errno));
closesocket(s);
return NULL;
+ }
+ arg &= (~O_NONBLOCK);
+ if( fcntl(s, F_SETFL, arg) < 0)
+ {
+ PRINT_SOCKET_ERROR("in fcntl(..., F_SETFL)", strerror(errno));
+ closesocket(s);
+ return NULL;
}
|
|
|