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}%~'
This commit is contained in:
Dan Williams
2013-02-15 13:42:44 -06:00
parent 5280364c4b
commit 263be58465

View File

@@ -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;