ppp: use queue to transmit

Since we are using non buffered I/O, use a queue to transmit when buffer
space is available.
This commit is contained in:
Kristen Carlson Accardi 2010-04-02 11:13:20 -07:00 committed by Denis Kenzior
parent 1ed6966cb4
commit 74e1abd353
3 changed files with 94 additions and 44 deletions

View 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);
}

View 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);

View 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);
}