aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2013-02-15 13:42:44 -0600
committerDan Williams <dcbw@redhat.com>2013-02-15 13:48:51 -0600
commit27408b4c1e13e3016a01e5b273e66d99f487d3ad (patch)
tree517f4c10c6c56eaa1d4f652d614ce8673471531d
parentcffdb733002546b0cfa6d529f23f1777b8acd9ad (diff)
serial-port: don't steal data from PPP when connected
There was a race where if PPP was slow to start, MM could read the first bits of PPP from the port, which MM shouldn't really do. So if the port is connected, remove our GIOChannel watch and let pppd handle all the data. When the port is disconnected, re-attach our watch and start reading from the port again. This may make it harder to detect spurious disconnects if for example pppd drops the connection and the thing controlling PPP (eg, NetworkManager or something else) doesn't tell us about that event by disconnecting the bearer. This is arguably programmer error though. See the logs in https://bugzilla.gnome.org/show_bug.cgi?id=624956#c10 for an example of this: DEBUG: <1280300196.929489> (ttyACM0): <-- '<CR><LF>CONNECT<CR><LF>' DEBUG: <1280300196.929761> (ttyACM0): port now connected DEBUG: <1280300196.929853> Modem /org/freedesktop/ModemManager/Modems/0: state changed (connecting -> connected) DEBUG: <1280300196.929954> (ttyACM0): simple connect state 6 DEBUG: <1280300196.933432> (ttyACM0): <-- '~\-1}#\-64!}!} } }2}#}$\-64#}!}$}%\-36}"}&} }*} } g}%~'
-rw-r--r--src/mm-serial-port.c31
1 files changed, 26 insertions, 5 deletions
diff --git a/src/mm-serial-port.c b/src/mm-serial-port.c
index 497d14cb..8538cd6b 100644
--- a/src/mm-serial-port.c
+++ b/src/mm-serial-port.c
@@ -754,6 +754,27 @@ data_available (GIOChannel *source,
}
static void
+data_watch_enable (MMSerialPort *self, gboolean enable)
+{
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+
+ if (priv->watch_id) {
+ if (enable)
+ g_warn_if_fail (priv->watch_id == 0);
+
+ g_source_remove (priv->watch_id);
+ priv->watch_id = 0;
+ }
+
+ if (enable) {
+ g_return_if_fail (priv->channel != NULL);
+ priv->watch_id = g_io_add_watch (priv->channel,
+ G_IO_IN | G_IO_ERR | G_IO_HUP,
+ data_available, self);
+ }
+}
+
+static void
port_connected (MMSerialPort *self, GParamSpec *pspec, gpointer user_data)
{
MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
@@ -780,6 +801,9 @@ port_connected (MMSerialPort *self, GParamSpec *pspec, gpointer user_data)
// close the port and error out?
}
}
+
+ /* When connected ignore let PPP have all the data */
+ data_watch_enable (self, !connected);
}
gboolean
@@ -861,9 +885,7 @@ mm_serial_port_open (MMSerialPort *self, GError **error)
priv->channel = g_io_channel_unix_new (priv->fd);
g_io_channel_set_encoding (priv->channel, NULL, NULL);
- priv->watch_id = g_io_add_watch (priv->channel,
- G_IO_IN | G_IO_ERR | G_IO_HUP,
- data_available, self);
+ data_watch_enable (self, TRUE);
g_warn_if_fail (priv->connected_id == 0);
priv->connected_id = g_signal_connect (self, "notify::" MM_PORT_CONNECTED,
@@ -939,8 +961,7 @@ mm_serial_port_close (MMSerialPort *self)
g_get_current_time (&tv_start);
if (priv->channel) {
- g_source_remove (priv->watch_id);
- priv->watch_id = 0;
+ data_watch_enable (self, FALSE);
g_io_channel_shutdown (priv->channel, TRUE, NULL);
g_io_channel_unref (priv->channel);
priv->channel = NULL;