diff options
-rw-r--r-- | src/mm-error-helpers.c | 195 | ||||
-rw-r--r-- | src/mm-error-helpers.h | 11 | ||||
-rw-r--r-- | src/tests/test-error-helpers.c | 84 |
3 files changed, 264 insertions, 26 deletions
diff --git a/src/mm-error-helpers.c b/src/mm-error-helpers.c index f7b0ba9c..81fc995c 100644 --- a/src/mm-error-helpers.c +++ b/src/mm-error-helpers.c @@ -15,11 +15,22 @@ * Copyright (C) 2011 - 2012 Google, Inc. */ +#include <config.h> + #include "mm-error-helpers.h" +#include "mm-errors-types.h" #include "mm-log.h" #include <ctype.h> +#if defined WITH_QMI +# include <libqmi-glib.h> +#endif + +#if defined WITH_MBIM +# include <libmbim-glib.h> +#endif + /******************************************************************************/ static gchar * @@ -41,6 +52,38 @@ normalize_error_string (const gchar *str) } /******************************************************************************/ +/* Core errors */ + +/* Human friendly messages for each error type */ +static const gchar *core_error_messages[] = { + [MM_CORE_ERROR_FAILED] = "Failed", + [MM_CORE_ERROR_CANCELLED] = "Cancelled", + [MM_CORE_ERROR_ABORTED] = "Aborted", + [MM_CORE_ERROR_UNSUPPORTED] = "Unsupported", + [MM_CORE_ERROR_NO_PLUGINS] = "No plugins", + [MM_CORE_ERROR_UNAUTHORIZED] = "Unauthorized", + [MM_CORE_ERROR_INVALID_ARGS] = "Invalid arguments", + [MM_CORE_ERROR_IN_PROGRESS] = "In progress", + [MM_CORE_ERROR_WRONG_STATE] = "Wrong state", + [MM_CORE_ERROR_CONNECTED] = "Connected", + [MM_CORE_ERROR_TOO_MANY] = "Too many", + [MM_CORE_ERROR_NOT_FOUND] = "Not found", + [MM_CORE_ERROR_RETRY] = "Retry", + [MM_CORE_ERROR_EXISTS] = "Exists", + [MM_CORE_ERROR_WRONG_SIM_STATE] = "Wrong SIM state", + [MM_CORE_ERROR_RESET_AND_RETRY] = "Reset and retry", + [MM_CORE_ERROR_TIMEOUT] = "Timed out", + [MM_CORE_ERROR_PROTOCOL] = "Protocol failure", + [MM_CORE_ERROR_THROTTLED] = "Throttled", +}; + +static const gchar * +core_error_get_string (MMCoreError code) +{ + return (code < G_N_ELEMENTS (core_error_messages)) ? core_error_messages[code] : NULL; +} + +/******************************************************************************/ /* Connection errors */ /* Human friendly messages for each error type */ @@ -52,17 +95,21 @@ static const gchar *connection_error_messages[] = { [MM_CONNECTION_ERROR_NO_ANSWER] = "No answer", }; +static const gchar * +connection_error_get_string (MMConnectionError code) +{ + return (code < G_N_ELEMENTS (connection_error_messages)) ? connection_error_messages[code] : NULL; +} + GError * mm_connection_error_for_code (MMConnectionError code, gpointer log_object) { - if (code < G_N_ELEMENTS (connection_error_messages)) { - const gchar *error_message; + const gchar *description; - error_message = connection_error_messages[code]; - if (error_message) - return g_error_new_literal (MM_CONNECTION_ERROR, code, error_message); - } + description = connection_error_get_string (code); + if (description) + return g_error_new_literal (MM_CONNECTION_ERROR, code, description); /* Not found? Then, default to 'no carrier' */ mm_obj_dbg (log_object, "unknown connection error: %u", code); @@ -244,17 +291,21 @@ static const gchar *me_error_messages[] = { /* All generic ME errors should be < 255, as those are the only reserved ones in the 3GPP spec */ G_STATIC_ASSERT (G_N_ELEMENTS (me_error_messages) <= 256); +static const gchar * +me_error_get_string (MMMobileEquipmentError code) +{ + return (code < G_N_ELEMENTS (me_error_messages)) ? me_error_messages[code] : NULL; +} + GError * mm_mobile_equipment_error_for_code (MMMobileEquipmentError code, gpointer log_object) { - if (code < G_N_ELEMENTS (me_error_messages)) { - const gchar *error_message; + const gchar *description; - error_message = me_error_messages[code]; - if (error_message) - return g_error_new_literal (MM_MOBILE_EQUIPMENT_ERROR, code, error_message); - } + description = me_error_get_string (code); + if (description) + return g_error_new_literal (MM_MOBILE_EQUIPMENT_ERROR, code, description); /* Not found? Then, default */ mm_obj_dbg (log_object, "unknown mobile equipment error: %u", code); @@ -264,6 +315,27 @@ mm_mobile_equipment_error_for_code (MMMobileEquipmentError code, } /******************************************************************************/ +/* Serial errors */ + +static const gchar *serial_error_messages[] = { + [MM_SERIAL_ERROR_UNKNOWN] = "Unknown", + [MM_SERIAL_ERROR_OPEN_FAILED] = "Open failed", + [MM_SERIAL_ERROR_SEND_FAILED] = "Send failed", + [MM_SERIAL_ERROR_RESPONSE_TIMEOUT] = "Response timeout", + [MM_SERIAL_ERROR_OPEN_FAILED_NO_DEVICE] = "Open failed, no device", + [MM_SERIAL_ERROR_FLASH_FAILED] = "Flash failed", + [MM_SERIAL_ERROR_NOT_OPEN] = "Not open", + [MM_SERIAL_ERROR_PARSE_FAILED] = "Parse failed", + [MM_SERIAL_ERROR_FRAME_NOT_FOUND] = "Frame not found", +}; + +static const gchar * +serial_error_get_string (MMSerialError code) +{ + return (code < G_N_ELEMENTS (serial_error_messages)) ? serial_error_messages[code] : NULL; +} + +/******************************************************************************/ /* Message errors * * The message errors are all >300, so we define a common offset for all error @@ -302,23 +374,26 @@ static const gchar *msg_error_messages[] = { /* All generic message errors should be <= 500 (500-common=200), as those are the only reserved ones in the 3GPP spec */ G_STATIC_ASSERT (G_N_ELEMENTS (msg_error_messages) <= 201); +static const gchar * +message_error_get_string (MMMessageError code) +{ + return ((code >= MM_MESSAGE_ERROR_COMMON_OFFSET) && ((code - MM_MESSAGE_ERROR_COMMON_OFFSET) < G_N_ELEMENTS (msg_error_messages))) ? + msg_error_messages[code - MM_MESSAGE_ERROR_COMMON_OFFSET] : NULL; +} + GError * mm_message_error_for_code (MMMessageError code, gpointer log_object) { - if ((code >= MM_MESSAGE_ERROR_COMMON_OFFSET) && ((code - MM_MESSAGE_ERROR_COMMON_OFFSET) < G_N_ELEMENTS (msg_error_messages))) { - const gchar *error_message; + const gchar *description; - error_message = msg_error_messages[code - MM_MESSAGE_ERROR_COMMON_OFFSET]; - if (error_message) - return g_error_new_literal (MM_MESSAGE_ERROR, code, error_message); - } + description = message_error_get_string (code); + if (description) + return g_error_new_literal (MM_MESSAGE_ERROR, code, description); /* Not found? Then, default */ mm_obj_dbg (log_object, "unknown message error: %u", code); - return g_error_new (MM_MESSAGE_ERROR, - MM_MESSAGE_ERROR_UNKNOWN, - "Unknown message error: %u", code); + return g_error_new (MM_MESSAGE_ERROR, MM_MESSAGE_ERROR_UNKNOWN, "Unknown message error: %u", code); } /******************************************************************************/ @@ -420,3 +495,81 @@ mm_message_error_for_string (const gchar *str, MM_MESSAGE_ERROR_UNKNOWN, "Unknown message error string: %s", str); } + +/******************************************************************************/ +/* CDMA activation errors */ + +static const gchar *cdma_activation_error_messages[] = { + [MM_CDMA_ACTIVATION_ERROR_NONE] = "None", + [MM_CDMA_ACTIVATION_ERROR_UNKNOWN] = "Unknown", + [MM_CDMA_ACTIVATION_ERROR_ROAMING] = "Roaming", + [MM_CDMA_ACTIVATION_ERROR_WRONG_RADIO_INTERFACE] = "Wrong radio interface", + [MM_CDMA_ACTIVATION_ERROR_COULD_NOT_CONNECT] = "Could not connect", + [MM_CDMA_ACTIVATION_ERROR_SECURITY_AUTHENTICATION_FAILED] = "Security authentication failed", + [MM_CDMA_ACTIVATION_ERROR_PROVISIONING_FAILED] = "Provisioning failed", + [MM_CDMA_ACTIVATION_ERROR_NO_SIGNAL] = "No signal", + [MM_CDMA_ACTIVATION_ERROR_TIMED_OUT] = "Timed out", + [MM_CDMA_ACTIVATION_ERROR_START_FAILED] = "Start failed", +}; + +static const gchar * +cdma_activation_error_get_string (MMCdmaActivationError code) +{ + return (code < G_N_ELEMENTS (cdma_activation_error_messages)) ? cdma_activation_error_messages[code] : NULL; +} + +/******************************************************************************/ +/* Takes a GError of any kind and ensures that the returned GError is a + * MM-defined one. */ + +static GError * +normalize_mm_error (const GError *error, + const gchar *error_description, + const gchar *error_type) +{ + if (error_description) { + GError *copy; + + copy = g_error_copy (error); + /* Add error type name only if it isn't already the same string */ + if (g_strcmp0 (copy->message, error_description) != 0) + g_prefix_error (©, "%s: ", error_description); + return copy; + } + + return g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Unhandled %s error (%u): %s", + error_type, error->code, error->message); +} + +GError * +mm_normalize_error (const GError *error) +{ + g_assert (error); + + if (error->domain == G_IO_ERROR) { + /* G_IO_ERROR_CANCELLED is an exception, because we map it to + * MM_CORE_ERROR_CANCELLED implicitly when building the DBus error name. */ + if (error->code == G_IO_ERROR_CANCELLED) + return g_error_copy (error); + + return g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Unhandled GIO error (%u): %s", error->code, error->message); + } + + /* Ensure all errors reported in the MM domains are known errors */ + if (error->domain == MM_CORE_ERROR) + return normalize_mm_error (error, core_error_get_string (error->code), "core"); + if (error->domain == MM_MOBILE_EQUIPMENT_ERROR) + return normalize_mm_error (error, me_error_get_string (error->code), "mobile equipment"); + if (error->domain == MM_CONNECTION_ERROR) + return normalize_mm_error (error, connection_error_get_string (error->code), "connection"); + if (error->domain == MM_SERIAL_ERROR) + return normalize_mm_error (error, serial_error_get_string (error->code), "serial"); + if (error->domain == MM_MESSAGE_ERROR) + return normalize_mm_error (error, message_error_get_string (error->code), "message"); + if (error->domain == MM_CDMA_ACTIVATION_ERROR) + return normalize_mm_error (error, cdma_activation_error_get_string (error->code), "CDMA activation"); + + /* Generic fallback */ + return g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "%s", error->message); +} diff --git a/src/mm-error-helpers.h b/src/mm-error-helpers.h index e99d1662..d0effac7 100644 --- a/src/mm-error-helpers.h +++ b/src/mm-error-helpers.h @@ -23,10 +23,11 @@ #include <ModemManager.h> #include <libmm-glib.h> -GError *mm_connection_error_for_code (MMConnectionError code, gpointer log_object); -GError *mm_mobile_equipment_error_for_code (MMMobileEquipmentError code, gpointer log_object); -GError *mm_mobile_equipment_error_for_string (const gchar *str, gpointer log_object); -GError *mm_message_error_for_code (MMMessageError code, gpointer log_object); -GError *mm_message_error_for_string (const gchar *str, gpointer log_object); +GError *mm_connection_error_for_code (MMConnectionError code, gpointer log_object); +GError *mm_mobile_equipment_error_for_code (MMMobileEquipmentError code, gpointer log_object); +GError *mm_mobile_equipment_error_for_string (const gchar *str, gpointer log_object); +GError *mm_message_error_for_code (MMMessageError code, gpointer log_object); +GError *mm_message_error_for_string (const gchar *str, gpointer log_object); +GError *mm_normalize_error (const GError *error); #endif /* MM_ERROR_HELPERS_H */ diff --git a/src/tests/test-error-helpers.c b/src/tests/test-error-helpers.c index 03bcab98..68e6daf3 100644 --- a/src/tests/test-error-helpers.c +++ b/src/tests/test-error-helpers.c @@ -13,6 +13,8 @@ * Copyright (C) 2019 Aleksander Morgado <aleksander@aleksander.es> */ +#include <config.h> + #include <glib.h> #include <glib-object.h> #include <string.h> @@ -24,6 +26,14 @@ #include "mm-error-helpers.h" #include "mm-log.h" +#if defined WITH_QMI +# include <libqmi-glib.h> +#endif + +#if defined WITH_MBIM +# include <libmbim-glib.h> +#endif + #define TEST_ERROR_HELPER(ERROR_CAPS,ERROR_SMALL,ERROR_CAMEL) \ static void \ test_error_helpers_## ERROR_SMALL (void) \ @@ -131,6 +141,78 @@ test_error_helpers_message_error_for_string (void) /*****************************************************************************/ +static void +normalize_and_assert_mm_error (gboolean expect_fallback, + GQuark domain, + int code, + const gchar *description) +{ + g_autoptr(GError) input_error = NULL; + g_autoptr(GError) normalized_error = NULL; + + g_debug ("Checking normalized error: %s", description); + + input_error = g_error_new_literal (domain, code, description); + normalized_error = mm_normalize_error (input_error); + + g_assert (normalized_error); + g_assert ((normalized_error->domain == MM_CORE_ERROR) || + (normalized_error->domain == MM_MOBILE_EQUIPMENT_ERROR) || + (normalized_error->domain == MM_CONNECTION_ERROR) || + (normalized_error->domain == MM_SERIAL_ERROR) || + (normalized_error->domain == MM_MESSAGE_ERROR) || + (normalized_error->domain == MM_CDMA_ACTIVATION_ERROR) || + g_error_matches (normalized_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)); + + g_assert (expect_fallback == g_error_matches (normalized_error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED)); +} + +static void +test_error_helpers_normalize (void) +{ + normalize_and_assert_mm_error (TRUE, G_IO_ERROR, G_IO_ERROR_FAILED, "GIO error"); + normalize_and_assert_mm_error (FALSE, G_IO_ERROR, G_IO_ERROR_CANCELLED, "GIO error cancelled"); + + normalize_and_assert_mm_error (TRUE, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Known core error"); /* This is exactly the fallback */ + normalize_and_assert_mm_error (TRUE, MM_CORE_ERROR, 123456, "Unknown core error"); + + normalize_and_assert_mm_error (FALSE, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NO_NETWORK, "Known ME error"); + normalize_and_assert_mm_error (TRUE, MM_MOBILE_EQUIPMENT_ERROR, 123456789, "Unknown ME error"); + + normalize_and_assert_mm_error (FALSE, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_CARRIER, "Known connection error"); + normalize_and_assert_mm_error (TRUE, MM_CONNECTION_ERROR, 123456, "Unknown connection error"); + + normalize_and_assert_mm_error (FALSE, MM_SERIAL_ERROR, MM_SERIAL_ERROR_OPEN_FAILED, "Known serial error"); + normalize_and_assert_mm_error (TRUE, MM_SERIAL_ERROR, 123456, "Unknown serial error"); + + normalize_and_assert_mm_error (FALSE, MM_MESSAGE_ERROR, MM_MESSAGE_ERROR_ME_FAILURE, "Known message error"); + normalize_and_assert_mm_error (TRUE, MM_MESSAGE_ERROR, 123456, "Unknown message error"); + + normalize_and_assert_mm_error (FALSE, MM_CDMA_ACTIVATION_ERROR, MM_CDMA_ACTIVATION_ERROR_ROAMING, "Known CDMA activation error"); + normalize_and_assert_mm_error (TRUE, MM_CDMA_ACTIVATION_ERROR, 123456, "Unknown CDMA activation error"); + +#if defined WITH_QMI + normalize_and_assert_mm_error (TRUE, QMI_CORE_ERROR, QMI_CORE_ERROR_TIMEOUT, "Known QMI core error"); + normalize_and_assert_mm_error (TRUE, QMI_CORE_ERROR, 123456, "Unknown QMI core error"); + + normalize_and_assert_mm_error (TRUE, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_ABORTED, "Known QMI protocol error"); + normalize_and_assert_mm_error (TRUE, QMI_PROTOCOL_ERROR, 123456, "Unknown QMI protocol error"); +#endif + +#if defined WITH_MBIM + normalize_and_assert_mm_error (TRUE, MBIM_CORE_ERROR, MBIM_CORE_ERROR_ABORTED, "Known MBIM core error"); + normalize_and_assert_mm_error (TRUE, MBIM_CORE_ERROR, 123456, "Unknown MBIM core error"); + + normalize_and_assert_mm_error (TRUE, MBIM_PROTOCOL_ERROR, MBIM_PROTOCOL_ERROR_CANCEL, "Known MBIM protocol error"); + normalize_and_assert_mm_error (TRUE, MBIM_PROTOCOL_ERROR, 123456, "Unknown MBIM protocol error"); + + normalize_and_assert_mm_error (TRUE, MBIM_STATUS_ERROR, MBIM_STATUS_ERROR_BUSY, "Known MBIM status error"); + normalize_and_assert_mm_error (TRUE, MBIM_STATUS_ERROR, 123456, "Unknown MBIM status error"); +#endif +} + +/*****************************************************************************/ + int main (int argc, char **argv) { setlocale (LC_ALL, ""); @@ -147,5 +229,7 @@ int main (int argc, char **argv) g_test_add_func ("/MM/error-helpers/mobile-equipment-error/for-string", test_error_helpers_mobile_equipment_error_for_string); g_test_add_func ("/MM/error-helpers/message-error/for-string", test_error_helpers_message_error_for_string); + g_test_add_func ("/MM/error-helpers/normalize", test_error_helpers_normalize); + return g_test_run (); } |