From: Javier Viguera <javier.viguera@digi.com>
Date: Tue, 14 May 2019 16:44:03 +0200
Subject: [PATCH] connectivity: add config option for response timeout

Instead of the 20 seconds hardcoded currently in the code, allow to
configure the response timeout in the connectivity section of the main
NetworkManager config file.

Signed-off-by: Javier Viguera <javier.viguera@digi.com>
Signed-off-by: Gabriel Valcazar <gabriel.valcazar@digi.com>
---
 src/core/nm-config-data.c  | 37 +++++++++++++++++++++++++++++++++++++
 src/core/nm-config-data.h  |  2 ++
 src/core/nm-config.c       | 15 +++++++++++++++
 src/core/nm-config.h       |  1 +
 src/core/nm-connectivity.c | 12 +++++++++++-
 5 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/src/core/nm-config-data.c b/src/core/nm-config-data.c
index ddb7787feffa..e1774ead4090 100644
--- a/src/core/nm-config-data.c
+++ b/src/core/nm-config-data.c
@@ -62,6 +62,7 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_CONFIG_MAIN_FILE,
                                   PROP_CONNECTIVITY_ENABLED,
                                   PROP_CONNECTIVITY_URI,
                                   PROP_CONNECTIVITY_INTERVAL,
+                                  PROP_CONNECTIVITY_TIMEOUT,
                                   PROP_CONNECTIVITY_RESPONSE,
                                   PROP_NO_AUTO_DEFAULT, );
 
@@ -86,6 +87,7 @@ typedef struct {
         char    *uri;
         char    *response;
         guint    interval;
+        guint    timeout;
     } connectivity;
 
     int autoconnect_retries_default;
@@ -298,6 +300,14 @@ nm_config_data_get_connectivity_interval(const NMConfigData *self)
     return NM_CONFIG_DATA_GET_PRIVATE(self)->connectivity.interval;
 }
 
