# HG changeset patch # User pieter.loubser@mxit.com # Date 1296810826 0 # Node ID 02b510d2d01423d55f8dce4820ddeef04d19e9e2 # Parent f995a9df914b64ab37f4e6bd9ac36469ea152cbf * do not send requests too fast to the mxit server or they will start ignoring you. diff -r f995a9df914b -r 02b510d2d014 libpurple/protocols/mxit/login.c --- 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 ); } } diff -r f995a9df914b -r 02b510d2d014 libpurple/protocols/mxit/mxit.c --- 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. diff -r f995a9df914b -r 02b510d2d014 libpurple/protocols/mxit/mxit.h --- 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 */ diff -r f995a9df914b -r 02b510d2d014 libpurple/protocols/mxit/profile.c --- 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 ); diff -r f995a9df914b -r 02b510d2d014 libpurple/protocols/mxit/protocol.c --- 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 diff -r f995a9df914b -r 02b510d2d014 libpurple/protocols/mxit/protocol.h --- 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_ */