diff --git a/ChangeLog b/ChangeLog index 9c7534f60..b98ae966d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2007-10-24 Julien Blache + * backends/net.c: Add an optional connection timeout for the + initial connection to saned. Based on a patch from Ryan Duryea + . Bump net backend version to 1.0.14. + * backends/net.conf.in: Add the new connect_timeout option and + adjust comments accordingly. + * doc/sane-net.man: Document the connect_timeout option and the + SANE_NET_TIMEOUT environment variable. + 2007-10-19 Stephane Voltz * tools/check-usb-chip.c: added detection of rts8801 and diff --git a/backend/net.c b/backend/net.c index 0aadbbbed..fdd91ce35 100644 --- a/backend/net.c +++ b/backend/net.c @@ -89,13 +89,13 @@ #if defined (HAVE_GETADDRINFO) && defined (HAVE_GETNAMEINFO) # define NET_USES_AF_INDEP # ifdef ENABLE_IPV6 -# define NET_VERSION "1.0.13 (AF-indep+IPv6)" +# define NET_VERSION "1.0.14 (AF-indep+IPv6)" # else -# define NET_VERSION "1.0.13 (AF-indep)" +# define NET_VERSION "1.0.14 (AF-indep)" # endif /* ENABLE_IPV6 */ #else # undef ENABLE_IPV6 -# define NET_VERSION "1.0.13" +# define NET_VERSION "1.0.14" #endif /* HAVE_GETADDRINFO && HAVE_GETNAMEINFO */ static SANE_Auth_Callback auth_callback; @@ -105,6 +105,7 @@ static const SANE_Device **devlist; static int client_big_endian; /* 1 == big endian; 0 == little endian */ static int server_big_endian; /* 1 == big endian; 0 == little endian */ static int depth; /* bits per pixel */ +static int connect_timeout = -1; /* timeout for connection to saned */ #ifndef NET_USES_AF_INDEP static int saned_port; @@ -290,6 +291,7 @@ connect_dev (Net_Device * dev) int on = 1; int level = -1; #endif + struct timeval tv; int i; @@ -317,6 +319,18 @@ connect_dev (Net_Device * dev) continue; } + /* Set SO_SNDTIMEO for the connection to saned */ + if (connect_timeout > 0) + { + tv.tv_sec = connect_timeout; + tv.tv_usec = 0; + + if (setsockopt (dev->ctl, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) + { + DBG (1, "connect_dev: [%d] failed to set SO_SNDTIMEO (%s)\n", i, strerror (errno)); + } + } + if (connect (dev->ctl, addrp->ai_addr, addrp->ai_addrlen) < 0) { DBG (1, "connect_dev: [%d] failed to connect (%s)\n", i, strerror (errno)); @@ -348,6 +362,7 @@ connect_dev (Net_Device * dev) int on = 1; int level = -1; #endif + struct timeval tv; DBG (2, "connect_dev: trying to connect to %s\n", dev->name); @@ -369,6 +384,19 @@ connect_dev (Net_Device * dev) sin = (struct sockaddr_in *) &dev->addr; sin->sin_port = saned_port; + + /* Set SO_SNDTIMEO for the connection to saned */ + if (connect_timeout > 0) + { + tv.tv_sec = connect_timeout; + tv.tv_usec = 0; + + if (setsockopt (dev->ctl, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) + { + DBG (1, "connect_dev: [%d] failed to set SO_SNDTIMEO (%s)\n", i, strerror (errno)); + } + } + if (connect (dev->ctl, &dev->addr, sizeof (dev->addr)) < 0) { DBG (1, "connect_dev: failed to connect (%s)\n", strerror (errno)); @@ -378,6 +406,18 @@ connect_dev (Net_Device * dev) DBG (3, "connect_dev: connection succeeded\n"); #endif /* NET_USES_AF_INDEP */ + /* We're connected now, so reset SO_SNDTIMEO to the default value of 0 */ + if (connect_timeout > 0) + { + tv.tv_sec = 0; + tv.tv_usec = 0; + + if (setsockopt (dev->ctl, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) + { + DBG (1, "connect_dev: [%d] failed to reset SO_SNDTIMEO (%s)\n", i, strerror (errno)); + } + } + #ifdef TCP_NODELAY # ifdef SOL_TCP level = SOL_TCP; @@ -620,6 +660,7 @@ SANE_Status sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) { char device_name[PATH_MAX]; + const char *optval; const char *env; size_t len; FILE *fp; @@ -693,6 +734,29 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) if (!len) continue; /* ignore empty lines */ + /* + * Check for net backend options. + * Anything that isn't an option is a saned host. + */ + if (strstr(device_name, "connect_timeout") != NULL) + { + /* Look for the = sign; if it's not there, error out */ + optval = strchr(device_name, '='); + + if (!optval) + continue; + + optval = sanei_config_skip_whitespace (++optval); + if ((optval != NULL) && (*optval != '\0')) + { + connect_timeout = atoi(optval); + + DBG (2, "sane_init: connect timeout set to %d seconds\n", connect_timeout); + } + + continue; + } + DBG (2, "sane_init: trying to add %s\n", device_name); add_device (device_name, 0); } @@ -747,6 +811,15 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) DBG (1, "sane_init: not enough memory to duplicate " "environment variable\n"); } + + DBG (2, "sane_init: evaluating environment variable SANE_NET_TIMEOUT\n"); + env = getenv ("SANE_NET_TIMEOUT"); + if (env) + { + connect_timeout = atoi(env); + DBG (2, "sane_init: connect timeout set to %d seconds from env\n", connect_timeout); + } + DBG (2, "sane_init: done\n"); return SANE_STATUS_GOOD; } diff --git a/backend/net.conf.in b/backend/net.conf.in index bca14897d..f55f29c0d 100644 --- a/backend/net.conf.in +++ b/backend/net.conf.in @@ -1,4 +1,13 @@ -# This is the net config file. Each line names a host to attach to. +# This is the net backend config file. + +## net backend options +# Timeout for the initial connection to saned. This will prevent the backend +# from blocking for several minutes trying to connect to an unresponsive +# saned host (network outage, host down, ...). Value in seconds. +# connect_timeout = 60 + +## saned hosts +# Each line names a host to attach to. # If you list "localhost" then your backends can be accessed either # directly or through the net backend. Going through the net backend # may be necessary to access devices that need special privileges. diff --git a/doc/descriptions/net.desc b/doc/descriptions/net.desc index 71c6fa5e4..1807c494d 100644 --- a/doc/descriptions/net.desc +++ b/doc/descriptions/net.desc @@ -1,5 +1,5 @@ :backend "net" ; name of backend -:version "1.0.13" +:version "1.0.14" :manpage "sane-net" :url "http://www.penguin-breeder.org/?page=sane-net" diff --git a/doc/sane-net.man b/doc/sane-net.man index 691e9b798..9abd311c9 100644 --- a/doc/sane-net.man +++ b/doc/sane-net.man @@ -1,4 +1,4 @@ -.TH sane-net 5 "8 Oct 2002" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy" +.TH sane-net 5 "24 Oct 2007" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy" .IX sane-net .SH NAME sane-net \- SANE network backend @@ -35,10 +35,24 @@ An IPv6 address can be specified enclosed in square brackets: .IR [::1] : device .RE .SH CONFIGURATION -The contents of the +The .IR net.conf -file is a list of host names (or IP addresses) that should be contacted for -scan requests. Empty lines and lines starting with a hash mark (#) are +file contains both backend options and a list of host names (or IP +addresses) that should be contacted for scan requests. Anything that +isn't one of the options listed below will be treated as an host name. +.PP +.TP +.B connect_timeout = nsecs +Timeout (in seconds) for the initial connection to the +.I saned +server. This will prevent the backend from blocking for several +minutes trying to connect to an unresponsive +.I saned +host (network outage, host down, ...). The environment variable +.B SANE_NET_TIMEOUT +can also be used to specify the timeout at runtime. +.PP +Empty lines and lines starting with a hash mark (#) are ignored. Note that IPv6 addresses in this file do not need to be enclosed in square brackets. A sample configuration file is shown below: .PP @@ -121,6 +135,11 @@ to "/tmp/config:" would result in directories "tmp/config", ".", and A colon-separated list of host names or IP addresses to be contacted by this backend. .TP +.B SANE_NET_TIMEOUT +Number of seconds to wait for a response from the +.I saned +server for the initial connection request. +.TP .B SANE_DEBUG_NET If the library was compiled with debug support enabled, this environment variable controls the debug level for this backend. E.g.,