首页 | 数据结构 | 文件列表 | 数据字段 | 全局定义

recv_core.c

浏览该文件的文档。
00001 
00023 // START OF FILE
00024 /*****************************************************************************/
00025 #include "debug.h"              // gaim_debug
00026 #include "internal.h"           // _("get_text")
00027 
00028 #include "utils.h"              // hex_dump_to_str
00029 #include "packet_parse.h"       // MAX_PACKET_SIZE
00030 #include "buddy_info.h"         // qq_process_modify_info_reply
00031 #include "buddy_list.h"         // qq_process_get_buddies_list_reply
00032 #include "buddy_opt.h"          // qq_process_add_buddy_reply
00033 #include "buddy_status.h"       // qq_process_friend_change_status
00034 #include "char_conv.h"          // qq_to_utf8
00035 #include "crypt.h"              // qq_crypt
00036 #include "group_network.h"      // qq_process_group_cmd_reply
00037 #include "header_info.h"        // cmd alias
00038 #include "keep_alive.h"         // qq_process_keep_alive_reply
00039 #include "im.h"                 // qq_process_send_im_reply
00040 #include "login_logout.h"       // qq_process_login_reply
00041 #include "qq_proxy.h"           // qq_proxy_read
00042 #include "recv_core.h"
00043 #include "sendqueue.h"          // qq_sendqueue_remove
00044 #include "sys_msg.h"            // qq_process_msg_sys
00045 
00046 typedef struct _packet_before_login packet_before_login;
00047 typedef struct _qq_recv_msg_header qq_recv_msg_header;
00048 
00049 struct _packet_before_login {
00050         guint8 *buf;
00051         gint len;
00052 };
00053 
00054 struct _qq_recv_msg_header {
00055         guint8 header_tag;
00056         guint16 source_tag;
00057         guint16 cmd;
00058         guint16 seq;            // can be ack_seq or send_seq, depends on cmd
00059 };
00060 
00061 /*****************************************************************************/
00062 // check whether one sequence number is duplicated or not
00063 // return TRUE if it is duplicated, otherwise FALSE
00064 gboolean _qq_check_packet_set_window(guint16 seq, GaimConnection * gc)
00065 {
00066         qq_data *qd;
00067         gchar *byte, mask;
00068 
00069         g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, FALSE);
00070         qd = (qq_data *) gc->proto_data;
00071         byte = &(qd->window[seq / 8]);
00072         mask = (1 << (seq % 8));
00073 
00074         if ((*byte) & mask)
00075                 return TRUE;    // check mask
00076         (*byte) |= mask;
00077         return FALSE;           // set mask
00078 }                               // _qq_check_packet_set_window
00079 
00080 /*****************************************************************************/
00081 // default process, decrypt and dump
00082 void _qq_process_packet_default(guint8 * buf, gint buf_len, guint16 cmd, guint16 seq, GaimConnection * gc) {
00083 
00084         qq_data *qd;
00085         guint8 *data;
00086         gchar *msg_utf8;
00087         gint len;
00088 
00089         g_return_if_fail(gc != NULL && gc->proto_data != NULL);
00090         g_return_if_fail(buf != NULL && buf_len != 0);
00091 
00092         qd = (qq_data *) gc->proto_data;
00093         len = buf_len;
00094         data = g_newa(guint8, len);
00095         msg_utf8 = NULL;
00096 
00097         if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) {
00098                 gaim_debug(GAIM_DEBUG_WARNING, "QQ",
00099                            ">>> [%d] %s, %d bytes -> [default] decrypt and dump\n%s",
00100                            seq, qq_get_cmd_desc(cmd), buf_len, hex_dump_to_str(data, len));
00101                 try_dump_as_gbk(data, len);
00102         } else
00103                 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Fail decrypt packet with default process\n");
00104 
00105 }                               // _qq_process_packet_default
00106 
00107 /*****************************************************************************/
00108 // process the incoming packet from qq_pending
00109 void _qq_packet_process(guint8 * buf, gint buf_len, GaimConnection * gc)
00110 {
00111         qq_data *qd;
00112         gint len, bytes_expected, bytes_read;
00113         guint16 buf_len_read;   // two bytes in the begining of TCP packet
00114         guint8 *cursor;
00115         qq_recv_msg_header header;
00116         packet_before_login *b4_packet;
00117 
00118         g_return_if_fail(gc != NULL && gc->proto_data != NULL);
00119         g_return_if_fail(buf != NULL && buf_len > 0);
00120 
00121         qd = (qq_data *) gc->proto_data;
00122         bytes_expected = qd->use_tcp ? QQ_TCP_HEADER_LENGTH : QQ_UDP_HEADER_LENGTH;
00123 
00124         if (buf_len < bytes_expected) {
00125                 gaim_debug(GAIM_DEBUG_ERROR,
00126                            "QQ", "Received packet is too short, dump and drop\n%s", hex_dump_to_str(buf, buf_len));
00127                 return;
00128         }
00129         // initialize
00130         cursor = buf;
00131         bytes_read = 0;
00132 
00133         // QQ TCP packet returns first 2 bytes the length of this packet
00134         if (qd->use_tcp) {
00135                 bytes_read += read_packet_w(buf, &cursor, buf_len, &buf_len_read);
00136                 if (buf_len_read != buf_len) {  // wrong
00137                         gaim_debug
00138                             (GAIM_DEBUG_ERROR,
00139                              "QQ",
00140                              "TCP read %d bytes, header says %d bytes, use header anyway\n", buf_len, buf_len_read);
00141                         buf_len = buf_len_read; // we believe header is more accurate
00142                 }               // if buf_len_read
00143         }                       // if use_tcp
00144 
00145         // now goes the normal QQ packet as UDP packet
00146         bytes_read += read_packet_b(buf, &cursor, buf_len, &header.header_tag);
00147         bytes_read += read_packet_w(buf, &cursor, buf_len, &header.source_tag);
00148         bytes_read += read_packet_w(buf, &cursor, buf_len, &header.cmd);
00149         bytes_read += read_packet_w(buf, &cursor, buf_len, &header.seq);
00150 
00151         if (bytes_read != bytes_expected) {     // read error
00152                 gaim_debug(GAIM_DEBUG_ERROR, "QQ",
00153                            "Fail reading packet header, expect %d bytes, read %d bytes\n", bytes_expected, bytes_read);
00154                 return;
00155         }                       // if bytes_read
00156 
00157         if ((buf[buf_len - 1] != QQ_PACKET_TAIL) || (header.header_tag != QQ_PACKET_TAG)) {
00158                 gaim_debug(GAIM_DEBUG_ERROR,
00159                            "QQ", "Unknown QQ proctocol, dump and drop\n%s", hex_dump_to_str(buf, buf_len));
00160                 return;
00161         }                       // if header_tag
00162 
00163         if (QQ_DEBUG)
00164                 gaim_debug(GAIM_DEBUG_INFO, "QQ",
00165                            "==> [%05d] %s, from (%s)\n",
00166                            header.seq, qq_get_cmd_desc(header.cmd), qq_get_source_str(header.source_tag));
00167         //add "&& header.cmd != QQ_CMD_GET_LOGIN_TOKEN" by Yuan Qingyun for QQ 2006 with SP1
00168         if (header.cmd != QQ_CMD_LOGIN && header.cmd != QQ_CMD_GET_LOGIN_TOKEN) {
00169                 if (!qd->logged_in) {   // packets before login
00170                         b4_packet = g_new0(packet_before_login, 1);
00171                         // must duplicate, buffer will be freed after exiting this function
00172                         b4_packet->buf = g_memdup(buf, buf_len);
00173                         b4_packet->len = buf_len;
00174                         if (qd->before_login_packets == NULL)
00175                                 qd->before_login_packets = g_queue_new();
00176                         g_queue_push_head(qd->before_login_packets, b4_packet);
00177                         return; // do not process it now
00178                 } else if (!g_queue_is_empty(qd->before_login_packets)) {
00179                         // logged_in, but we have packets before login
00180                         b4_packet = (packet_before_login *)
00181                             g_queue_pop_head(qd->before_login_packets);
00182                         _qq_packet_process(b4_packet->buf, b4_packet->len, gc);
00183                         // in fact this is a recursive call, 
00184                         // all packets before login will be processed before goes on
00185                         g_free(b4_packet->buf); // the buf is duplicated, need to be freed
00186                         g_free(b4_packet);
00187                 }               // if logged_in
00188         }                       //if header.cmd != QQ_CMD_LOGIN
00189 
00190         // this is the length of all the encrypted data (also remove tail tag
00191         len = buf_len - (bytes_read) - 1;
00192 
00193         // whether it is an ack
00194         switch (header.cmd) {
00195         case QQ_CMD_RECV_IM:
00196         case QQ_CMD_RECV_MSG_SYS:
00197         case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS:
00198                 // server intiated packet, we need to send ack and check duplicaion
00199                 // this must be put after processing b4_packet
00200                 // as these packets will be passed in twice
00201                 if (_qq_check_packet_set_window(header.seq, gc)) {
00202                         gaim_debug(GAIM_DEBUG_WARNING,
00203                                    "QQ", "dup [%05d] %s, discard...\n", header.seq, qq_get_cmd_desc(header.cmd));
00204                         return;
00205                 }
00206                 break;
00207         default:{               // ack packet, we need to update sendqueue
00208                         // we do not check duplication for server ack
00209                         qq_sendqueue_remove(qd, header.seq);
00210                         if (QQ_DEBUG)
00211                                 gaim_debug(GAIM_DEBUG_INFO, "QQ",
00212                                            "ack [%05d] %s, remove from sendqueue\n",
00213                                            header.seq, qq_get_cmd_desc(header.cmd));
00214                 }               // default
00215         }                       // switch header.cmd
00216 
00217         // now process the packet
00218         switch (header.cmd) {
00219         case QQ_CMD_KEEP_ALIVE:
00220                 qq_process_keep_alive_reply(cursor, len, gc);
00221                 break;
00222         case QQ_CMD_UPDATE_INFO:
00223                 qq_process_modify_info_reply(cursor, len, gc);
00224                 break;
00225         case QQ_CMD_ADD_FRIEND_WO_AUTH:
00226                 qq_process_add_buddy_reply(cursor, len, header.seq, gc);
00227                 break;
00228         case QQ_CMD_DEL_FRIEND:
00229                 qq_process_remove_buddy_reply(cursor, len, gc);
00230                 break;
00231         case QQ_CMD_REMOVE_SELF:
00232                 qq_process_remove_self_reply(cursor, len, gc);
00233                 break;
00234         case QQ_CMD_BUDDY_AUTH:
00235                 qq_process_add_buddy_auth_reply(cursor, len, gc);
00236                 break;
00237         case QQ_CMD_GET_USER_INFO:
00238                 qq_process_get_info_reply(cursor, len, gc);
00239                 break;
00240         case QQ_CMD_CHANGE_ONLINE_STATUS:
00241                 qq_process_change_status_reply(cursor, len, gc);
00242                 break;
00243         case QQ_CMD_SEND_IM:
00244                 qq_process_send_im_reply(cursor, len, gc);
00245                 break;
00246         case QQ_CMD_RECV_IM:
00247                 qq_process_recv_im(cursor, len, header.seq, gc);
00248                 break;
00249         case QQ_CMD_LOGIN:
00250                 qq_process_login_reply(cursor, len, gc);
00251                 break;
00252         case QQ_CMD_GET_FRIENDS_LIST:
00253                 qq_process_get_buddies_list_reply(cursor, len, gc);
00254                 break;
00255         case QQ_CMD_GET_FRIENDS_ONLINE:
00256                 qq_process_get_buddies_online_reply(cursor, len, gc);
00257                 break;
00258         case QQ_CMD_GROUP_CMD:
00259                 qq_process_group_cmd_reply(cursor, len, header.seq, gc);
00260                 break;
00261         case QQ_CMD_RECV_MSG_SYS:
00262                 qq_process_msg_sys(cursor, len, header.seq, gc);
00263                 break;
00264         case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS:
00265                 qq_process_friend_change_status(cursor, len, gc);
00266                 break;
00267         case QQ_CMD_GET_LOGIN_TOKEN://add by Yuan Qingyun for QQ 2006 with SP1
00268                 qq_process_login_token_relay(cursor, len, gc);
00269                 break;
00270         default:
00271                 _qq_process_packet_default(cursor, len, header.cmd, header.seq, gc);
00272                 break;
00273         }                       // switch header.cmd
00274 }                               // _qq_packet_process
00275 
00276 /*****************************************************************************/
00277 // clean up the packets before login
00278 void qq_b4_packets_free(qq_data * qd)
00279 {
00280         packet_before_login *b4_packet;
00281         g_return_if_fail(qd != NULL);
00282         // now clean up my own data structures
00283         if (qd->before_login_packets != NULL) {
00284                 while (NULL != (b4_packet = g_queue_pop_tail(qd->before_login_packets))) {
00285                         g_free(b4_packet->buf);
00286                         g_free(b4_packet);
00287                 }
00288                 g_queue_free(qd->before_login_packets);
00289         }                       // if 
00290 }                               // qq_b4_packets_free
00291 
00292 /*****************************************************************************/
00293 void qq_input_pending(gpointer data, gint source, GaimInputCondition cond)
00294 {
00295         GaimConnection *gc;
00296         qq_data *qd;;
00297         guint8 *buf;
00298         gint len;
00299 
00300         gc = (GaimConnection *) data;
00301         g_return_if_fail(gc != NULL && gc->proto_data != NULL && cond == GAIM_INPUT_READ);
00302 
00303         qd = (qq_data *) gc->proto_data;
00304         // according to glib manual memory allocated by g_newa could be 
00305         // automatically freed when the current stack frame is cleaned up
00306         buf = g_newa(guint8, MAX_PACKET_SIZE);
00307 
00308         // here we have UDP proxy suppport
00309         len = qq_proxy_read(qd, buf, MAX_PACKET_SIZE);
00310         if (len <= 0) {
00311                 gaim_connection_error(gc, _("Unable to read from socket"));
00312                 return;
00313         } else
00314                 _qq_packet_process(buf, len, gc);
00315 }                               // qq_input_pending
00316 
00317 /*****************************************************************************/
00318 // END OF FILE

Generated at Mon May 8 15:41:24 2006 for OpenQ by  doxygen 1.4.4