+guint
+nm_config_data_get_connectivity_timeout(const NMConfigData *self)
+{
+    g_return_val_if_fail(self, 0);
+
+    return NM_CONFIG_DATA_GET_PRIVATE(self)->connectivity.timeout;
+}
+
 const char *
 nm_config_data_get_connectivity_response(const NMConfigData *self)
 {
@@ -1891,6 +1901,8 @@ nm_config_data_diff(NMConfigData *old_data, NMConfigData *new_data)
             != nm_config_data_get_connectivity_enabled(new_data)
         || nm_config_data_get_connectivity_interval(old_data)
                != nm_config_data_get_connectivity_interval(new_data)
+        || nm_config_data_get_connectivity_timeout(old_data)
+               != nm_config_data_get_connectivity_timeout(new_data)
         || !nm_streq0(nm_config_data_get_connectivity_uri(old_data),
                       nm_config_data_get_connectivity_uri(new_data))
         || !nm_streq0(nm_config_data_get_connectivity_response(old_data),
@@ -1964,6 +1976,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
     case PROP_CONNECTIVITY_INTERVAL:
         g_value_set_uint(value, nm_config_data_get_connectivity_interval(self));
         break;
+    case PROP_CONNECTIVITY_TIMEOUT:
+        g_value_set_uint(value, nm_config_data_get_connectivity_timeout(self));
+        break;
     case PROP_CONNECTIVITY_RESPONSE:
         g_value_set_string(value, nm_config_data_get_connectivity_response(self));
         break;
@@ -2106,6 +2121,19 @@ constructed(GObject *object)
                                      NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL);
     g_free(str);
 
+    /* On missing config value, fallback to the default value */
+    str = g_key_file_get_string(priv->keyfile,
+                                NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY,
+                                "timeout",
+                                NULL);
+    priv->connectivity.timeout =
+        _nm_utils_ascii_str_to_int64(str,
+                                     10,
+                                     1,
+                                     G_MAXUINT,
+                                     NM_CONFIG_DEFAULT_CONNECTIVITY_TIMEOUT);
+    g_free(str);
+
     priv->dns_mode   = nm_strstrip(g_key_file_get_string(priv->keyfile,
                                                        NM_CONFIG_KEYFILE_GROUP_MAIN,
                                                        NM_CONFIG_KEYFILE_KEY_MAIN_DNS,
@@ -2305,6 +2333,15 @@ nm_config_data_class_init(NMConfigDataClass *config_class)
                           0,
                           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
+    obj_properties[PROP_CONNECTIVITY_TIMEOUT] =
+        g_param_spec_uint(NM_CONFIG_DATA_CONNECTIVITY_TIMEOUT,
+                          "",
+                          "",
+                          0,
+                          G_MAXUINT,
+                          0,
+                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
     obj_properties[PROP_CONNECTIVITY_RESPONSE] =
         g_param_spec_string(NM_CONFIG_DATA_CONNECTIVITY_RESPONSE,
                             "",
diff --git a/src/core/nm-config-data.h b/src/core/nm-config-data.h
index fdc7e1fc3d2b..fa7a2814819e 100644
--- a/src/core/nm-config-data.h
+++ b/src/core/nm-config-data.h
@@ -46,6 +46,7 @@ typedef enum {
 #define NM_CONFIG_DATA_CONNECTIVITY_ENABLED  "connectivity-enabled"
 #define NM_CONFIG_DATA_CONNECTIVITY_URI      "connectivity-uri"
 #define NM_CONFIG_DATA_CONNECTIVITY_INTERVAL "connectivity-interval"
+#define NM_CONFIG_DATA_CONNECTIVITY_TIMEOUT  "connectivity-timeout"
 #define NM_CONFIG_DATA_CONNECTIVITY_RESPONSE "connectivity-response"
 #define NM_CONFIG_DATA_NO_AUTO_DEFAULT       "no-auto-default"
 #define NM_CONFIG_DATA_DNS_MODE              "dns"
@@ -171,6 +172,7 @@ char      **nm_config_data_get_plugins(const NMConfigData *config_data, gboolean
 gboolean    nm_config_data_get_connectivity_enabled(const NMConfigData *config_data);
 const char *nm_config_data_get_connectivity_uri(const NMConfigData *config_data);
 guint       nm_config_data_get_connectivity_interval(const NMConfigData *config_data);
+guint       nm_config_data_get_connectivity_timeout(const NMConfigData *config_data);
 const char *nm_config_data_get_connectivity_response(const NMConfigData *config_data);
 
 int nm_config_data_get_autoconnect_retries_default(const NMConfigData *config_data);
diff --git a/src/core/nm-config.c b/src/core/nm-config.c
index 60a2f1df53b2..864eadd9dd6c 100644
--- a/src/core/nm-config.c
+++ b/src/core/nm-config.c
@@ -45,6 +45,7 @@ struct NMConfigCmdLineOptions {
      * set or not via GOptionEntry
      */
     int   connectivity_interval;
+    int   connectivity_timeout;
     char *connectivity_response;
 
     /* @first_start is not provided by command line. It is a convenient hack
@@ -479,6 +480,7 @@ _nm_config_cmd_line_options_clear(NMConfigCmdLineOptions *cli)
     nm_clear_g_free(&cli->connectivity_uri);
     nm_clear_g_free(&cli->connectivity_response);
     cli->connectivity_interval = -1;
+    cli->connectivity_timeout = -1;
     cli->first_start           = FALSE;
 }
 
@@ -502,6 +504,7 @@ _nm_config_cmd_line_options_copy(const NMConfigCmdLineOptions *cli, NMConfigCmdL
     dst->connectivity_uri      = g_strdup(cli->connectivity_uri);
     dst->connectivity_response = g_strdup(cli->connectivity_response);
     dst->connectivity_interval = cli->connectivity_interval;
+    dst->connectivity_timeout = cli->connectivity_timeout;
     dst->first_start           = cli->first_start;
 }
 
@@ -652,6 +655,13 @@ nm_config_cmd_line_options_add_to_entries(NMConfigCmdLineOptions *cli, GOptionCo
          &cli->connectivity_interval,
          N_("The interval between connectivity checks (in seconds)"),
          G_STRINGIFY(NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL)},
+        {"connectivity-timeout",
+         0,
+         G_OPTION_FLAG_HIDDEN,
+         G_OPTION_ARG_INT,
+         &cli->connectivity_timeout,
+         N_("The timeout for the connectivity checks (in seconds)"),
+         G_STRINGIFY(NM_CONFIG_DEFAULT_CONNECTIVITY_TIMEOUT)},
         {"connectivity-response",
          0,
          G_OPTION_FLAG_HIDDEN,
@@ -1412,6 +1422,11 @@ read_entire_config(const NMConfigCmdLineOptions *cli,
                                    NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY,
                                    "interval",
                                    cli->connectivity_interval);
+        if (cli->connectivity_timeout >= 0)
+            g_key_file_set_integer(keyfile,
+                                   NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY,
+                                   "timeout",
+                                   cli->connectivity_timeout);
         if (cli->connectivity_response && cli->connectivity_response[0])
             g_key_file_set_string(keyfile,
                                   NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY,
diff --git a/src/core/nm-config.h b/src/core/nm-config.h
index 2c23ff200e1d..58c8b3e67712 100644
--- a/src/core/nm-config.h
+++ b/src/core/nm-config.h
@@ -26,6 +26,7 @@
 #define NM_CONFIG_SIGNAL_CONFIG_CHANGED "config-changed"
 
 #define NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL 300
+#define NM_CONFIG_DEFAULT_CONNECTIVITY_TIMEOUT 20
 #define NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE "NetworkManager is online" /* NOT LOCALIZED */
 
 typedef struct NMConfigCmdLineOptions NMConfigCmdLineOptions;
diff --git a/src/core/nm-connectivity.c b/src/core/nm-connectivity.c
index 7199c9a242ad..46f5a8da1d9f 100644
--- a/src/core/nm-connectivity.c
+++ b/src/core/nm-connectivity.c
@@ -108,6 +108,7 @@ typedef struct {
     CList      completed_handles_lst_head;
     NMConfig  *config;
     ConConfig *con_config;
+    guint      timeout;
     guint      interval;
 
     bool enabled : 1;
@@ -642,6 +643,7 @@ _idle_cb(gpointer user_data)
 static void
 do_curl_request(NMConnectivityCheckHandle *cb_data)
 {
+    NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (cb_data->self);
     CURLM *mhandle;
     CURL  *ehandle;
     long   resolve;
@@ -662,7 +664,7 @@ do_curl_request(NMConnectivityCheckHandle *cb_data)
     cb_data->concheck.curl_mhandle    = mhandle;
     cb_data->concheck.curl_ehandle    = ehandle;
     cb_data->concheck.request_headers = curl_slist_append(NULL, "Connection: close");
-    cb_data->timeout_id               = g_timeout_add_seconds(20, _timeout_cb, cb_data);
+    cb_data->timeout_id               = g_timeout_add_seconds(priv->timeout, _timeout_cb, cb_data);
 
     curl_multi_setopt(mhandle, CURLMOPT_SOCKETFUNCTION, multi_socket_cb);
     curl_multi_setopt(mhandle, CURLMOPT_SOCKETDATA, cb_data);
@@ -1044,6 +1046,7 @@ update_config(NMConnectivity *self, NMConfigData *config_data)
 {
     NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE(self);
     guint                  interval;
+    guint                  timeout;
     gboolean               enabled;
     gboolean               changed      = FALSE;
     const char            *cur_uri      = priv->con_config ? priv->con_config->uri : NULL;
@@ -1130,6 +1133,13 @@ update_config(NMConnectivity *self, NMConfigData *config_data)
         changed       = TRUE;
     }
 
+    /* Set the timeout */
+    timeout = nm_config_data_get_connectivity_timeout(config_data);
+    if (priv->timeout != timeout) {
+        priv->timeout = timeout;
+        changed = TRUE;
+    }
+
     if (changed)
         g_signal_emit(self, signals[CONFIG_CHANGED], 0);
 }
