From bcbf96cf7fb0eb69e8b5d24efbe3e40d968ccd94 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 17 Apr 2008 11:08:52 +0000 Subject: [PATCH] 2008-04-17 Dan Williams * src/nm-serial-device.c src/nm-serial-device.h - (wait_for_reply_got_data): break input into lines, and search each line for responses _and_ terminator strings; also make sure that the read loop doesn't continue after the timeout is supposed to fire - (nm_serial_device_wait_for_reply): take an array of terminators too * src/nm-gsm-device.c src/nm-cdma-device.c - Send terminators to nm_serial_device_wait_for_reply() git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3570 4912f4e0-d625-0410-9fb7-b9a5a253dbdc --- ChangeLog | 13 ++++++ src/nm-cdma-device.c | 6 +-- src/nm-gsm-device.c | 16 ++++--- src/nm-serial-device.c | 102 +++++++++++++++++++++++++++++++++-------- src/nm-serial-device.h | 1 + 5 files changed, 110 insertions(+), 28 deletions(-) diff --git a/ChangeLog b/ChangeLog index b947ead053..09c0becebb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2008-04-17 Dan Williams + + * src/nm-serial-device.c + src/nm-serial-device.h + - (wait_for_reply_got_data): break input into lines, and search each + line for responses _and_ terminator strings; also make sure that + the read loop doesn't continue after the timeout is supposed to fire + - (nm_serial_device_wait_for_reply): take an array of terminators too + + * src/nm-gsm-device.c + src/nm-cdma-device.c + - Send terminators to nm_serial_device_wait_for_reply() + 2008-04-16 Dan Williams Patch from 陈鑫 diff --git a/src/nm-cdma-device.c b/src/nm-cdma-device.c index 10344ad875..19aa77017d 100644 --- a/src/nm-cdma-device.c +++ b/src/nm-cdma-device.c @@ -135,7 +135,7 @@ do_dial (NMSerialDevice *device) g_free (command); if (success) { - id = nm_serial_device_wait_for_reply (device, 60, responses, dial_done, NULL); + 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 @@ -171,14 +171,14 @@ static void init_modem (NMSerialDevice *device, gpointer user_data) { guint id; - char *responses[] = { "OK", "ERR", NULL }; + 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, 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); diff --git a/src/nm-gsm-device.c b/src/nm-gsm-device.c index 5a71bff2f0..b8a5fa34c3 100644 --- a/src/nm-gsm-device.c +++ b/src/nm-gsm-device.c @@ -144,7 +144,7 @@ do_dial (NMSerialDevice *device) g_free (command); if (success) { - id = nm_serial_device_wait_for_reply (device, 60, responses, dial_done, NULL); + 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 @@ -192,7 +192,7 @@ manual_registration (NMSerialDevice *device) g_free (command); if (success) { - id = nm_serial_device_wait_for_reply (device, 30, responses, manual_registration_done, NULL); + 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 @@ -282,13 +282,14 @@ automatic_registration (NMSerialDevice *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, automatic_registration_response, NULL); + 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 @@ -391,7 +392,7 @@ enter_pin (NMSerialDevice *device, gboolean retry) g_free (command); if (success) { - id = nm_serial_device_wait_for_reply (device, 3, responses, enter_pin_done, NULL); + 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 @@ -441,13 +442,14 @@ check_pin (NMSerialDevice *device) { 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, check_pin_done, NULL); + 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 @@ -480,14 +482,14 @@ static void init_modem (NMSerialDevice *device, gpointer user_data) { guint id; - char *responses[] = { "OK", "ERR", NULL }; + 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, init_done, NULL); + 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 diff --git a/src/nm-serial-device.c b/src/nm-serial-device.c index 14a2e6dcd3..d862dabed3 100644 --- a/src/nm-serial-device.c +++ b/src/nm-serial-device.c @@ -524,9 +524,12 @@ nm_serial_device_get_reply (NMSerialDevice *device, typedef struct { NMSerialDevice *device; char **str_needles; + char **terminators; GString *result; NMSerialWaitForReplyFn callback; gpointer user_data; + guint timeout; + time_t start; guint timeout_id; guint got_data_id; } WaitForReplyInfo; @@ -543,6 +546,7 @@ wait_for_reply_info_destroy (gpointer data) g_string_free (info->result, TRUE); g_strfreev (info->str_needles); + g_strfreev (info->terminators); g_free (info); } @@ -556,6 +560,35 @@ wait_for_reply_timeout (gpointer data) return FALSE; } +static gboolean +find_terminator (const char *line, char **terminators) +{ + int i; + + for (i = 0; terminators[i]; i++) { + if (!strcasecmp (line, terminators[i])) + return TRUE; + } + return FALSE; +} + +static gboolean +find_response (const char *line, char **responses, gint *idx) +{ + int i; + + /* Don't look for a result again if we got one previously */ + for (i = 0; responses[i]; i++) { + if (strcasestr (line, responses[i])) { + *idx = i; + return TRUE; + } + } + return FALSE; +} + +#define RESPONSE_LINE_MAX 128 + static gboolean wait_for_reply_got_data (GIOChannel *source, GIOCondition condition, @@ -565,9 +598,9 @@ wait_for_reply_got_data (GIOChannel *source, gchar buf[SERIAL_BUF_SIZE + 1]; gsize bytes_read; GIOStatus status; + gboolean got_response = FALSE; gboolean done = FALSE; int idx = -1; - int i; if (!(condition & G_IO_IN)) goto done; @@ -587,14 +620,42 @@ wait_for_reply_got_data (GIOChannel *source, g_string_append (info->result, buf); serial_debug ("Got:", info->result->str, info->result->len); + } - for (i = 0; info->str_needles[i]; i++) { - if ( info->result->str - && strcasestr (info->result->str, info->str_needles[i])) { - idx = i; - done = TRUE; + /* Look for needles and terminators */ + if ((bytes_read > 0) && info->result->str) { + char *p = info->result->str; + + /* Break the response up into lines and process each one */ + while ( (p < info->result->str + strlen (info->result->str)) + && !(done && got_response)) { + char line[RESPONSE_LINE_MAX] = { '\0', }; + char *tmp; + int i; + gboolean got_something = FALSE; + + for (i = 0; *p && (i < RESPONSE_LINE_MAX - 1); p++) { + /* Ignore front CR/LF */ + if ((*p == '\n') || (*p == '\r')) { + if (got_something) + break; + } else { + line[i++] = *p; + got_something = TRUE; + } + } + line[i] = '\0'; + + 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 (done && got_response) + break; } /* Limit the size of the buffer */ @@ -602,7 +663,19 @@ wait_for_reply_got_data (GIOChannel *source, g_warning ("%s (%s): response buffer filled before repsonse received", __func__, nm_device_get_iface (NM_DEVICE (info->device))); done = TRUE; + break; } + + /* Make sure we don't go over the timeout, in addition to the timeout + * handler that's been scheduled. If for some reason this loop doesn't + * terminate (terminator not found, whatever) then this should make + * sure that NM doesn't spin the CPU forever. + */ + if (time (NULL) - info->start > info->timeout + 1) { + done = TRUE; + break; + } else + g_usleep (50); } while (!done || bytes_read == SERIAL_BUF_SIZE || status == G_IO_STATUS_AGAIN); done: @@ -624,29 +697,20 @@ guint nm_serial_device_wait_for_reply (NMSerialDevice *device, guint timeout, char **responses, + char **terminators, NMSerialWaitForReplyFn callback, gpointer user_data) { WaitForReplyInfo *info; - char **str_array; - int i; g_return_val_if_fail (NM_IS_SERIAL_DEVICE (device), 0); g_return_val_if_fail (responses != NULL, 0); g_return_val_if_fail (callback != NULL, 0); - /* Copy the array */ - str_array = g_new (char*, g_strv_length (responses) + 1); - i = 0; - while (responses[i]) { - str_array[i] = g_strdup (responses[i]); - i++; - } - str_array[i] = NULL; - info = g_new0 (WaitForReplyInfo, 1); info->device = device; - info->str_needles = str_array; + 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; @@ -656,6 +720,8 @@ nm_serial_device_wait_for_reply (NMSerialDevice *device, wait_for_reply_got_data, info); + info->timeout = timeout * 1000; + info->start = time (NULL); info->timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT, timeout * 1000, wait_for_reply_timeout, diff --git a/src/nm-serial-device.h b/src/nm-serial-device.h index 6f30047a19..b6f8134d8e 100644 --- a/src/nm-serial-device.h +++ b/src/nm-serial-device.h @@ -61,6 +61,7 @@ guint nm_serial_device_get_reply (NMSerialDevice *device, guint nm_serial_device_wait_for_reply (NMSerialDevice *device, guint timeout, char **responses, + char **terminators, NMSerialWaitForReplyFn callback, gpointer user_data);