changeset 23613:0a674616953c

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.
author Evan Schoenberg <evan.s@dreskin.net>
date Sun, 20 Jul 2008 05:47:42 +0000
parents de24d89313b0
children e53a21941d43
files libpurple/protocols/oscar/family_icq.c libpurple/protocols/oscar/family_locate.c libpurple/protocols/oscar/flap_connection.c libpurple/protocols/oscar/oscar.h
diffstat 4 files changed, 80 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- 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);
 
--- 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);
 
--- 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);
 
--- 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);