# HG changeset patch # User Evan Schoenberg # Date 1216532862 0 # Node ID 0a674616953cd2b0f0071f682a9dba9dfe50425a # Parent de24d89313b06744c6c3ea97831c5dccf911be3d Added `flap_connection_send_snac_with_priority()`, which allows specifying high versus low priority for the SNAC to be sent. If we are not rate limited, a SNAC is always sent immediately. If we are at or near the rate limit, the SNAC may be queued to be sent when it wouldn't violate a rate limit to do so. Previously, SNACs were always sent in the order requested. A SNAC may now be set to be low priority, in which case other SNACs will be sent first if a queue is in use. This means that even if we have 120 'get ICQ status note' requests in the queue, a 'send message' SNAC can still be sent nearly immediately (rather than after a 10 minute or so delay). `flap_connection_send_snac_()` calls `flap_connection_send_snac_with_priority` with high priority. Get Info requests (including ICQ Status Note requests) are the only low priority SNACs at this time. diff -r de24d89313b0 -r 0a674616953c libpurple/protocols/oscar/family_icq.c --- a/libpurple/protocols/oscar/family_icq.c Thu Jul 17 16:48:37 2008 +0000 +++ b/libpurple/protocols/oscar/family_icq.c Sun Jul 20 05:47:42 2008 +0000 @@ -214,7 +214,7 @@ byte_stream_putle16(&bs, 0x04b2); /* shrug. */ byte_stream_putle32(&bs, atoi(uin)); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs); + flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, /* High priority? */ FALSE); byte_stream_destroy(&bs); @@ -497,7 +497,7 @@ byte_stream_put16(&bs, strlen(uin)); byte_stream_putstr(&bs, uin); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x000, snacid, &bs); + flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x000, snacid, &bs, /* High priority? */ FALSE); byte_stream_destroy(&bs); diff -r de24d89313b0 -r 0a674616953c libpurple/protocols/oscar/family_locate.c --- a/libpurple/protocols/oscar/family_locate.c Thu Jul 17 16:48:37 2008 +0000 +++ b/libpurple/protocols/oscar/family_locate.c Sun Jul 20 05:47:42 2008 +0000 @@ -1386,7 +1386,7 @@ byte_stream_putstr(&bs, sn); snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, sn, strlen(sn)+1); - flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, snacid, &bs); + flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, snacid, &bs, /* High priority? */ FALSE); byte_stream_destroy(&bs); diff -r de24d89313b0 -r 0a674616953c libpurple/protocols/oscar/flap_connection.c --- a/libpurple/protocols/oscar/flap_connection.c Thu Jul 17 16:48:37 2008 +0000 +++ b/libpurple/protocols/oscar/flap_connection.c Sun Jul 20 05:47:42 2008 +0000 @@ -107,21 +107,18 @@ return MIN(((rateclass->current * (rateclass->windowsize - 1)) + timediff) / rateclass->windowsize, rateclass->max); } -static gboolean flap_connection_send_queued(gpointer data) +/* + * Attempt to send the contents of a given queue + * @result TRUE if the queue was completely emptied or was iniitally empty; FALSE if rate limiting prevented it from being emptied + */ +static gboolean flap_connection_send_snac_queue(FlapConnection *conn, struct timeval now, GQueue *queue) { - FlapConnection *conn; - struct timeval now; - - conn = data; - gettimeofday(&now, NULL); - - purple_debug_info("oscar", "Attempting to send %u queued SNACs for %p\n", g_queue_get_length(conn->queued_snacs), conn); - while (!g_queue_is_empty(conn->queued_snacs)) + while (!g_queue_is_empty(queue)) { QueuedSnac *queued_snac; struct rateclass *rateclass; - queued_snac = g_queue_peek_head(conn->queued_snacs); + queued_snac = g_queue_peek_head(queue); rateclass = flap_connection_get_rateclass(conn, queued_snac->family, queued_snac->subtype); if (rateclass != NULL) @@ -133,8 +130,8 @@ /* (Add 100ms padding to account for inaccuracies in the calculation) */ if (new_current < rateclass->alert + 100) /* Not ready to send this SNAC yet--keep waiting. */ - return TRUE; - + return FALSE; + rateclass->current = new_current; rateclass->last.tv_sec = now.tv_sec; rateclass->last.tv_usec = now.tv_usec; @@ -142,11 +139,35 @@ flap_connection_send(conn, queued_snac->frame); g_free(queued_snac); - g_queue_pop_head(conn->queued_snacs); + g_queue_pop_head(queue); } - conn->queued_timeout = 0; - return FALSE; + /* We emptied the queue */ + return TRUE; +} + +static gboolean flap_connection_send_queued(gpointer data) +{ + FlapConnection *conn; + struct timeval now; + + conn = data; + gettimeofday(&now, NULL); + + purple_debug_info("oscar", "Attempting to send %u queued SNACs and %u queued low-priority SNACs for %p\n", + (conn->queued_snacs ? g_queue_get_length(conn->queued_snacs) : 0), + (conn->queued_lowpriority_snacs ? g_queue_get_length(conn->queued_lowpriority_snacs) : 0), + conn); + if (!conn->queued_snacs || flap_connection_send_snac_queue(conn, now, conn->queued_snacs)) { + if (!conn->queued_lowpriority_snacs || flap_connection_send_snac_queue(conn, now, conn->queued_lowpriority_snacs)) { + /* Both queues emptied. */ + conn->queued_timeout = 0; + return FALSE; + } + } + + /* We couldn't send all our SNACs. Keep trying */ + return TRUE; } /** @@ -157,9 +178,10 @@ * * @param data The optional bytestream that makes up the data portion * of this SNAC. For empty SNACs this should be NULL. + * @param high_priority If TRUE, the SNAC will be queued normally if needed. If FALSE, it wil be queued separately, to be sent only if all high priority SNACs have been sent. */ void -flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data) +flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data, gboolean high_priority) { FlapFrame *frame; guint32 length; @@ -213,7 +235,16 @@ queued_snac->family = family; queued_snac->subtype = subtype; queued_snac->frame = frame; - g_queue_push_tail(conn->queued_snacs, queued_snac); + + if (high_priority) { + if (!conn->queued_snacs) + conn->queued_snacs = g_queue_new(); + g_queue_push_tail(conn->queued_snacs, queued_snac); + } else { + if (!conn->queued_lowpriority_snacs) + conn->queued_lowpriority_snacs = g_queue_new(); + g_queue_push_tail(conn->queued_lowpriority_snacs, queued_snac); + } if (conn->queued_timeout == 0) conn->queued_timeout = purple_timeout_add(500, flap_connection_send_queued, conn); @@ -224,6 +255,12 @@ flap_connection_send(conn, frame); } +void +flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data) +{ + flap_connection_send_snac_with_priority(od, conn, family, subtype, flags, snacid, data, /* High priority? */ TRUE); +} + /** * This sends an empty channel 4 FLAP. This is sent to signify * that we're logging off. This shouldn't really be necessary-- @@ -275,7 +312,6 @@ conn->fd = -1; conn->subtype = -1; conn->type = type; - conn->queued_snacs = g_queue_new(); od->oscar_connections = g_slist_prepend(od->oscar_connections, conn); @@ -434,14 +470,28 @@ conn->rateclasses = g_slist_delete_link(conn->rateclasses, conn->rateclasses); } - while (!g_queue_is_empty(conn->queued_snacs)) - { - QueuedSnac *queued_snac; - queued_snac = g_queue_pop_head(conn->queued_snacs); - flap_frame_destroy(queued_snac->frame); - g_free(queued_snac); + if (conn->queued_snacs) { + while (!g_queue_is_empty(conn->queued_snacs)) + { + QueuedSnac *queued_snac; + queued_snac = g_queue_pop_head(conn->queued_snacs); + flap_frame_destroy(queued_snac->frame); + g_free(queued_snac); + } + g_queue_free(conn->queued_snacs); } - g_queue_free(conn->queued_snacs); + + if (conn->queued_lowpriority_snacs) { + while (!g_queue_is_empty(conn->queued_lowpriority_snacs)) + { + QueuedSnac *queued_snac; + queued_snac = g_queue_pop_head(conn->queued_lowpriority_snacs); + flap_frame_destroy(queued_snac->frame); + g_free(queued_snac); + } + g_queue_free(conn->queued_lowpriority_snacs); + } + if (conn->queued_timeout > 0) purple_timeout_remove(conn->queued_timeout); diff -r de24d89313b0 -r 0a674616953c libpurple/protocols/oscar/oscar.h --- a/libpurple/protocols/oscar/oscar.h Thu Jul 17 16:48:37 2008 +0000 +++ b/libpurple/protocols/oscar/oscar.h Sun Jul 20 05:47:42 2008 +0000 @@ -433,6 +433,7 @@ GSList *rateclasses; /* Contains nodes of struct rateclass. */ GQueue *queued_snacs; /**< Contains QueuedSnacs. */ + GQueue *queued_lowpriority_snacs; /**< Contains QueuedSnacs to send only once queued_snacs is empty */ guint queued_timeout; void *internal; /* internal conn-specific libfaim data */ @@ -625,6 +626,7 @@ void flap_connection_send_version(OscarData *od, FlapConnection *conn); void flap_connection_send_version_with_cookie(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy); void flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data); +void flap_connection_send_snac_with_high_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data, gboolean high_priority); void flap_connection_send_keepalive(OscarData *od, FlapConnection *conn); FlapFrame *flap_frame_new(OscarData *od, guint16 channel, int datalen);