pidgin.mxit: f5e41543: * do not send requests too fast to the ...

pieter.loubser at mxit.com pieter.loubser at mxit.com
Fri Feb 4 04:15:57 EST 2011


----------------------------------------------------------------------
Revision: f5e415439fcd668fa55f202c719f7d3feecd65bb
Parent:   116c3c0389e69edd90534a89c3d070edaa9892e8
Author:   pieter.loubser at mxit.com
Date:     02/04/11 04:13:46
Branch:   im.pidgin.pidgin.mxit
URL: http://d.pidgin.im/viewmtn/revision/info/f5e415439fcd668fa55f202c719f7d3feecd65bb

Changelog: 

 * do not send requests too fast to the mxit server or they will start ignoring you.


Changes against parent 116c3c0389e69edd90534a89c3d070edaa9892e8

  patched  libpurple/protocols/mxit/login.c
  patched  libpurple/protocols/mxit/mxit.c
  patched  libpurple/protocols/mxit/mxit.h
  patched  libpurple/protocols/mxit/profile.c
  patched  libpurple/protocols/mxit/protocol.c
  patched  libpurple/protocols/mxit/protocol.h

-------------- next part --------------
============================================================
--- libpurple/protocols/mxit/login.c	280c74cc5e523a6c0dc438e5ab83e0504cd65288
+++ libpurple/protocols/mxit/login.c	c3b11a7c2a04d44237ec6d2cf3fd2f3b3b95a3ec
@@ -84,7 +84,7 @@ static struct MXitSession* mxit_create_o
 	session->iimages = g_hash_table_new( g_str_hash, g_str_equal );
 	session->rx_state = RX_STATE_RLEN;
 	session->http_interval = MXIT_HTTP_POLL_MIN;
-	session->http_last_poll = time( NULL );
+	session->http_last_poll = mxit_now_milli();
 
 	return session;
 }
