changeset 31747:02b510d2d014

* do not send requests too fast to the mxit server or they will start ignoring you.
author pieter.loubser@mxit.com
date Fri, 04 Feb 2011 09:13:46 +0000
parents f995a9df914b
children 8cddae054791
files libpurple/protocols/mxit/login.c libpurple/protocols/mxit/mxit.c libpurple/protocols/mxit/mxit.h libpurple/protocols/mxit/profile.c libpurple/protocols/mxit/protocol.c libpurple/protocols/mxit/protocol.h
diffstat 6 files changed, 98 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/mxit/login.c	Wed Jan 26 09:36:58 2011 +0000
+++ b/libpurple/protocols/mxit/login.c	Fri Feb 04 09:13:46 2011 +0000
@@ -84,7 +84,7 @@
 	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 @@
 	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 @@
 	/* 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 );
 	}
 }
 
--- a/libpurple/protocols/mxit/mxit.c	Wed Jan 26 09:36:58 2011 +0000
+++ b/libpurple/protocols/mxit/mxit.c	Fri Feb 04 09:13:46 2011 +0000
@@ -525,7 +525,7 @@
 	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.
--- a/libpurple/protocols/mxit/mxit.h	Wed Jan 26 09:36:58 2011 +0000
+++ b/libpurple/protocols/mxit/mxit.h	Fri Feb 04 09:13:46 2011 +0000
@@ -135,7 +135,7 @@
 	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 @@
 
 	/* 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 @@
 	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 */
--- a/libpurple/protocols/mxit/profile.c	Wed Jan 26 09:36:58 2011 +0000
+++ b/libpurple/protocols/mxit/profile.c	Fri Feb 04 09:13:46 2011 +0000
@@ -108,10 +108,10 @@
  */
 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 @@
 	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 );
--- a/libpurple/protocols/mxit/protocol.c	Wed Jan 26 09:36:58 2011 +0000
+++ b/libpurple/protocols/mxit/protocol.c	Fri Feb 04 09:13:46 2011 +0000
@@ -46,6 +46,18 @@
 #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 @@
 	}
 
 	/* 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 @@
 	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 @@
 
 
 /*------------------------------------------------------------------------
- * 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;
+	}
+
+	/* 
+	 * 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 );
+		}
 	}
-
-	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 );
-	}
-
+}
+
+
+/*------------------------------------------------------------------------
+ * 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 @@
 {
 	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 @@
 
 	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 @@
 {
 	/* 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
--- a/libpurple/protocols/mxit/protocol.h	Wed Jan 26 09:36:58 2011 +0000
+++ b/libpurple/protocols/mxit/protocol.h	Fri Feb 04 09:13:46 2011 +0000
@@ -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 @@
 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 @@
 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_ */