diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 15e03276bc..4ad6b277fb 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -59,6 +59,8 @@ #define CLOCK_BOOTTIME 7 #endif +G_DEFINE_QUARK (nm-utils-error-quark, nm_utils_error) + G_STATIC_ASSERT (sizeof (NMUtilsTestFlags) <= sizeof (int)); int _nm_utils_testing = 0; diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 1b7d924ab2..03d6be28a2 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -232,4 +232,25 @@ gboolean nm_utils_get_testing_initialized (void); NMUtilsTestFlags nm_utils_get_testing (void); void _nm_utils_set_testing (NMUtilsTestFlags flags); +/*****************************************************************************/ + +/** + * NMUtilsError: + * @NM_UTILS_ERROR_UNKNOWN: unknown or unclassified error + * @NM_UTILS_ERROR_CANCELLED_DISPOSING: when disposing an object that has + * pending aynchronous operations, the operation is cancelled with this + * error reason. Depending on the usage, this might indicate a bug because + * usually the target object should stay alive as long as there are pending + * operations. + */ +typedef enum { + NM_UTILS_ERROR_UNKNOWN = 0, /*< nick=Unknown >*/ + NM_UTILS_ERROR_CANCELLED_DISPOSING, /*< nick=CancelledDisposing >*/ +} NMUtilsError; + +#define NM_UTILS_ERROR (nm_utils_error_quark ()) +GQuark nm_utils_error_quark (void); + +/*****************************************************************************/ + #endif /* __NETWORKMANAGER_UTILS_H__ */ diff --git a/src/rdisc/nm-fake-rdisc.c b/src/rdisc/nm-fake-rdisc.c index 68f43c0e52..be36c75ea6 100644 --- a/src/rdisc/nm-fake-rdisc.c +++ b/src/rdisc/nm-fake-rdisc.c @@ -236,7 +236,7 @@ nm_fake_rdisc_done (NMFakeRDisc *self) /******************************************************************/ static gboolean -send_rs (NMRDisc *rdisc) +send_rs (NMRDisc *rdisc, GError **error) { g_signal_emit (rdisc, signals[RS_SENT], 0); return TRUE; diff --git a/src/rdisc/nm-lndp-rdisc.c b/src/rdisc/nm-lndp-rdisc.c index 46f814767f..d40a117de4 100644 --- a/src/rdisc/nm-lndp-rdisc.c +++ b/src/rdisc/nm-lndp-rdisc.c @@ -52,20 +52,28 @@ G_DEFINE_TYPE (NMLNDPRDisc, nm_lndp_rdisc, NM_TYPE_RDISC) /******************************************************************/ static gboolean -send_rs (NMRDisc *rdisc) +send_rs (NMRDisc *rdisc, GError **error) { NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); struct ndp_msg *msg; - int error; + int errsv; - error = ndp_msg_new (&msg, NDP_MSG_RS); - g_assert (!error); + errsv = ndp_msg_new (&msg, NDP_MSG_RS); + if (errsv) { + errsv = errsv > 0 ? errsv : -errsv; + g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "cannot create router solicitation"); + return FALSE; + } ndp_msg_ifindex_set (msg, rdisc->ifindex); - error = ndp_msg_send (priv->ndp, msg); + errsv = ndp_msg_send (priv->ndp, msg); ndp_msg_destroy (msg); - if (error) { - error ("(%s): cannot send router solicitation: %d.", rdisc->ifname, error); + if (errsv) { + errsv = errsv > 0 ? errsv : -errsv; + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "%s (%d)", + g_strerror (errsv), errsv); return FALSE; } diff --git a/src/rdisc/nm-rdisc.c b/src/rdisc/nm-rdisc.c index a73ab7d0f5..43810c6ce2 100644 --- a/src/rdisc/nm-rdisc.c +++ b/src/rdisc/nm-rdisc.c @@ -38,6 +38,7 @@ typedef struct { gint64 last_rs; guint ra_timeout_id; /* first RA timeout */ guint timeout_id; /* prefix/dns/etc lifetime timeout */ + char *last_send_rs_error; } NMRDiscPrivate; #define NM_RDISC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_RDISC, NMRDiscPrivate)) @@ -280,11 +281,25 @@ send_rs (NMRDisc *rdisc) { NMRDiscClass *klass = NM_RDISC_GET_CLASS (rdisc); NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); + GError *error = NULL; - debug ("(%s): sending router solicitation", rdisc->ifname); - - if (klass->send_rs (rdisc)) + if (klass->send_rs (rdisc, &error)) { + debug ("(%s): router solicitation sent", rdisc->ifname); priv->solicitations_left--; + g_clear_pointer (&priv->last_send_rs_error, g_free); + } else { + gboolean different_message; + + different_message = g_strcmp0 (priv->last_send_rs_error, error->message) != 0; + nm_log (different_message ? LOGL_WARN : LOGL_DEBUG, LOGD_IP6, + "(%s): failure sending router solicitation: %s", + rdisc->ifname, error->message); + if (different_message) { + g_clear_pointer (&priv->last_send_rs_error, g_free); + priv->last_send_rs_error = g_strdup (error->message); + } + g_clear_error (&error); + } priv->last_rs = nm_utils_get_monotonic_timestamp_s (); if (priv->solicitations_left > 0) { @@ -581,8 +596,11 @@ timeout_cb (gpointer user_data) void nm_rdisc_ra_received (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed) { + NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); + clear_ra_timeout (rdisc); clear_rs_timeout (rdisc); + g_clear_pointer (&priv->last_send_rs_error, g_free); check_timestamps (rdisc, now, changed); } @@ -621,6 +639,7 @@ dispose (GObject *object) clear_ra_timeout (rdisc); clear_rs_timeout (rdisc); + g_clear_pointer (&priv->last_send_rs_error, g_free); if (priv->timeout_id) { g_source_remove (priv->timeout_id); diff --git a/src/rdisc/nm-rdisc.h b/src/rdisc/nm-rdisc.h index 463e19121b..9f0ff5a6af 100644 --- a/src/rdisc/nm-rdisc.h +++ b/src/rdisc/nm-rdisc.h @@ -133,7 +133,7 @@ typedef struct { GObjectClass parent; void (*start) (NMRDisc *rdisc); - gboolean (*send_rs) (NMRDisc *rdisc); + gboolean (*send_rs) (NMRDisc *rdisc, GError **error); void (*config_changed) (NMRDisc *rdisc, NMRDiscConfigMap changed); void (*ra_process) (NMRDisc *rdisc); void (*ra_timeout) (NMRDisc *rdisc);