@@ -106,7 +106,7 @@ static void mxit_connected( struct MXitS
 	purple_connection_update_progress( session->con, _( "Logging In..." ), 2, 4 );
 
 	/* create a timer to send a ping packet if the connection is idle */
-	session->last_tx = time( NULL );
+	session->last_tx = mxit_now_milli();
 
 	/* encrypt the user password */
 	session->encpwd = mxit_encrypt_password( session );
@@ -143,7 +143,7 @@ static void mxit_connected( struct MXitS
 	/* This timer might already exist if we're registering a new account */
 	if ( session->q_timer == 0 ) {
 		/* start the tx queue manager timer */
-		session->q_timer = purple_timeout_add_seconds( 2, mxit_manage_queue, session );
+		session->q_timer = purple_timeout_add_seconds( 2, mxit_manage_queue_slow, session );
 	}
 }
 
============================================================
--- libpurple/protocols/mxit/mxit.c	7895738dcd9a6824458c9a3e60f9d168a517a01c
+++ libpurple/protocols/mxit/mxit.c	d03869e405a6c42843598342ebd6f4e09da07add
@@ -525,7 +525,7 @@ static void mxit_keepalive( PurpleConnec
 	if ( session->http )
 		return;
 
-	if ( session->last_tx <= time( NULL ) - MXIT_PING_INTERVAL ) {
+	if ( session->last_tx <= ( mxit_now_milli() - ( MXIT_PING_INTERVAL * 1000 ) ) ) {
 		/*
 		 * this connection has been idle for too long, better ping
 		 * the server before it kills our connection.
============================================================
--- libpurple/protocols/mxit/mxit.h	02522588e1f937bee2ea68cfab1eea11968b41da
+++ libpurple/protocols/mxit/mxit.h	c3009a770c3cc34d3db8f3d2951dbe3061198e91
@@ -135,7 +135,7 @@ struct MXitSession {
 	unsigned int		http_seqno;					/* HTTP request sequence number */
 	guint				http_timer_id;				/* timer resource id (pidgin) */
 	int					http_interval;				/* poll inverval */
-	time_t				http_last_poll;				/* the last time a poll has been sent */
+	gint64				http_last_poll;				/* the last time a poll has been sent */
 	guint				http_handler;				/* HTTP connection handler */
 	void*				http_out_req;				/* HTTP outstanding request */
 
@@ -160,7 +160,7 @@ struct MXitSession {
 
 	/* transmit */
 	struct tx_queue		queue;						/* transmit packet queue (FIFO mode) */
-	time_t				last_tx;					/* timestamp of last packet sent */
+	gint64				last_tx;					/* timestamp of last packet sent */
 	int					outack;						/* outstanding ack packet */
 	guint				q_timer;					/* timer handler for managing queue */
 
@@ -170,7 +170,7 @@ struct MXitSession {
 	unsigned int		rx_i;						/* receive buffer current index */
 	int					rx_res;						/* amount of bytes still outstanding for the current packet */
 	char				rx_state;					/* current receiver state */
-	time_t				last_rx;					/* timestamp of last packet received */
+	gint64				last_rx;					/* timestamp of last packet received */
 	GList*				active_chats;				/* list of all our contacts we received messages from (active chats) */
 
 	/* groupchat */
============================================================
--- libpurple/protocols/mxit/profile.c	2b7bd748818fa1c6fbf135c8119263441427b57b
+++ libpurple/protocols/mxit/profile.c	fc9bef9d9f59005ee7fae5b668415ed6c96a8f46
@@ -108,10 +108,10 @@ static const char* datetime( gint64 msec
  */
 static const char* datetime( gint64 msecs )
 {
-    time_t secs = msecs / 1000;
+	time_t secs = msecs / 1000;
 
-    struct tm t;
-    localtime_r( &secs, &t );
+	struct tm t;
+	localtime_r( &secs, &t );
 
 	return purple_utf8_strftime( "%d-%m-%Y %H:%M:%S", &t );
 }
@@ -140,13 +140,10 @@ void mxit_show_profile( struct MXitSessi
 	purple_notify_user_info_add_pair( info, _( "Display Name" ), profile->nickname );
 	purple_notify_user_info_add_pair( info, _( "Birthday" ), profile->birthday );
 	purple_notify_user_info_add_pair( info, _( "Gender" ), profile->male ? _( "Male" ) : _( "Female" ) );
-//	purple_notify_user_info_add_pair( info, _( "Hidden Number" ), profile->hidden ? _( "Yes" ) : _( "No" ) );
 
 	/* optional information */
-//	purple_notify_user_info_add_pair( info, _( "Title" ), profile->title );
 	purple_notify_user_info_add_pair( info, _( "First Name" ), profile->firstname );
 	purple_notify_user_info_add_pair( info, _( "Last Name" ), profile->lastname );
-//	purple_notify_user_info_add_pair( info, _( "Email" ), profile->email );
 	purple_notify_user_info_add_pair( info, _( "Country" ), profile->regcountry );
 
 	purple_notify_user_info_add_section_break( info );
============================================================
--- libpurple/protocols/mxit/protocol.c	b7f1d65db1173aefe60880cdfe7d437e248a1e2e
+++ libpurple/protocols/mxit/protocol.c	3043aec5ae922abfa6cf414af63fcc12126875ef
@@ -46,7 +46,19 @@
 #define		CP_REC_TERM			( ( session->http ) ? CP_HTTP_REC_TERM : CP_SOCK_REC_TERM )
 
 
+/*------------------------------------------------------------------------
+ * return the current timestamp in milliseconds
+ */
+gint64 mxit_now_milli( void )
+{
+	GTimeVal	now;
 
+	g_get_current_time( &now );
+
+	return ( ( now.tv_sec * 1000 ) + ( now.tv_usec / 1000 ) );
+}
+
+
 /*------------------------------------------------------------------------
  * Display a notification popup message to the user.
  *
@@ -412,7 +424,7 @@ static void mxit_send_packet( struct MXi
 	}
 
 	/* update the timestamp of the last-transmitted packet */
-	session->last_tx = time( NULL );
+	session->last_tx = mxit_now_milli();
 
 	/*
 	 * we need to remember that we are still waiting for the ACK from
@@ -475,17 +487,13 @@ static void mxit_queue_packet( struct MX
 	packet->datalen = datalen;
 
 
-	/*
-	 * shortcut: first check if there are any commands still outstanding.
-	 * if not, then we might as well just write this packet directly and
-	 * skip the whole queueing thing
-	 */
-	if ( session->outack == 0 ) {
-		/* no outstanding ACKs, so we might as well write it directly */
+	/* shortcut */
+	if ( ( session->queue.count == 0 ) && ( session->outack == 0 ) ) {
+		/* the queue is empty and there are no outstanding acks so we can write it directly */
 		mxit_send_packet( session, packet );
 	}
 	else {
-		/* ACK still outstanding, so we need to queue this request until we have the ACK */
+		/* we need to queue this packet */
 
 		if ( ( packet->cmd == CP_CMD_PING ) || ( packet->cmd == CP_CMD_POLL ) ) {
 			/* we do NOT queue HTTP poll nor socket ping packets */
@@ -504,42 +512,89 @@ static void mxit_queue_packet( struct MX
 
 
 /*------------------------------------------------------------------------
- * Callback to manage the packet send queue (send next packet, timeout's, etc).
+ * Manage the packet send queue (send next packet, timeout's, etc).
  *
  *  @param session		The MXit session object
  */
-gboolean mxit_manage_queue( gpointer user_data )
+static void mxit_manage_queue( struct MXitSession* session )
 {
-	struct MXitSession* session		= (struct MXitSession*) user_data;
 	struct tx_packet*	packet		= NULL;
+	gint64				now			= mxit_now_milli();
 
 	if ( !( session->flags & MXIT_FLAG_CONNECTED ) ) {
 		/* we are not connected, so ignore the queue */
-		return TRUE;
+		return;
 	}
 	else if ( session->outack > 0 ) {
 		/* we are still waiting for an outstanding ACK from the MXit server */
-		if ( session->last_tx <= time( NULL ) - MXIT_ACK_TIMEOUT ) {
+		if ( session->last_tx <= mxit_now_milli() - ( MXIT_ACK_TIMEOUT * 1000 ) ) {
 			/* ack timeout! so we close the connection here */
 			purple_debug_info( MXIT_PLUGIN_ID, "mxit_manage_queue: Timeout awaiting ACK for command '%i'\n", session->outack );
 			purple_connection_error( session->con, _( "Timeout while waiting for a response from the MXit server." ) );
 		}
-		return TRUE;
+		return;
 	}
 
-	packet = pop_tx_packet( session );
-	if ( packet != NULL ) {
-		/* there was a packet waiting to be sent to the server, now is the time to do something about it */
+	/* 
+	 * the mxit server has flood detection and it prevents you from sending messages to fast.
+	 * this is a self defense mechanism, a very annoying feature. so the client must ensure that
+	 * it does not send messages too fast otherwise mxit will ignore the user for 30 seconds.
+	 * this is what we are trying to avoid here..
+	 */
+	if ( session->last_tx > ( now - MXIT_TX_DELAY ) ) {
+		/* we need to wait a little before sending the next packet, so schedule a wakeup call */
+		gint64 tdiff = now - ( session->last_tx );
+		guint delay = ( MXIT_TX_DELAY - tdiff ) + 9;
+		if ( delay <= 0 )
+			delay = MXIT_TX_DELAY;
+		purple_timeout_add( delay, mxit_manage_queue_fast, session );
+	}
+	else {
+		/* get the next packet from the queue to send */
+		packet = pop_tx_packet( session );
+		if ( packet != NULL ) {
+			/* there was a packet waiting to be sent to the server, now is the time to do something about it */
 
-		/* send the packet to MXit server */
-		mxit_send_packet( session, packet );
+			/* send the packet to MXit server */
+			mxit_send_packet( session, packet );
+		}
 	}
+}
 
+
+/*------------------------------------------------------------------------
+ * Slow callback to manage the packet send queue.
+ *
+ *  @param session		The MXit session object
+ */
+gboolean mxit_manage_queue_slow( gpointer user_data )
+{
+	struct MXitSession* session		= (struct MXitSession*) user_data;
+
+	mxit_manage_queue( session );
+
+	/* continue running */
 	return TRUE;
 }
 
 
 /*------------------------------------------------------------------------
+ * Fast callback to manage the packet send queue.
+ *
+ *  @param session		The MXit session object
+ */
+gboolean mxit_manage_queue_fast( gpointer user_data )
+{
+	struct MXitSession* session		= (struct MXitSession*) user_data;
+
+	mxit_manage_queue( session );
+
+	/* stop running */
+	return FALSE;
+}
+
+
+/*------------------------------------------------------------------------
  * Callback to manage HTTP server polling (HTTP connections ONLY)
  *
  *  @param session		The MXit session object
@@ -548,9 +603,9 @@ gboolean mxit_manage_polling( gpointer u
 {
 	struct MXitSession* session		= (struct MXitSession*) user_data;
 	gboolean			poll		= FALSE;
-	time_t				now			= time( NULL );
+	gint64				now			= mxit_now_milli();
 	int					polldiff;
-	int					rxdiff;
+	gint64				rxdiff;
 
 	if ( !( session->flags & MXIT_FLAG_LOGGEDIN ) ) {
 		/* we only poll if we are actually logged in */
@@ -580,7 +635,7 @@ gboolean mxit_manage_polling( gpointer u
 
 	if ( poll ) {
 		/* send poll request */
-		session->http_last_poll = time( NULL );
+		session->http_last_poll = mxit_now_milli();
 		mxit_send_poll( session );
 	}
 
@@ -2001,7 +2056,7 @@ static int process_success_response( str
 {
 	/* ignore ping/poll packets */
 	if ( ( packet->cmd != CP_CMD_PING ) && ( packet->cmd != CP_CMD_POLL ) )
-		session->last_rx = time( NULL );
+		session->last_rx = mxit_now_milli();
 
 	/*
 	 * when we pass the packet records to the next level for parsing
============================================================
--- libpurple/protocols/mxit/protocol.h	957abd9e0c5b3b161acbab0544cce1ae10986b86
+++ libpurple/protocols/mxit/protocol.h	7d9ad1e196c3935b9e52be2dc31c626b8b5d6f8a
@@ -84,6 +84,7 @@
 
 #define		MXIT_PING_INTERVAL		( 5 * 60 )				/* ping the server after X seconds of being idle (5 minutes) */
 #define		MXIT_ACK_TIMEOUT		( 30 )					/* timeout after waiting X seconds for an ack from the server (30 seconds) */
+#define		MXIT_TX_DELAY			( 100 )					/* delay between sending consecutive packets (100 ms) */
 
 /* MXit client version */
 #define		MXIT_CP_DISTCODE		'P'						/* client distribution code (magic, do not touch!) */
@@ -107,7 +108,7 @@
 #define		MXIT_CP_CAP				"utf8=true;cid="MXIT_CLIENT_ID
 
 /* Client settings */
-#define		MAX_QUEUE_SIZE			( 1 << 4 )				/* tx queue size (16 packets) */
+#define		MAX_QUEUE_SIZE			( 1 << 5 )				/* tx queue size (32 packets) */
 #define		MXIT_POPUP_WIN_NAME		"MXit Notification"		/* popup window name */
 #define		MXIT_MAX_ATTRIBS		10						/* maximum profile attributes supported */
 #define		MXIT_DEFAULT_LOCALE		"en"					/* default locale setting */
@@ -284,7 +285,8 @@ void mxit_cb_rx( gpointer data, gint sou
 gboolean find_active_chat( const GList* chats, const char* who );
 
 void mxit_cb_rx( gpointer data, gint source, PurpleInputCondition cond );
-gboolean mxit_manage_queue( gpointer user_data );
+gboolean mxit_manage_queue_slow( gpointer user_data );
+gboolean mxit_manage_queue_fast( gpointer user_data );
 gboolean mxit_manage_polling( gpointer user_data );
 
 void mxit_send_register( struct MXitSession* session );
@@ -324,6 +326,7 @@ void mxit_close_connection( struct MXitS
 int mxit_parse_packet( struct MXitSession* session );
 void dump_bytes( struct MXitSession* session, const char* buf, int len );
 void mxit_close_connection( struct MXitSession* session );
+gint64 mxit_now_milli( void );
 
 
 #endif		/* _MXIT_PROTO_H_ */


More information about the Commits mailing list