From 263be58465ba0e449d73b65fd69d5dc10423a78f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 15 Feb 2013 13:42:44 -0600 Subject: 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): <-- 'CONNECT' 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}%~' --- src/mm-serial-port.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/mm-serial-port.c b/src/mm-serial-port.c index 87f06e27..45e10094 100644 --- a/src/mm-serial-port.c +++ b/src/mm-serial-port.c @@ -807,6 +807,27 @@ data_available (GIOChannel *source, return TRUE; } +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) { @@ -833,6 +854,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 @@ -914,9 +938,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, @@ -998,8 +1020,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; -- cgit v1.2.3-70-g09d2