ppp: use queue to transmit
authorKristen Carlson Accardi <kristen@linux.intel.com>
Fri, 2 Apr 2010 18:13:20 +0000 (11:13 -0700)
committerDenis Kenzior <denkenz@gmail.com>
Fri, 2 Apr 2010 18:05:47 +0000 (13:05 -0500)
Since we are using non buffered I/O, use a queue to transmit when buffer
space is available.

gatchat/gatppp.c
gatchat/ppp.h
gatchat/ppp_cp.c

index c38c20a..2462e7b 100644 (file)
@@ -135,17 +135,20 @@ static void ppp_put(GAtPPP *ppp, guint8 *buf, int *pos,
 }
 
 /* XXX implement PFC and ACFC */
-static guint8 *ppp_encode(GAtPPP *ppp, guint8 *data, int len,
-                               guint *newlen)
+static struct frame_buffer *ppp_encode(GAtPPP *ppp, guint8 *data, int len)
 {
        int pos = 0;
        int i = 0;
        guint16 fcs = PPPINITFCS16;
        guint16 proto = get_host_short(data);
        gboolean lcp = (proto == LCP_PROTOCOL);
-       guint8 *frame = g_try_malloc0(BUFFERSZ);
-       if (!frame)
+       guint8 *frame;
+       struct frame_buffer *fb =
+               g_try_malloc0(BUFFERSZ + sizeof(struct frame_buffer));
+
+       if (!fb)
                return NULL;
+       frame = fb->bytes;
 
        /* copy in the HDLC framing */
        frame[pos++] = PPP_FLAG_SEQ;
@@ -173,8 +176,8 @@ static guint8 *ppp_encode(GAtPPP *ppp, guint8 *data, int len,
        /* add flag */
        frame[pos++] = PPP_FLAG_SEQ;
 
-       *newlen = pos;
-       return frame;
+       fb->len = pos;
+       return fb;
 }
 
 static gint is_proto_handler(gconstpointer a, gconstpointer b)
@@ -316,41 +319,6 @@ static void ppp_record(GAtPPP *ppp, gboolean in, guint8 *data, guint16 length)
        err = write(ppp->record_fd, data, length);
 }
 
