miniupnp.tuxfamily.org Forum Index miniupnp.tuxfamily.org
The forum about miniupnp and libnatpmp
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Add a timeout in selectigd()

 
Post new topic   Reply to topic    miniupnp.tuxfamily.org Forum Index -> miniupnpc Bugs
View previous topic :: View next topic  
Author Message
peutipoix



Joined: 03 Jun 2009
Posts: 3

PostPosted: Tue Jun 30, 2009 7:16 am    Post subject: Add a timeout in selectigd() Reply with quote

Useless first post...

[quote]
You must have 1 posts before you can post URL's/Links.
[/quote]
Back to top
View user's profile Send private message
peutipoix



Joined: 03 Jun 2009
Posts: 3

PostPosted: Tue Jun 30, 2009 7:17 am    Post subject: Reply with quote

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;
    }
Back to top
View user's profile Send private message
miniupnp
Site Admin


Joined: 14 Apr 2007
Posts: 1525

PostPosted: Sat Jul 04, 2009 5:51 pm    Post subject: Reply with quote

interesting...
about the ip address 169.254.131.132, such ip addresses are used by devices when DHCP configuration failed. You should check that this device is powered on after the DHCP server on the network is available.
_________________
Main miniUPnP author.
http://miniupnp.tuxfamily.org/
Back to top
View user's profile Send private message Visit poster's website
peutipoix



Joined: 03 Jun 2009
Posts: 3

PostPosted: Mon Jul 20, 2009 4:12 pm    Post subject: Reply with quote

I didn't know usage of this particular IP address... and it seems that you've pointed out the problem: I do not observe this behaviour anymore if I respect the order DHCPserver -> NAS.

arf... I have been particularly unlucky to reboot my NAS while the DHCP was down...

Anyway... thanks!!
Back to top
View user's profile Send private message
miniupnp
Site Admin


Joined: 14 Apr 2007
Posts: 1525

PostPosted: Tue Jul 21, 2009 8:55 am    Post subject: Reply with quote

The RFC 3330 http://www.rfc-editor.org/rfc/rfc3330.txt and 3927 http://tools.ietf.org/html/rfc3927 give details about the 169.254.0.0/16 address class.
_________________
Main miniUPnP author.
http://miniupnp.tuxfamily.org/
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    miniupnp.tuxfamily.org Forum Index -> miniupnpc Bugs All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group
Protected by Anti-Spam ACP
© 2007 Thomas Bernard, author of MiniUPNP.