5757
5858#include "common.h"
5959#include "nut_stdint.h"
60+ #include "nut_float.h"
6061#include "timehead.h"
6162#include "upsclient.h"
6263
@@ -154,9 +155,12 @@ typedef struct HOST_CERT_s {
154155} HOST_CERT_t ;
155156static HOST_CERT_t * upscli_find_host_cert (const char * hostname );
156157
157-
158+ /* Flag for SSL init */
158159static int upscli_initialized = 0 ;
159160
161+ /* 0 means no timeout in upscli_connect() */
162+ static struct timeval upscli_default_timeout = {0 , 0 };
163+
160164#ifdef WITH_OPENSSL
161165static SSL_CTX * ssl_ctx ;
162166#elif defined(WITH_NSS ) /* WITH_OPENSLL */
@@ -345,6 +349,11 @@ int upscli_init(int certverify, const char *certpath,
345349 NUT_UNUSED_VARIABLE (certpasswd );
346350#endif /* WITH_OPENSSL | WITH_NSS */
347351
352+ if (upscli_initialized == 1 ) {
353+ upslogx (LOG_WARNING , "upscli already initialized" );
354+ return -1 ;
355+ }
356+
348357 quiet_init_ssl = getenv ("NUT_QUIET_INIT_SSL" );
349358 if (quiet_init_ssl != NULL ) {
350359 if (* quiet_init_ssl == '\0'
@@ -357,11 +366,6 @@ int upscli_init(int certverify, const char *certpath,
357366 }
358367 }
359368
360- if (upscli_initialized == 1 ) {
361- upslogx (LOG_WARNING , "upscli already initialized" );
362- return -1 ;
363- }
364-
365369#ifdef WITH_OPENSSL
366370
367371#if OPENSSL_VERSION_NUMBER < 0x10100000L
@@ -1130,6 +1134,8 @@ int upscli_tryconnect(UPSCONN_t *ups, const char *host, uint16_t port, int flags
11301134 else {
11311135 /* Timeout */
11321136 v = -1 ;
1137+ ups -> upserror = UPSCLI_ERR_CONNFAILURE ;
1138+ ups -> syserrno = ETIMEDOUT ;
11331139 break ;
11341140 }
11351141 }
@@ -1150,6 +1156,14 @@ int upscli_tryconnect(UPSCONN_t *ups, const char *host, uint16_t port, int flags
11501156
11511157 if (v < 0 ) {
11521158 close (sock_fd );
1159+ /* if timeout, break out so client can continue */
1160+ /* match Linux behavior that updates timeout struct */
1161+ if (timeout != NULL &&
1162+ ups -> upserror == UPSCLI_ERR_CONNFAILURE &&
1163+ ups -> syserrno == ETIMEDOUT
1164+ ) {
1165+ break ;
1166+ }
11531167 continue ;
11541168 }
11551169
@@ -1234,7 +1248,12 @@ int upscli_tryconnect(UPSCONN_t *ups, const char *host, uint16_t port, int flags
12341248
12351249int upscli_connect (UPSCONN_t * ups , const char * host , uint16_t port , int flags )
12361250{
1237- return upscli_tryconnect (ups ,host ,port ,flags ,NULL );
1251+ struct timeval tv = upscli_default_timeout , * ptv = NULL ;
1252+ if (tv .tv_sec != 0 || tv .tv_usec != 0 ) {
1253+ /* By default, ptv==NULL for a blocking upscli_tryconnect() */
1254+ ptv = & tv ;
1255+ }
1256+ return upscli_tryconnect (ups , host , port , flags , ptv );
12381257}
12391258
12401259/* map upsd error strings back to upsclient internal numbers */
@@ -1846,6 +1865,113 @@ int upscli_ssl(UPSCONN_t *ups)
18461865 return 0 ;
18471866}
18481867
1868+ int upscli_set_default_timeout (const char * secs ) {
1869+ double fsecs ;
1870+
1871+ if (secs ) {
1872+ if (str_to_double (secs , & fsecs , 10 ) < 1 ) {
1873+ return -1 ;
1874+ }
1875+ if (d_equal (fsecs , 0.0 )) {
1876+ upscli_default_timeout .tv_sec = 0 ;
1877+ upscli_default_timeout .tv_usec = 0 ;
1878+ return 0 ;
1879+ }
1880+ if (fsecs < 0.0 ) {
1881+ return -1 ;
1882+ }
1883+ upscli_default_timeout .tv_sec = (time_t )fsecs ;
1884+ fsecs *= 1000000 ;
1885+ upscli_default_timeout .tv_usec =
1886+ (suseconds_t )((int )fsecs % 1000000 );
1887+ }
1888+ else {
1889+ upscli_default_timeout .tv_sec = 0 ;
1890+ upscli_default_timeout .tv_usec = 0 ;
1891+ }
1892+ return 0 ;
1893+ }
1894+
1895+ void upscli_get_default_timeout (struct timeval * ptv ) {
1896+ if (ptv ) {
1897+ * ptv = upscli_default_timeout ;
1898+ }
1899+ }
1900+
1901+ int upscli_init_default_timeout (const char * cli_secs , const char * config_secs , const char * default_secs ) {
1902+ const char * envvar_secs , * cause = "built-in" ;
1903+ int failed = 0 , applied = 0 ;
1904+
1905+ /* First the very default: blocking connections as we always had */
1906+ upscli_default_timeout .tv_sec = 0 ;
1907+ upscli_default_timeout .tv_usec = 0 ;
1908+
1909+ /* Then try a program's built-in default, if any */
1910+ if (default_secs ) {
1911+ if (upscli_set_default_timeout (default_secs ) < 0 ) {
1912+ upsdebugx (1 , "%s: default_secs='%s' value was not recognized, ignored" ,
1913+ __func__ , default_secs );
1914+ failed ++ ;
1915+ } else {
1916+ cause = "default_secs" ;
1917+ applied ++ ;
1918+ }
1919+ }
1920+
1921+ /* Then override with envvar setting, if any (and if its value is valid) */
1922+ envvar_secs = getenv ("NUT_DEFAULT_CONNECT_TIMEOUT" );
1923+ if (envvar_secs ) {
1924+ if (upscli_set_default_timeout (envvar_secs ) < 0 ) {
1925+ upsdebugx (1 , "%s: NUT_DEFAULT_CONNECT_TIMEOUT='%s' value was not recognized, ignored" ,
1926+ __func__ , envvar_secs );
1927+ failed ++ ;
1928+ } else {
1929+ cause = "envvar_secs" ;
1930+ applied ++ ;
1931+ }
1932+ }
1933+
1934+ /* Then override with config-file setting, if any (and if its value is valid) */
1935+ if (config_secs ) {
1936+ if (upscli_set_default_timeout (config_secs ) < 0 ) {
1937+ upsdebugx (1 , "%s: config_secs='%s' value was not recognized, ignored" ,
1938+ __func__ , config_secs );
1939+ failed ++ ;
1940+ } else {
1941+ cause = "config_secs" ;
1942+ applied ++ ;
1943+ }
1944+ }
1945+
1946+ /* Then override with command-line setting, if any (and if its value is valid) */
1947+ if (cli_secs ) {
1948+ if (upscli_set_default_timeout (cli_secs ) < 0 ) {
1949+ upsdebugx (1 , "%s: cli_secs='%s' value was not recognized, ignored" ,
1950+ __func__ , cli_secs );
1951+ failed ++ ;
1952+ } else {
1953+ cause = "cli_secs" ;
1954+ applied ++ ;
1955+ }
1956+ }
1957+
1958+ upsdebugx (1 , "%s: upscli_default_timeout=%" PRIiMAX
1959+ ".%06" PRIiMAX " sec assigned from: %s" ,
1960+ __func__ , (intmax_t )upscli_default_timeout .tv_sec ,
1961+ (intmax_t )upscli_default_timeout .tv_usec , cause );
1962+
1963+ /* Some non-built-in value was OK */
1964+ if (applied )
1965+ return 0 ;
1966+
1967+ /* None of provided non-built-in values was OK */
1968+ if (failed )
1969+ return -1 ;
1970+
1971+ /* At least we have the built-in default and nothing failed */
1972+ return 0 ;
1973+ }
1974+
18491975/* Pick up the methods below from libcommon and expose in the NUT client API */
18501976int upscli_str_contains_token (const char * string , const char * token )
18511977{
0 commit comments