-/*
- * transmit out through the lower layer interface
- *
- * infolen - length of the information part of the packet
- */
-void ppp_transmit(GAtPPP *ppp, guint8 *packet, guint infolen)
-{
-       guint8 *frame;
-       guint framelen;
-       GError *error = NULL;
-       GIOStatus status;
-       gsize bytes_written;
-
-       /*
-        * do the octet stuffing.  Add 2 bytes to the infolen to
-        * include the protocol field.
-        */
-       frame = ppp_encode(ppp, packet, infolen + 2, &framelen);
-       if (!frame) {
-               g_printerr("Failed to encode packet to transmit\n");
-               return;
-       }
-
-       /* transmit through the lower layer interface */
-       /*
-        * TBD - should we just put this on a queue and transmit when
-        * we won't block, or allow ourselves to block here?
-        */
-       status = g_io_channel_write_chars(ppp->modem, (gchar *) frame,
-                                       framelen, &bytes_written, &error);
-       ppp_record(ppp, FALSE, frame, bytes_written);
-
-       g_free(frame);
-}
-
 static gboolean ppp_cb(GIOChannel *channel, GIOCondition cond, gpointer data)
 {
        GAtPPP *ppp = data;
@@ -378,6 +346,9 @@ static gboolean ppp_cb(GIOChannel *channel, GIOCondition cond, gpointer data)
 
 static void ppp_dead(GAtPPP *ppp)
 {
+       if (ppp->write_watch)
+               return;
+
        /* notify interested parties */
        if (ppp->disconnect_cb)
                ppp->disconnect_cb(ppp->disconnect_data);
@@ -385,8 +356,12 @@ static void ppp_dead(GAtPPP *ppp)
        if (g_atomic_int_get(&ppp->ref_count))
                return;
 
+       /* cleanup queue */
+       g_queue_free(ppp->xmit_queue);
+
        /* cleanup modem channel */
-       g_source_remove(ppp->modem_watch);
+       g_source_remove(ppp->read_watch);
+       g_source_remove(ppp->write_watch);
        g_io_channel_unref(ppp->modem);
 
        lcp_free(ppp->lcp);
@@ -619,6 +594,9 @@ GAtPPP *g_at_ppp_new(GIOChannel *modem)
 
        ppp->index = 0;
 
+       /* intialize the queue */
+       ppp->xmit_queue = g_queue_new();
+
        /* initialize the lcp state */
        ppp->lcp = lcp_new(ppp);
 
@@ -632,7 +610,7 @@ GAtPPP *g_at_ppp_new(GIOChannel *modem)
        ppp->net = ppp_net_new(ppp);
 
        /* start listening for packets from the modem */
-       ppp->modem_watch = g_io_add_watch(modem,
+       ppp->read_watch = g_io_add_watch(modem,
                        G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
                        ppp_cb, ppp);
 
@@ -640,3 +618,72 @@ GAtPPP *g_at_ppp_new(GIOChannel *modem)
 
        return ppp;
 }
+
+static gboolean ppp_xmit_cb(GIOChannel *channel, GIOCondition cond,
+                               gpointer data)
+{
+       GAtPPP *ppp = data;
+       struct frame_buffer *fb;
+       GError *error = NULL;
+       GIOStatus status;
+       gsize bytes_written;
+
+       if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
+               return FALSE;
+
+       if (cond & G_IO_OUT) {
+               while ((fb = g_queue_peek_head(ppp->xmit_queue))) {
+                       status = g_io_channel_write_chars(ppp->modem,
+                                       (gchar *) fb->bytes, fb->len,
+                                        &bytes_written, &error);
+                       if (status != G_IO_STATUS_NORMAL &&
+                               status != G_IO_STATUS_AGAIN)
+                               return FALSE;
+
+                       if (bytes_written < fb->len)
+                               return TRUE;
+
+                       ppp_record(ppp, FALSE, fb->bytes, bytes_written);
+                       g_free(g_queue_pop_head(ppp->xmit_queue));
+               }
+       }
+       return FALSE;
+}
+
+static void ppp_xmit_destroy_notify(gpointer destroy_data)
+{
+       GAtPPP *ppp = destroy_data;
+
+       g_print("%s\n", __FUNCTION__);
+
+       ppp->write_watch = 0;
+       if (ppp->phase == PPP_DEAD)
+               ppp_dead(ppp);
+}
+
+/*
+ * transmit out through the lower layer interface
+ *
+ * infolen - length of the information part of the packet
+ */
+void ppp_transmit(GAtPPP *ppp, guint8 *packet, guint infolen)
+{
+       struct frame_buffer *fb;
+
+       /*
+        * do the octet stuffing.  Add 2 bytes to the infolen to
+        * include the protocol field.
+        */
+       fb = ppp_encode(ppp, packet, infolen + 2);
+       if (!fb) {
+               g_printerr("Failed to encode packet to transmit\n");
+               return;
+       }
+       /* push decoded frame onto xmit queue */
+       g_queue_push_tail(ppp->xmit_queue, fb);
+
+       /* transmit this whenever we can write without blocking */
+       ppp->write_watch = g_io_add_watch_full(ppp->modem, G_PRIORITY_DEFAULT,
+                               G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               ppp_xmit_cb, ppp, ppp_xmit_destroy_notify);
+}
index f2b4175..1262c12 100644 (file)
@@ -135,10 +135,12 @@ struct _GAtPPP {
        gpointer connect_data;
        GAtDisconnectFunc disconnect_cb;
        gpointer disconnect_data;
-       gint modem_watch;
+       gint read_watch;
+       gint write_watch;
        GAtDebugFunc debugf;
        gpointer debug_data;
        int record_fd;
+       GQueue *xmit_queue;
 };
 
 void ppp_generate_event(GAtPPP *ppp, enum ppp_event event);
index d74a07b..16c0603 100644 (file)
@@ -164,6 +164,7 @@ static void pppcp_this_layer_finished(struct pppcp_data *data)
 {
        struct pppcp_action *action = data->action;
 
+       pppcp_trace(data);
        if (action->this_layer_finished)
                action->this_layer_finished(data);
 }