Mercurial > pidgin
view libpurple/protocols/qq/qq_trans.c @ 29793:399756f65c88
propagate from branch 'im.pidgin.pidgin' (head 46ae10a850bb3c3ce9a3bb47a7de9edd4becdb93)
to branch 'im.pidgin.cpw.malu.ft_thumbnails' (head e1429716d38c7e085c82406c5ed9d8feeeb3c7bb)
author | Marcus Lundblad <ml@update.uu.se> |
---|---|
date | Tue, 28 Jul 2009 20:51:56 +0000 |
parents | 7da3cf2530b7 |
children | 7c871249318b |
line wrap: on
line source
/** * @file qq_trans.c * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #include "internal.h" #include "connection.h" #include "debug.h" #include "notify.h" #include "prefs.h" #include "request.h" #include "qq_define.h" #include "qq_network.h" #include "qq_process.h" #include "qq_trans.h" enum { QQ_TRANS_IS_SERVER = 0x01, /* Is server command or client command */ QQ_TRANS_IS_IMPORT = 0x02, /* Only notice if not get reply; or resend, disconn if reties get 0*/ QQ_TRANS_REMAINED = 0x04, /* server command before login*/ QQ_TRANS_IS_REPLY = 0x08 /* server command before login*/ }; struct _qq_transaction { guint8 flag; guint16 seq; guint16 cmd; guint8 room_cmd; guint32 room_id; guint8 *data; gint data_len; gint fd; gint send_retries; gint rcved_times; gint scan_times; guint32 update_class; guint32 ship32; }; gboolean qq_trans_is_server(qq_transaction *trans) { g_return_val_if_fail(trans != NULL, FALSE); if (trans->flag & QQ_TRANS_IS_SERVER) return TRUE; else return FALSE; } gboolean qq_trans_is_dup(qq_transaction *trans) { g_return_val_if_fail(trans != NULL, TRUE); if (trans->rcved_times > 1) return TRUE; else return FALSE; } guint8 qq_trans_get_room_cmd(qq_transaction *trans) { g_return_val_if_fail(trans != NULL, 0); return trans->room_cmd; } guint32 qq_trans_get_room_id(qq_transaction *trans) { g_return_val_if_fail(trans != NULL, 0); return trans->room_id; } guint32 qq_trans_get_class(qq_transaction *trans) { g_return_val_if_fail(trans != NULL, QQ_CMD_CLASS_NONE); return trans->update_class; } guint32 qq_trans_get_ship(qq_transaction *trans) { g_return_val_if_fail(trans != NULL, 0); return trans->ship32; } static qq_transaction *trans_create(PurpleConnection *gc, gint fd, guint16 cmd, guint16 seq, guint8 *data, gint data_len, guint32 update_class, guint32 ship32) { qq_data *qd; qq_transaction *trans; g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, NULL); qd = (qq_data *) gc->proto_data; trans = g_new0(qq_transaction, 1); memset(trans, 0, sizeof(qq_transaction)); trans->fd = fd; trans->cmd = cmd; trans->seq = seq; trans->data = NULL; trans->data_len = 0; if (data != NULL && data_len > 0) { /* don't use g_strdup, may have 0x00 */ trans->data = g_memdup(data, data_len); trans->data_len = data_len; } trans->update_class = update_class; trans->ship32 = ship32; return trans; } /* Remove a packet with seq from send trans */ static void trans_remove(PurpleConnection *gc, qq_transaction *trans) { qq_data *qd = (qq_data *)gc->proto_data; g_return_if_fail(gc != NULL && gc->proto_data != NULL); qd = (qq_data *) gc->proto_data; g_return_if_fail(trans != NULL); #if 0 purple_debug_info("QQ_TRANS", "Remove [%s%05d] retry %d rcved %d scan %d %s\n", (trans->flag & QQ_TRANS_IS_SERVER) ? "SRV-" : "", trans->seq, trans->send_retries, trans->rcved_times, trans->scan_times, qq_get_cmd_desc(trans->cmd)); #endif if (trans->data) g_free(trans->data); qd->transactions = g_list_remove(qd->transactions, trans); g_free(trans); } static qq_transaction *trans_find(PurpleConnection *gc, guint16 cmd, guint16 seq) { qq_data *qd; GList *list; qq_transaction *trans; g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, NULL); qd = (qq_data *) gc->proto_data; list = qd->transactions; while (list != NULL) { trans = (qq_transaction *) list->data; if(trans->cmd == cmd && trans->seq == seq) { return trans; } list = list->next; } return NULL; } void qq_trans_add_client_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len, guint32 update_class, guint32 ship32) { qq_data *qd = (qq_data *)gc->proto_data; qq_transaction *trans = trans_create(gc, qd->fd, cmd, seq, data, data_len, update_class, ship32); if (cmd == QQ_CMD_TOKEN || cmd == QQ_CMD_LOGIN || cmd == QQ_CMD_KEEP_ALIVE) { trans->flag |= QQ_TRANS_IS_IMPORT; } trans->send_retries = qd->resend_times; #if 0 purple_debug_info("QQ_TRANS", "Add client cmd, seq %d, data %p, len %d\n", trans->seq, trans->data, trans->data_len); #endif qd->transactions = g_list_append(qd->transactions, trans); } qq_transaction *qq_trans_find_rcved(PurpleConnection *gc, guint16 cmd, guint16 seq) { qq_transaction *trans; trans = trans_find(gc, cmd, seq); if (trans == NULL) { return NULL; } if (trans->rcved_times == 0) { trans->scan_times = 0; } trans->rcved_times++; /* server may not get our confirm reply before, send reply again*/ if (qq_trans_is_server(trans) && (trans->flag & QQ_TRANS_IS_REPLY)) { if (trans->data != NULL && trans->data_len > 0) { qq_send_cmd_encrypted(gc, trans->cmd, trans->seq, trans->data, trans->data_len, FALSE); } } return trans; } void qq_trans_add_room_cmd(PurpleConnection *gc, guint16 seq, guint8 room_cmd, guint32 room_id, guint8 *data, gint data_len, guint32 update_class, guint32 ship32) { qq_data *qd = (qq_data *)gc->proto_data; qq_transaction *trans = trans_create(gc, qd->fd, QQ_CMD_ROOM, seq, data, data_len, update_class, ship32); trans->room_cmd = room_cmd; trans->room_id = room_id; trans->send_retries = qd->resend_times; #if 0 purple_debug_info("QQ_TRANS", "Add room cmd, seq %d, data %p, len %d\n", trans->seq, trans->data, trans->data_len); #endif qd->transactions = g_list_append(qd->transactions, trans); } void qq_trans_add_server_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len) { qq_data *qd = (qq_data *)gc->proto_data; qq_transaction *trans = trans_create(gc, qd->fd, cmd, seq, rcved, rcved_len, QQ_CMD_CLASS_NONE, 0); trans->flag = QQ_TRANS_IS_SERVER; trans->send_retries = 0; trans->rcved_times = 1; #if 0 purple_debug_info("QQ_TRANS", "Add server cmd, seq %d, data %p, len %d\n", trans->seq, trans->data, trans->data_len); #endif qd->transactions = g_list_append(qd->transactions, trans); } void qq_trans_add_server_reply(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *reply, gint reply_len) { qq_transaction *trans; g_return_if_fail(reply != NULL && reply_len > 0); trans = trans_find(gc, cmd, seq); if (trans == NULL) { return; } g_return_if_fail(trans->flag & QQ_TRANS_IS_SERVER); trans->flag |= QQ_TRANS_IS_REPLY; if (trans->data) g_free(trans->data); trans->data = g_memdup(reply, reply_len); trans->data_len = reply_len; } void qq_trans_add_remain(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len) { qq_data *qd = (qq_data *)gc->proto_data; qq_transaction *trans = trans_create(gc, qd->fd, cmd, seq, data, data_len, QQ_CMD_CLASS_NONE, 0); trans->flag = QQ_TRANS_IS_SERVER; trans->flag |= QQ_TRANS_REMAINED; trans->send_retries = 0; trans->rcved_times = 1; #if 1 purple_debug_info("QQ_TRANS", "Add server cmd and remained, seq %d, data %p, len %d\n", trans->seq, trans->data, trans->data_len); #endif qd->transactions = g_list_append(qd->transactions, trans); } void qq_trans_process_remained(PurpleConnection *gc) { qq_data *qd = (qq_data *)gc->proto_data; GList *curr; GList *next; qq_transaction *trans; g_return_if_fail(qd != NULL); next = qd->transactions; while( (curr = next) ) { next = curr->next; trans = (qq_transaction *) (curr->data); #if 0 purple_debug_info("QQ_TRANS", "Scan [%d]\n", trans->seq); #endif if ( !(trans->flag & QQ_TRANS_IS_SERVER) ) { continue; } if ( !(trans->flag & QQ_TRANS_REMAINED) ) { continue; } /* set QQ_TRANS_REMAINED off */ trans->flag &= ~QQ_TRANS_REMAINED; #if 1 purple_debug_info("QQ_TRANS", "Process server cmd remained, seq %d, data %p, len %d, send_retries %d\n", trans->seq, trans->data, trans->data_len, trans->send_retries); #endif qq_proc_server_cmd(gc, trans->cmd, trans->seq, trans->data, trans->data_len); } /* purple_debug_info("QQ_TRANS", "Scan finished\n"); */ return; } gboolean qq_trans_scan(PurpleConnection *gc) { qq_data *qd = (qq_data *)gc->proto_data; GList *curr; GList *next; qq_transaction *trans; g_return_val_if_fail(qd != NULL, FALSE); next = qd->transactions; while( (curr = next) ) { next = curr->next; trans = (qq_transaction *) (curr->data); /* purple_debug_info("QQ_TRANS", "Scan [%d]\n", trans->seq); */ if (trans->flag & QQ_TRANS_REMAINED) { /* keep server cmd before login*/ continue; } trans->scan_times++; if (trans->scan_times <= 1) { /* skip in 10 seconds */ continue; } if (trans->rcved_times > 0) { /* Has been received */ trans_remove(gc, trans); continue; } if (trans->flag & QQ_TRANS_IS_SERVER) { continue; } /* Never get reply */ trans->send_retries--; if (trans->send_retries <= 0) { purple_debug_warning("QQ_TRANS", "[%d] %s is lost.\n", trans->seq, qq_get_cmd_desc(trans->cmd)); if (trans->flag & QQ_TRANS_IS_IMPORT) { return TRUE; } qd->net_stat.lost++; purple_debug_error("QQ_TRANS", "Lost [%d] %s, data %p, len %d, retries %d\n", trans->seq, qq_get_cmd_desc(trans->cmd), trans->data, trans->data_len, trans->send_retries); trans_remove(gc, trans); continue; } qd->net_stat.resend++; purple_debug_warning("QQ_TRANS", "Resend [%d] %s data %p, len %d, send_retries %d\n", trans->seq, qq_get_cmd_desc(trans->cmd), trans->data, trans->data_len, trans->send_retries); qq_send_cmd_encrypted(gc, trans->cmd, trans->seq, trans->data, trans->data_len, FALSE); } /* purple_debug_info("QQ_TRANS", "Scan finished\n"); */ return FALSE; } /* clean up send trans and free all contents */ void qq_trans_remove_all(PurpleConnection *gc) { qq_data *qd = (qq_data *)gc->proto_data; qq_transaction *trans; gint count = 0; while(qd->transactions != NULL) { trans = (qq_transaction *) (qd->transactions->data); qd->transactions = g_list_remove(qd->transactions, trans); if (trans->data) g_free(trans->data); g_free(trans); count++; } if (count > 0) { purple_debug_info("QQ_TRANS", "Free all %d packets\n", count); } }