diff --git a/ChangeLog b/ChangeLog index 264801dbc0..2e70b513fc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2008-06-30 Tambet Ingo + + * src/nm-serial-device.c: + * src/nm-gsm-device.c: + * src/nm-cdma-device.c: Move the pending call handling to a common location + in serial device. Handle setting device state to failed in one place as well. + 2008-06-29 Dan Williams * src/nm-hal-manager.c diff --git a/src/nm-cdma-device.c b/src/nm-cdma-device.c index f4d0b0ee0c..47c91a2887 100644 --- a/src/nm-cdma-device.c +++ b/src/nm-cdma-device.c @@ -19,7 +19,6 @@ typedef struct { char *monitor_iface; NMSerialDevice *monitor_device; - guint pending_id; guint state_to_disconnected_id; } NMCdmaDevicePrivate; @@ -59,12 +58,6 @@ nm_cdma_device_new (const char *udi, NULL); } -static inline void -cdma_device_set_pending (NMCdmaDevice *device, guint pending_id) -{ - NM_CDMA_DEVICE_GET_PRIVATE (device)->pending_id = pending_id; -} - static NMSetting * cdma_device_get_setting (NMCdmaDevice *device, GType setting_type) { @@ -90,8 +83,6 @@ dial_done (NMSerialDevice *device, { gboolean success = FALSE; - cdma_device_set_pending (NM_CDMA_DEVICE (device), 0); - switch (reply_index) { case 0: nm_info ("Connected, Woo!"); @@ -125,25 +116,18 @@ do_dial (NMSerialDevice *device) { NMSettingCdma *setting; char *command; - guint id; + guint id = 0; char *responses[] = { "CONNECT", "BUSY", "NO DIAL TONE", "NO CARRIER", NULL }; - gboolean success; setting = NM_SETTING_CDMA (cdma_device_get_setting (NM_CDMA_DEVICE (device), NM_TYPE_SETTING_CDMA)); command = g_strconcat ("ATDT", setting->number, NULL); - success = nm_serial_device_send_command_string (device, command); + if (nm_serial_device_send_command_string (device, command)) + id = nm_serial_device_wait_for_reply (device, 60, responses, responses, dial_done, NULL); g_free (command); - if (success) { - id = nm_serial_device_wait_for_reply (device, 60, responses, responses, dial_done, NULL); - if (id) - cdma_device_set_pending (NM_CDMA_DEVICE (device), id); - else - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); - } else { + if (id == 0) nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); - } } static void @@ -151,8 +135,6 @@ init_done (NMSerialDevice *device, int reply_index, gpointer user_data) { - cdma_device_set_pending (NM_CDMA_DEVICE (device), 0); - switch (reply_index) { case 0: do_dial (device); @@ -171,37 +153,31 @@ init_done (NMSerialDevice *device, static void init_modem (NMSerialDevice *device, gpointer user_data) { - guint id; + guint id = 0; char *responses[] = { "OK", "ERROR", "ERR", NULL }; - if (!nm_serial_device_send_command_string (device, "ATZ E0")) { - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); - return; - } + if (nm_serial_device_send_command_string (device, "ATZ E0")) + id = nm_serial_device_wait_for_reply (device, 10, responses, responses, init_done, NULL); - id = nm_serial_device_wait_for_reply (device, 10, responses, responses, init_done, NULL); - - if (id) - cdma_device_set_pending (NM_CDMA_DEVICE (device), id); - else + if (id == 0) nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); } static NMActStageReturn real_act_stage1_prepare (NMDevice *device) { - NMCdmaDevicePrivate *priv = NM_CDMA_DEVICE_GET_PRIVATE (device); NMSerialDevice *serial_device = NM_SERIAL_DEVICE (device); NMSettingSerial *setting; + guint id; setting = NM_SETTING_SERIAL (cdma_device_get_setting (NM_CDMA_DEVICE (device), NM_TYPE_SETTING_SERIAL)); if (!nm_serial_device_open (serial_device, setting)) return NM_ACT_STAGE_RETURN_FAILURE; - priv->pending_id = nm_serial_device_flash (serial_device, 100, init_modem, NULL); + id = nm_serial_device_flash (serial_device, 100, init_modem, NULL); - return priv->pending_id ? NM_ACT_STAGE_RETURN_POSTPONE : NM_ACT_STAGE_RETURN_FAILURE; + return id ? NM_ACT_STAGE_RETURN_POSTPONE : NM_ACT_STAGE_RETURN_FAILURE; } static NMConnection * @@ -267,19 +243,6 @@ real_connection_secrets_updated (NMDevice *dev, nm_device_activate_schedule_stage1_device_prepare (dev); } -static void -real_deactivate_quickly (NMDevice *device) -{ - NMCdmaDevicePrivate *priv = NM_CDMA_DEVICE_GET_PRIVATE (device); - - if (priv->pending_id) { - g_source_remove (priv->pending_id); - priv->pending_id = 0; - } - - NM_DEVICE_CLASS (nm_cdma_device_parent_class)->deactivate_quickly (device); -} - /*****************************************************************************/ /* Monitor device handling */ @@ -496,7 +459,6 @@ nm_cdma_device_class_init (NMCdmaDeviceClass *klass) device_class->get_generic_capabilities = real_get_generic_capabilities; device_class->act_stage1_prepare = real_act_stage1_prepare; device_class->connection_secrets_updated = real_connection_secrets_updated; - device_class->deactivate_quickly = real_deactivate_quickly; /* Properties */ g_object_class_install_property diff --git a/src/nm-gsm-device.c b/src/nm-gsm-device.c index ea082b3213..6436857118 100644 --- a/src/nm-gsm-device.c +++ b/src/nm-gsm-device.c @@ -45,8 +45,8 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; -static void enter_pin (NMSerialDevice *device, gboolean retry); -static void automatic_registration (NMSerialDevice *device); +static void enter_pin (NMGsmDevice *device, gboolean retry); +static void automatic_registration (NMGsmDevice *device); NMGsmDevice * nm_gsm_device_new (const char *udi, @@ -68,10 +68,39 @@ nm_gsm_device_new (const char *udi, NULL); } -static inline void -gsm_device_set_pending (NMGsmDevice *device, guint pending_id) +static void +modem_wait_for_reply (NMGsmDevice *self, + const char *command, + guint timeout, + char **responses, + char **terminators, + NMSerialWaitForReplyFn callback) { - NM_GSM_DEVICE_GET_PRIVATE (device)->pending_id = pending_id; + NMSerialDevice *serial = NM_SERIAL_DEVICE (self); + guint id = 0; + + if (nm_serial_device_send_command_string (serial, command)) + id = nm_serial_device_wait_for_reply (serial, timeout, responses, terminators, callback, NULL); + + if (id == 0) + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED); +} + +static void +modem_get_reply (NMGsmDevice *self, + const char *command, + guint timeout, + const char *terminators, + NMSerialGetReplyFn callback) +{ + NMSerialDevice *serial = NM_SERIAL_DEVICE (self); + guint id = 0; + + if (nm_serial_device_send_command_string (serial, command)) + id = nm_serial_device_get_reply (serial, timeout, terminators, callback, NULL); + + if (id == 0) + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED); } static NMSetting * @@ -99,8 +128,6 @@ dial_done (NMSerialDevice *device, { gboolean success = FALSE; - gsm_device_set_pending (NM_GSM_DEVICE (device), 0); - switch (reply_index) { case 0: nm_info ("Connected, Woo!"); @@ -130,13 +157,11 @@ dial_done (NMSerialDevice *device, } static void -do_dial (NMSerialDevice *device, guint cid) +do_dial (NMGsmDevice *device, guint cid) { NMSettingGsm *setting; char *command; - guint id; char *responses[] = { "CONNECT", "BUSY", "NO DIAL TONE", "NO CARRIER", NULL }; - gboolean success; setting = NM_SETTING_GSM (gsm_device_get_setting (NM_GSM_DEVICE (device), NM_TYPE_SETTING_GSM)); @@ -154,18 +179,8 @@ do_dial (NMSerialDevice *device, guint cid) } else command = g_strconcat ("ATDT", setting->number, NULL); - success = nm_serial_device_send_command_string (device, command); + modem_wait_for_reply (device, command, 60, responses, responses, dial_done); g_free (command); - - if (success) { - id = nm_serial_device_wait_for_reply (device, 60, responses, responses, dial_done, NULL); - if (id) - gsm_device_set_pending (NM_GSM_DEVICE (device), id); - else - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); - } else { - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); - } } static void @@ -173,13 +188,9 @@ set_apn_done (NMSerialDevice *device, int reply_index, gpointer user_data) { - guint cid = GPOINTER_TO_UINT (user_data); - - gsm_device_set_pending (NM_GSM_DEVICE (device), 0); - switch (reply_index) { case 0: - do_dial (device, cid); + do_dial (NM_GSM_DEVICE (device), 1); break; default: nm_warning ("Setting APN failed"); @@ -189,13 +200,11 @@ set_apn_done (NMSerialDevice *device, } static void -set_apn (NMSerialDevice *device) +set_apn (NMGsmDevice *device) { NMSettingGsm *setting; char *command; char *responses[] = { "OK", "ERROR", NULL }; - gboolean success; - guint id = 0; guint cid = 1; setting = NM_SETTING_GSM (gsm_device_get_setting (NM_GSM_DEVICE (device), NM_TYPE_SETTING_GSM)); @@ -207,16 +216,8 @@ set_apn (NMSerialDevice *device) } command = g_strdup_printf ("AT+CGDCONT=%d, \"IP\", \"%s\"", cid, setting->apn); - success = nm_serial_device_send_command_string (device, command); + modem_wait_for_reply (device, command, 3, responses, responses, set_apn_done); g_free (command); - - if (success) - id = nm_serial_device_wait_for_reply (device, 3, responses, responses, set_apn_done, GUINT_TO_POINTER (cid)); - - if (id) - gsm_device_set_pending (NM_GSM_DEVICE (device), id); - else - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); } static void @@ -224,11 +225,9 @@ manual_registration_done (NMSerialDevice *device, int reply_index, gpointer user_data) { - gsm_device_set_pending (NM_GSM_DEVICE (device), 0); - switch (reply_index) { case 0: - set_apn (device); + set_apn (NM_GSM_DEVICE (device)); break; case -1: nm_warning ("Manual registration timed out"); @@ -242,29 +241,17 @@ manual_registration_done (NMSerialDevice *device, } static void -manual_registration (NMSerialDevice *device) +manual_registration (NMGsmDevice *device) { NMSettingGsm *setting; char *command; - guint id; char *responses[] = { "OK", "ERROR", "ERR", NULL }; - gboolean success; - setting = NM_SETTING_GSM (gsm_device_get_setting (NM_GSM_DEVICE (device), NM_TYPE_SETTING_GSM)); + setting = NM_SETTING_GSM (gsm_device_get_setting (device, NM_TYPE_SETTING_GSM)); command = g_strdup_printf ("AT+COPS=1,2,\"%s\"", setting->network_id); - success = nm_serial_device_send_command_string (device, command); + modem_wait_for_reply (device, command, 30, responses, responses, manual_registration_done); g_free (command); - - if (success) { - id = nm_serial_device_wait_for_reply (device, 30, responses, responses, manual_registration_done, NULL); - if (id) - gsm_device_set_pending (NM_GSM_DEVICE (device), id); - else - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); - } else { - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); - } } static void @@ -272,38 +259,26 @@ get_network_done (NMSerialDevice *device, const char *response, gpointer user_data) { - gsm_device_set_pending (NM_GSM_DEVICE (device), 0); - if (response) nm_info ("Associated with network: %s", response); else nm_warning ("Couldn't read active network name"); - set_apn (device); + set_apn (NM_GSM_DEVICE (device)); } static void -automatic_registration_get_network (NMSerialDevice *device) +automatic_registration_get_network (NMGsmDevice *device) { - guint id; const char terminators[] = { '\r', '\n', '\0' }; - if (!nm_serial_device_send_command_string (device, "AT+COPS?")) { - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); - return; - } - - id = nm_serial_device_get_reply (device, 10, terminators, get_network_done, NULL); - if (id) - gsm_device_set_pending (NM_GSM_DEVICE (device), id); - else - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); + modem_get_reply (device, "AT+COPS?", 10, terminators, get_network_done); } static gboolean automatic_registration_again (gpointer data) { - automatic_registration (NM_SERIAL_DEVICE (data)); + automatic_registration (NM_GSM_DEVICE (data)); return FALSE; } @@ -312,20 +287,17 @@ automatic_registration_response (NMSerialDevice *device, int reply_index, gpointer user_data) { - gsm_device_set_pending (NM_GSM_DEVICE (device), 0); - switch (reply_index) { case 0: nm_info ("Registered on Home network"); - automatic_registration_get_network (device); + automatic_registration_get_network (NM_GSM_DEVICE (device)); break; case 1: nm_info ("Registered on Roaming network"); - automatic_registration_get_network (device); + automatic_registration_get_network (NM_GSM_DEVICE (device)); break; case 2: - gsm_device_set_pending (NM_GSM_DEVICE (device), - g_timeout_add (1000, automatic_registration_again, device)); + NM_GSM_DEVICE_GET_PRIVATE (device)->pending_id = g_timeout_add (1000, automatic_registration_again, device); break; case 3: nm_warning ("Automatic registration failed: not registered and not searching."); @@ -343,30 +315,20 @@ automatic_registration_response (NMSerialDevice *device, } static void -automatic_registration (NMSerialDevice *device) +automatic_registration (NMGsmDevice *device) { - guint id; char *responses[] = { "+CREG: 0,1", "+CREG: 0,5", "+CREG: 0,2", "+CREG: 0,0", NULL }; char *terminators[] = { "OK", "ERROR", "ERR", NULL }; - if (!nm_serial_device_send_command_string (device, "AT+CREG?")) { - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); - return; - } - - id = nm_serial_device_wait_for_reply (device, 60, responses, terminators, automatic_registration_response, NULL); - if (id) - gsm_device_set_pending (NM_GSM_DEVICE (device), id); - else - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); + modem_wait_for_reply (device, "AT+CREG?", 60, responses, terminators, automatic_registration_response); } static void -do_register (NMSerialDevice *device) +do_register (NMGsmDevice *device) { NMSettingGsm *setting; - setting = NM_SETTING_GSM (gsm_device_get_setting (NM_GSM_DEVICE (device), NM_TYPE_SETTING_GSM)); + setting = NM_SETTING_GSM (gsm_device_get_setting (device, NM_TYPE_SETTING_GSM)); if (setting->network_id) manual_registration (device); @@ -379,11 +341,9 @@ init_full_done (NMSerialDevice *device, int reply_index, gpointer user_data) { - gsm_device_set_pending (NM_GSM_DEVICE (device), 0); - switch (reply_index) { case 0: - do_register (device); + do_register (NM_GSM_DEVICE (device)); break; case -1: nm_warning ("Modem second stage initialization timed out"); @@ -397,24 +357,11 @@ init_full_done (NMSerialDevice *device, } static void -init_modem_full (NMSerialDevice *device) +init_modem_full (NMGsmDevice *device) { - guint id; char *responses[] = { "OK", "ERROR", "ERR", NULL }; - /* At this point we know that SIM has been unlocked, and we can safely - * initialize the modem - */ - if (!nm_serial_device_send_command_string (device, "ATZ")) { - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); - return; - } - - id = nm_serial_device_wait_for_reply (device, 10, responses, responses, init_full_done, NULL); - if (id) - gsm_device_set_pending (NM_GSM_DEVICE (device), id); - else - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); + modem_wait_for_reply (device, "ATZ", 10, responses, responses, init_full_done); } static void @@ -424,10 +371,9 @@ enter_pin_done (NMSerialDevice *device, { NMSettingGsm *setting; - gsm_device_set_pending (NM_GSM_DEVICE (device), 0); switch (reply_index) { case 0: - init_modem_full (device); + init_modem_full (NM_GSM_DEVICE (device)); break; case -1: nm_warning ("Did not receive response for secret"); @@ -453,13 +399,13 @@ enter_pin_done (NMSerialDevice *device, break; } - enter_pin (device, TRUE); + enter_pin (NM_GSM_DEVICE (device), TRUE); break; } } static void -enter_pin (NMSerialDevice *device, gboolean retry) +enter_pin (NMGsmDevice *device, gboolean retry) { NMSettingGsm *setting; NMActRequest *req; @@ -490,23 +436,11 @@ enter_pin (NMSerialDevice *device, gboolean retry) if (secret) { char *command; - guint id; char *responses[] = { "OK", "ERROR", "ERR", NULL }; - gboolean success; command = g_strdup_printf ("AT+CPIN=\"%s\"", secret); - success = nm_serial_device_send_command_string (device, command); + modem_wait_for_reply (device, command, 3, responses, responses, enter_pin_done); g_free (command); - - if (success) { - id = nm_serial_device_wait_for_reply (device, 3, responses, responses, enter_pin_done, NULL); - if (id) - gsm_device_set_pending (NM_GSM_DEVICE (device), id); - else - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); - } else { - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); - } } else { nm_info ("(%s): GSM %s secret required", nm_device_get_iface (NM_DEVICE (device)), secret_name); nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_NEED_AUTH); @@ -519,19 +453,17 @@ check_pin_done (NMSerialDevice *device, int reply_index, gpointer user_data) { - gsm_device_set_pending (NM_GSM_DEVICE (device), 0); - switch (reply_index) { case 0: - do_register (device); + do_register (NM_GSM_DEVICE (device)); break; case 1: NM_GSM_DEVICE_GET_PRIVATE (device)->need_secret = NM_GSM_SECRET_PIN; - enter_pin (device, FALSE); + enter_pin (NM_GSM_DEVICE (device), FALSE); break; case 2: NM_GSM_DEVICE_GET_PRIVATE (device)->need_secret = NM_GSM_SECRET_PUK; - enter_pin (device, FALSE); + enter_pin (NM_GSM_DEVICE (device), FALSE); break; case -1: nm_warning ("PIN checking timed out"); @@ -545,22 +477,12 @@ check_pin_done (NMSerialDevice *device, } static void -check_pin (NMSerialDevice *device) +check_pin (NMGsmDevice *self) { - guint id; char *responses[] = { "READY", "SIM PIN", "SIM PUK", "ERROR", "ERR", NULL }; char *terminators[] = { "OK", "ERROR", "ERR", NULL }; - if (!nm_serial_device_send_command_string (device, "AT+CPIN?")) { - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); - return; - } - - id = nm_serial_device_wait_for_reply (device, 3, responses, terminators, check_pin_done, NULL); - if (id) - gsm_device_set_pending (NM_GSM_DEVICE (device), id); - else - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); + modem_wait_for_reply (self, "AT+CPIN?", 3, responses, terminators, check_pin_done); } static void @@ -568,11 +490,9 @@ init_done (NMSerialDevice *device, int reply_index, gpointer user_data) { - gsm_device_set_pending (NM_GSM_DEVICE (device), 0); - switch (reply_index) { case 0: - check_pin (device); + check_pin (NM_GSM_DEVICE (device)); break; case -1: nm_warning ("Modem initialization timed out"); @@ -588,18 +508,9 @@ init_done (NMSerialDevice *device, static void init_modem (NMSerialDevice *device, gpointer user_data) { - guint id; char *responses[] = { "OK", "ERROR", "ERR", NULL }; - if (!nm_serial_device_send_command_string (device, "ATZ E0")) { - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); - return; - } - id = nm_serial_device_wait_for_reply (device, 10, responses, responses, init_done, NULL); - if (id) - gsm_device_set_pending (NM_GSM_DEVICE (device), id); - else - nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_FAILED); + modem_wait_for_reply (NM_GSM_DEVICE (device), "AT E0", 10, responses, responses, init_done); } static NMActStageReturn @@ -608,6 +519,7 @@ real_act_stage1_prepare (NMDevice *device) NMGsmDevicePrivate *priv = NM_GSM_DEVICE_GET_PRIVATE (device); NMSerialDevice *serial_device = NM_SERIAL_DEVICE (device); NMSettingSerial *setting; + guint id; priv->need_secret = NM_GSM_SECRET_NONE; @@ -616,9 +528,9 @@ real_act_stage1_prepare (NMDevice *device) if (!nm_serial_device_open (serial_device, setting)) return NM_ACT_STAGE_RETURN_FAILURE; - priv->pending_id = nm_serial_device_flash (serial_device, 100, init_modem, NULL); + id = nm_serial_device_flash (serial_device, 100, init_modem, NULL); - return priv->pending_id ? NM_ACT_STAGE_RETURN_POSTPONE : NM_ACT_STAGE_RETURN_FAILURE; + return id ? NM_ACT_STAGE_RETURN_POSTPONE : NM_ACT_STAGE_RETURN_FAILURE; } static NMConnection * diff --git a/src/nm-serial-device.c b/src/nm-serial-device.c index 319e7b0f4d..5a642f02f7 100644 --- a/src/nm-serial-device.c +++ b/src/nm-serial-device.c @@ -36,6 +36,9 @@ typedef struct { NMIP4Config *pending_ip4_config; struct termios old_t; + guint pending_id; + guint timeout_id; + /* PPP stats */ guint32 in_bytes; guint32 out_bytes; @@ -228,6 +231,98 @@ serial_device_get_setting (NMSerialDevice *device, GType setting_type) return setting; } +/* Timeout handling */ + +static void +nm_serial_device_timeout_removed (gpointer data) +{ + NMSerialDevicePrivate *priv = NM_SERIAL_DEVICE_GET_PRIVATE (data); + + priv->timeout_id = 0; +} + +static gboolean +nm_serial_device_timed_out (gpointer data) +{ + NMSerialDevicePrivate *priv = NM_SERIAL_DEVICE_GET_PRIVATE (data); + + /* Cancel data reading */ + if (priv->pending_id) + g_source_remove (priv->pending_id); + else + nm_warning ("Timeout reached, but there's nothing to time out"); + + return FALSE; +} + +static void +nm_serial_device_add_timeout (NMSerialDevice *self, guint timeout) +{ + NMSerialDevicePrivate *priv = NM_SERIAL_DEVICE_GET_PRIVATE (self); + + if (priv->pending_id == 0) + nm_warning ("Adding a time out while not waiting for any data"); + + if (priv->timeout_id) { + nm_warning ("Trying to add a new time out while the old one still exists"); + g_source_remove (priv->timeout_id); + } + + priv->timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT, + timeout * 1000, + nm_serial_device_timed_out, + self, + nm_serial_device_timeout_removed); + if (G_UNLIKELY (priv->timeout_id == 0)) + nm_warning ("Registering serial device time out failed."); +} + +static void +nm_serial_device_remove_timeout (NMSerialDevice *self) +{ + NMSerialDevicePrivate *priv = NM_SERIAL_DEVICE_GET_PRIVATE (self); + + if (priv->timeout_id) + g_source_remove (priv->timeout_id); +} + +/* Pending data reading */ + +static guint +nm_serial_device_set_pending (NMSerialDevice *device, + guint timeout, + GIOFunc callback, + gpointer user_data, + GDestroyNotify notify) +{ + NMSerialDevicePrivate *priv = NM_SERIAL_DEVICE_GET_PRIVATE (device); + + if (G_UNLIKELY (priv->pending_id)) { + /* FIXME: Probably should queue up pending calls instead? */ + /* Multiple pending calls on the same GIOChannel doesn't work, so let's cancel the previous one. */ + nm_warning ("Adding new pending call while previous one isn't finished."); + nm_warning ("Cancelling the previous pending call."); + g_source_remove (priv->pending_id); + } + + priv->pending_id = g_io_add_watch_full (priv->channel, + G_PRIORITY_DEFAULT, + G_IO_IN | G_IO_ERR | G_IO_HUP, + callback, user_data, notify); + + nm_serial_device_add_timeout (device, timeout); + + return priv->pending_id;} + +static void +nm_serial_device_pending_done (NMSerialDevice *self) +{ + NM_SERIAL_DEVICE_GET_PRIVATE (self)->pending_id = 0; + nm_serial_device_remove_timeout (self); +} + +/****/ + static gboolean config_fd (NMSerialDevice *device, NMSettingSerial *setting) { @@ -315,6 +410,9 @@ nm_serial_device_close (NMSerialDevice *device) priv = NM_SERIAL_DEVICE_GET_PRIVATE (device); + if (priv->pending_id) + g_source_remove (priv->pending_id); + if (priv->fd) { nm_debug ("Closing device '%s'", nm_device_get_iface (NM_DEVICE (device))); @@ -389,34 +487,23 @@ typedef struct { GString *result; NMSerialGetReplyFn callback; gpointer user_data; - guint timeout_id; - guint got_data_id; } GetReplyInfo; static void -get_reply_info_destroy (gpointer data) +get_reply_done (gpointer data) { GetReplyInfo *info = (GetReplyInfo *) data; - if (info->got_data_id) - g_source_remove (info->got_data_id); + nm_serial_device_pending_done (info->device); + /* Call the callback */ + info->callback (info->device, info->result->str, info->user_data); + + /* Free info */ g_free (info->terminators); + g_string_free (info->result, TRUE); - if (info->result) - g_string_free (info->result, TRUE); - - g_free (info); -} - -static gboolean -get_reply_timeout (gpointer data) -{ - GetReplyInfo *info = (GetReplyInfo *) data; - - info->callback (info->device, NULL, info->user_data); - - return FALSE; + g_slice_free (GetReplyInfo, info); } static gboolean @@ -431,8 +518,10 @@ get_reply_got_data (GIOChannel *source, gboolean done = FALSE; int i; - if (!(condition & G_IO_IN)) - goto done; + if (condition & G_IO_HUP || condition & G_IO_ERR) { + g_string_truncate (info->result, 0); + return FALSE; + } do { GError *err = NULL; @@ -474,30 +563,11 @@ get_reply_got_data (GIOChannel *source, if (info->result->len > SERIAL_BUF_SIZE) { g_warning ("%s (%s): response buffer filled before repsonse received", __func__, nm_device_get_iface (NM_DEVICE (info->device))); - g_string_free (info->result, TRUE); - info->result = NULL; + g_string_truncate (info->result, 0); done = TRUE; } } while (!done || bytes_read == SERIAL_BUF_SIZE || status == G_IO_STATUS_AGAIN); -done: - if (condition & G_IO_HUP || condition & G_IO_ERR) { - g_string_free (info->result, TRUE); - info->result = NULL; - done = TRUE; - } - - if (done) { - char *result = info->result ? g_string_free (info->result, FALSE) : NULL; - info->result = NULL; - info->callback (info->device, result, info->user_data); - g_free (result); - - /* Clear the id - returning FALSE already removes it */ - info->got_data_id = 0; - g_source_remove (info->timeout_id); - } - return !done; } @@ -514,25 +584,14 @@ nm_serial_device_get_reply (NMSerialDevice *device, g_return_val_if_fail (terminators != NULL, 0); g_return_val_if_fail (callback != NULL, 0); - info = g_new (GetReplyInfo, 1); + info = g_slice_new0 (GetReplyInfo); info->device = device; info->terminators = g_strdup (terminators); info->result = g_string_new (NULL); info->callback = callback; info->user_data = user_data; - info->got_data_id = g_io_add_watch (NM_SERIAL_DEVICE_GET_PRIVATE (device)->channel, - G_IO_IN | G_IO_ERR | G_IO_HUP, - get_reply_got_data, - info); - - info->timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT, - timeout * 1000, - get_reply_timeout, - info, - get_reply_info_destroy); - - return info->timeout_id; + return nm_serial_device_set_pending (device, timeout, get_reply_got_data, info, get_reply_done); } typedef struct { @@ -542,36 +601,28 @@ typedef struct { GString *result; NMSerialWaitForReplyFn callback; gpointer user_data; + int reply_index; guint timeout; time_t start; - guint timeout_id; - guint got_data_id; } WaitForReplyInfo; static void -wait_for_reply_info_destroy (gpointer data) +wait_for_reply_done (gpointer data) { WaitForReplyInfo *info = (WaitForReplyInfo *) data; - if (info->got_data_id) - g_source_remove (info->got_data_id); + nm_serial_device_pending_done (info->device); + /* Call the callback */ + info->callback (info->device, info->reply_index, info->user_data); + + /* Free info */ if (info->result) g_string_free (info->result, TRUE); g_strfreev (info->str_needles); g_strfreev (info->terminators); - g_free (info); -} - -static gboolean -wait_for_reply_timeout (gpointer data) -{ - WaitForReplyInfo *info = (WaitForReplyInfo *) data; - - info->callback (info->device, -1, info->user_data); - - return FALSE; + g_slice_free (WaitForReplyInfo, info); } static gboolean @@ -614,10 +665,9 @@ wait_for_reply_got_data (GIOChannel *source, GIOStatus status; gboolean got_response = FALSE; gboolean done = FALSE; - int idx = -1; - if (!(condition & G_IO_IN)) - goto done; + if (condition & G_IO_HUP || condition & G_IO_ERR) + return FALSE; do { GError *err = NULL; @@ -663,8 +713,8 @@ wait_for_reply_got_data (GIOChannel *source, tmp = g_strstrip (line); if (tmp && strlen (tmp)) { done = find_terminator (tmp, info->terminators); - if (idx == -1) - got_response = find_response (tmp, info->str_needles, &idx); + if (info->reply_index == -1) + got_response = find_response (tmp, info->str_needles, &(info->reply_index)); } } @@ -692,18 +742,6 @@ wait_for_reply_got_data (GIOChannel *source, g_usleep (50); } while (!done || bytes_read == SERIAL_BUF_SIZE || status == G_IO_STATUS_AGAIN); -done: - if (condition & G_IO_HUP || condition & G_IO_ERR) - done = TRUE; - - if (done) { - info->callback (info->device, idx, info->user_data); - - /* Clear the id - returning FALSE already removes it */ - info->got_data_id = 0; - g_source_remove (info->timeout_id); - } - return !done; } @@ -721,28 +759,18 @@ nm_serial_device_wait_for_reply (NMSerialDevice *device, g_return_val_if_fail (responses != NULL, 0); g_return_val_if_fail (callback != NULL, 0); - info = g_new0 (WaitForReplyInfo, 1); + info = g_slice_new0 (WaitForReplyInfo); info->device = device; info->str_needles = g_strdupv (responses); info->terminators = g_strdupv (terminators); info->result = g_string_new (NULL); info->callback = callback; info->user_data = user_data; - - info->got_data_id = g_io_add_watch (NM_SERIAL_DEVICE_GET_PRIVATE (device)->channel, - G_IO_IN | G_IO_ERR | G_IO_HUP, - wait_for_reply_got_data, - info); - + info->reply_index = -1; info->timeout = timeout * 1000; info->start = time (NULL); - info->timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT, - timeout * 1000, - wait_for_reply_timeout, - info, - wait_for_reply_info_destroy); - return info->timeout_id; + return nm_serial_device_set_pending (device, timeout, wait_for_reply_got_data, info, wait_for_reply_done); } #if 0 @@ -753,14 +781,18 @@ typedef struct { gpointer user_data; } WaitQuietInfo; -static gboolean +static void wait_quiet_done (gpointer data) { WaitQuietInfo *info = (WaitQuietInfo *) data; + nm_serial_device_pending_done (info->device); + + /* Call the callback */ info->callback (info->device, info->timed_out, info->user_data); - return FALSE; + /* Free info */ + g_slice_free (WaitQuietInfo, info); } static gboolean @@ -769,7 +801,7 @@ wait_quiet_quiettime (gpointer data) WaitQuietInfo *info = (WaitQuietInfo *) data; info->timed_out = FALSE; - wait_quiet_done (data); + g_source_remove (NM_SERIAL_DEVICE_GET_PRIVATE (info->device)->pending); return FALSE; } @@ -784,6 +816,9 @@ wait_quiet_got_data (GIOChannel *source, char buf[4096]; GIOStatus status; + if (condition & G_IO_HUP || condition & G_IO_ERR) + return FALSE; + if (condition & G_IO_IN) { do { status = g_io_channel_read_chars (source, buf, 4096, &bytes_read, NULL); @@ -796,11 +831,6 @@ wait_quiet_got_data (GIOChannel *source, } while (bytes_read == 4096 || status == G_IO_STATUS_AGAIN); } - if (condition & G_IO_HUP || condition & G_IO_ERR) { - wait_quiet_done (data); - return FALSE - } - return TRUE; } @@ -816,27 +846,16 @@ nm_serial_device_wait_quiet (NMSerialDevice *device, g_return_if_fail (NM_IS_SERIAL_DEVICE (device)); g_return_if_fail (callback != NULL); - info = g_new (WaitQuietInfo, 1); - + info = g_slice_new0 (WaitQuietInfo); info->device = device; info->timed_out = TRUE; info->callback = callback; info->user_data = user_data; - - info->got_data_id = g_io_add_watch (NM_SERIAL_DEVICE_GET_PRIVATE (device)->channel, - G_IO_IN | G_IO_ERR | G_IO_HUP, - wait_quiet_got_data, - info); - info->quiet_id = g_timeout_add (quiet_time, wait_quiet_timeout, info); - info->timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT, - timeout, - wait_quiet_timeout, - info, - wait_quiet_info_destroy); + return nm_serial_device_set_pending (device, timeout, wait_quiet_got_data, info, wait_quiet_done); } #endif @@ -874,14 +893,25 @@ set_speed (NMSerialDevice *device, speed_t speed) tcsetattr (fd, TCSANOW, &options); } -static gboolean +static void flash_done (gpointer data) { FlashInfo *info = (FlashInfo *) data; - set_speed (info->device, info->current_speed); + NM_SERIAL_DEVICE_GET_PRIVATE (info->device)->pending_id = 0; + info->callback (info->device, info->user_data); + g_slice_free (FlashInfo, info); +} + +static gboolean +flash_do (gpointer data) +{ + FlashInfo *info = (FlashInfo *) data; + + set_speed (info->device, info->current_speed); + return FALSE; } @@ -892,11 +922,12 @@ nm_serial_device_flash (NMSerialDevice *device, gpointer user_data) { FlashInfo *info; + guint id; g_return_val_if_fail (NM_IS_SERIAL_DEVICE (device), 0); g_return_val_if_fail (callback != NULL, 0); - info = g_new (FlashInfo, 1); + info = g_slice_new0 (FlashInfo); info->device = device; info->current_speed = get_speed (device); info->callback = callback; @@ -904,11 +935,15 @@ nm_serial_device_flash (NMSerialDevice *device, set_speed (device, B0); - return g_timeout_add_full (G_PRIORITY_DEFAULT, - flash_time, - flash_done, - info, - g_free); + id = g_timeout_add_full (G_PRIORITY_DEFAULT, + flash_time, + flash_do, + info, + flash_done); + + NM_SERIAL_DEVICE_GET_PRIVATE (device)->pending_id = id; + + return id; } GIOChannel *