mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-07-22 18:54:36 +00:00
connectivity: merge branch 'th/connectivity-busy-loop-fix'
This commit is contained in:
commit
057c7b94a0
|
@ -195,7 +195,7 @@ cb_data_free (NMConnectivityCheckHandle *cb_data,
|
|||
* the easy handle "at any moment"; specifically not from the
|
||||
* write function. Thus here we just dissociate the cb_data from
|
||||
* the easy handle and the easy handle will be cleaned up when the
|
||||
* message goes to CURLMSG_DONE in curl_check_connectivity(). */
|
||||
* message goes to CURLMSG_DONE in _con_curl_check_connectivity(). */
|
||||
curl_easy_setopt (cb_data->concheck.curl_ehandle, CURLOPT_WRITEFUNCTION, NULL);
|
||||
curl_easy_setopt (cb_data->concheck.curl_ehandle, CURLOPT_WRITEDATA, NULL);
|
||||
curl_easy_setopt (cb_data->concheck.curl_ehandle, CURLOPT_HEADERFUNCTION, NULL);
|
||||
|
@ -234,8 +234,8 @@ _check_handle_get_response (NMConnectivityCheckHandle *cb_data)
|
|||
return cb_data->concheck.response ?: NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE;
|
||||
}
|
||||
|
||||
static void
|
||||
curl_check_connectivity (CURLM *mhandle, int sockfd, int ev_bitmask)
|
||||
static gboolean
|
||||
_con_curl_check_connectivity (CURLM *mhandle, int sockfd, int ev_bitmask)
|
||||
{
|
||||
NMConnectivityCheckHandle *cb_data;
|
||||
CURLMsg *msg;
|
||||
|
@ -244,10 +244,13 @@ curl_check_connectivity (CURLM *mhandle, int sockfd, int ev_bitmask)
|
|||
long response_code;
|
||||
CURLMcode ret;
|
||||
int running_handles;
|
||||
gboolean success = TRUE;
|
||||
|
||||
ret = curl_multi_socket_action (mhandle, sockfd, ev_bitmask, &running_handles);
|
||||
if (ret != CURLM_OK)
|
||||
if (ret != CURLM_OK) {
|
||||
_LOGD ("connectivity check failed: %d", ret);
|
||||
success = FALSE;
|
||||
}
|
||||
|
||||
while ((msg = curl_multi_info_read (mhandle, &m_left))) {
|
||||
|
||||
|
@ -258,6 +261,7 @@ curl_check_connectivity (CURLM *mhandle, int sockfd, int ev_bitmask)
|
|||
eret = curl_easy_getinfo (msg->easy_handle, CURLINFO_PRIVATE, (char **) &cb_data);
|
||||
if (eret != CURLE_OK) {
|
||||
_LOGD ("curl cannot extract cb_data for easy handle, skipping msg");
|
||||
success = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -286,16 +290,22 @@ curl_check_connectivity (CURLM *mhandle, int sockfd, int ev_bitmask)
|
|||
"unexpected short response");
|
||||
}
|
||||
}
|
||||
|
||||
/* if we return a failure, we don't know what went wrong. It's likely serious, because
|
||||
* a failure here is not expected. Return FALSE, so that we stop polling the file descriptor.
|
||||
* Worst case, this leaves the pending connectivity check unhandled, until our regular
|
||||
* time-out kicks in. */
|
||||
return success;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
curl_timeout_cb (gpointer user_data)
|
||||
_con_curl_timeout_cb (gpointer user_data)
|
||||
{
|
||||
gs_unref_object NMConnectivity *self = g_object_ref (NM_CONNECTIVITY (user_data));
|
||||
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
|
||||
|
||||
priv->concheck.curl_timer = 0;
|
||||
curl_check_connectivity (priv->concheck.curl_mhandle, CURL_SOCKET_TIMEOUT, 0);
|
||||
_con_curl_check_connectivity (priv->concheck.curl_mhandle, CURL_SOCKET_TIMEOUT, 0);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
|
@ -307,17 +317,34 @@ multi_timer_cb (CURLM *multi, long timeout_ms, void *userdata)
|
|||
|
||||
nm_clear_g_source (&priv->concheck.curl_timer);
|
||||
if (timeout_ms != -1)
|
||||
priv->concheck.curl_timer = g_timeout_add (timeout_ms, curl_timeout_cb, self);
|
||||
priv->concheck.curl_timer = g_timeout_add (timeout_ms, _con_curl_timeout_cb, self);
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
NMConnectivity *self;
|
||||
GIOChannel *ch;
|
||||
|
||||
/* this is a very simplistic weak-pointer. If ConCurlSockData gets
|
||||
* destroyed, it will set *destroy_notify to TRUE.
|
||||
*
|
||||
* _con_curl_socketevent_cb() uses this to detect whether it can
|
||||
* safely access @fdp after _con_curl_check_connectivity(). */
|
||||
gboolean *destroy_notify;
|
||||
|
||||
guint ev;
|
||||
} ConCurlSockData;
|
||||
|
||||
static gboolean
|
||||
curl_socketevent_cb (GIOChannel *ch, GIOCondition condition, gpointer user_data)
|
||||
_con_curl_socketevent_cb (GIOChannel *ch, GIOCondition condition, gpointer user_data)
|
||||
{
|
||||
gs_unref_object NMConnectivity *self = g_object_ref (NM_CONNECTIVITY (user_data));
|
||||
ConCurlSockData *fdp = user_data;
|
||||
gs_unref_object NMConnectivity *self = g_object_ref (fdp->self);
|
||||
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
|
||||
int fd = g_io_channel_unix_get_fd (ch);
|
||||
int action = 0;
|
||||
gboolean fdp_destroyed = FALSE;
|
||||
gboolean success;
|
||||
|
||||
if (condition & G_IO_IN)
|
||||
action |= CURL_CSELECT_IN;
|
||||
|
@ -326,35 +353,49 @@ curl_socketevent_cb (GIOChannel *ch, GIOCondition condition, gpointer user_data)
|
|||
if (condition & G_IO_ERR)
|
||||
action |= CURL_CSELECT_ERR;
|
||||
|
||||
curl_check_connectivity (priv->concheck.curl_mhandle, fd, action);
|
||||
return G_SOURCE_CONTINUE;
|
||||
nm_assert (!fdp->destroy_notify);
|
||||
fdp->destroy_notify = &fdp_destroyed;
|
||||
|
||||
success = _con_curl_check_connectivity (priv->concheck.curl_mhandle, fd, action);
|
||||
|
||||
if (fdp_destroyed) {
|
||||
/* hups. fdp got invalidated during _con_curl_check_connectivity(). That's fine,
|
||||
* just don't touch it. */
|
||||
} else {
|
||||
nm_assert (fdp->destroy_notify == &fdp_destroyed);
|
||||
fdp->destroy_notify = NULL;
|
||||
if (!success)
|
||||
fdp->ev = 0;
|
||||
}
|
||||
|
||||
return success ? G_SOURCE_CONTINUE : G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GIOChannel *ch;
|
||||
guint ev;
|
||||
} CurlSockData;
|
||||
|
||||
static int
|
||||
multi_socket_cb (CURL *e_handle, curl_socket_t s, int what, void *userdata, void *socketp)
|
||||
multi_socket_cb (CURL *e_handle, curl_socket_t fd, int what, void *userdata, void *socketp)
|
||||
{
|
||||
NMConnectivity *self = NM_CONNECTIVITY (userdata);
|
||||
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
|
||||
CurlSockData *fdp = socketp;
|
||||
ConCurlSockData *fdp = socketp;
|
||||
GIOCondition condition = 0;
|
||||
|
||||
(void) _NM_ENSURE_TYPE (int, fd);
|
||||
|
||||
if (what == CURL_POLL_REMOVE) {
|
||||
if (fdp) {
|
||||
curl_multi_assign (priv->concheck.curl_mhandle, s, NULL);
|
||||
if (fdp->destroy_notify)
|
||||
*fdp->destroy_notify = TRUE;
|
||||
curl_multi_assign (priv->concheck.curl_mhandle, fd, NULL);
|
||||
nm_clear_g_source (&fdp->ev);
|
||||
g_io_channel_unref (fdp->ch);
|
||||
g_slice_free (CurlSockData, fdp);
|
||||
g_slice_free (ConCurlSockData, fdp);
|
||||
}
|
||||
} else {
|
||||
if (!fdp) {
|
||||
fdp = g_slice_new0 (CurlSockData);
|
||||
fdp->ch = g_io_channel_unix_new (s);
|
||||
curl_multi_assign (priv->concheck.curl_mhandle, s, fdp);
|
||||
fdp = g_slice_new0 (ConCurlSockData);
|
||||
fdp->self = self;
|
||||
fdp->ch = g_io_channel_unix_new (fd);
|
||||
curl_multi_assign (priv->concheck.curl_mhandle, fd, fdp);
|
||||
} else
|
||||
nm_clear_g_source (&fdp->ev);
|
||||
|
||||
|
@ -366,7 +407,7 @@ multi_socket_cb (CURL *e_handle, curl_socket_t s, int what, void *userdata, void
|
|||
condition = G_IO_IN | G_IO_OUT;
|
||||
|
||||
if (condition)
|
||||
fdp->ev = g_io_add_watch (fdp->ch, condition, curl_socketevent_cb, self);
|
||||
fdp->ev = g_io_add_watch (fdp->ch, condition, _con_curl_socketevent_cb, fdp);
|
||||
}
|
||||
|
||||
return CURLM_OK;
|
||||
|
|
Loading…
Reference in a new issue