Mercurial > pidgin
annotate libpurple/protocols/qq/qq_network.c @ 23638:1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
* Commit to Pidgin
* Tickets:
Fixes #1861
Fixes #1902
References #5112
2008.08.02 - ccpaging <ecc_hy(at)hotmail.com>
* Store all keys and md5 values of qq_data in char[QQ_KEY_LENGTH]
* Use random value in inikey
* TEA header padding in crypt.c
* Rewrite login part of qq_process
2008.07.31 - ccpaging <ecc_hy(at)hotmail.com>
* Fixed: send reply when get duplicate server command. The server may not get our reply before.
* Tag custom picture as text "(Broken)"
2008.07.30 - ccpaging <ecc_hy(at)hotmail.com>, csyfek <csyfek(at)gmail.com>
* Change some debug message
* Modify buddy status flag according to eva for QQ2006
* Modify buddy status parse and correspond to eva2
* Add getIP/putIP functions to packet_parse.c, and replace some gen_ip_str
* Replace guint32 *ip with struct in_addr, and reduce g_new/g_free operation
* Source file changed:
Merge buddy_status into buddy_list
Change login_logout to qq_base
Merge keep_alive into qq_base
New qq_process extract from qq_network
* Fixed: Byte alignment bug in crypt.c, tested in ARM PDA
* Fixed: group chat message may get in before getting group info, and so group info is empty
* Add qq_send_cmd_group_get_group_info when joined a group chat in group_im.c
* Add some new group command identify according eva but further program
* Add some new QQ client version identify
* Fixed: Identify buddy's client version by IM packet, and not by status
* Add some new info in buddy's tooltip text
* Add video falg to buddy's emblem. But those flag in buddy status may not prasing correctly
* Use new timeout function to handle send keep_alive, resend packet, update buddy status
* Add new advanced options:
The end user may change interval of keep_alive, resend packet, update buddy status to feed their
need.
For example, saving network flow when use mobile phone.
Keep alive packet must be sent in 60-120 seconds whatever client rcved data of not.
The intervals of keep alive and update status should be multiple of resend's interval,
Since we use counter not time() in a single timeout function for efficiency.
* Rewrite qq_trans.c, and use one g_list to manage:
Store server packet before login, and prase all of them when get login
Store client send packet for resend scanning, confirm server reply, filter duplicate server reply
Store server packet for filter out duplicate
* Add QQ_MSG_SYS_NOTICE = 0x06 in sys_msg.c
* Rewrite qq_proc_cmd_reply and qq_proc_cmd_server:
In QQ protocol, one packet reply may need a new packet send later.
We may call it packet trigger. The triggers always is hided in every qq_process_reply.
Now we try to extract those triggers and put into a single function,
and then every trigger should be obviously and easy to manage.
author | SHiNE CsyFeK <csyfek@gmail.com> |
---|---|
date | Sat, 02 Aug 2008 15:00:46 +0000 |
parents | bdb38a8bf721 |
children | 5f454b975a99 |
rev | line source |
---|---|
23050 | 1 /** |
2 * @file qq_network.c | |
3 * | |
4 * purple | |
5 * | |
6 * Purple is the legal property of its developers, whose names are too numerous | |
7 * to list here. Please refer to the COPYRIGHT file distributed with this | |
8 * source distribution. | |
9 * | |
10 * This program is free software; you can redistribute it and/or modify | |
11 * it under the terms of the GNU General Public License as published by | |
12 * the Free Software Foundation; either version 2 of the License, or | |
13 * (at your option) any later version. | |
14 * | |
15 * This program is distributed in the hope that it will be useful, | |
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 * GNU General Public License for more details. | |
19 * | |
20 * You should have received a copy of the GNU General Public License | |
21 * along with this program; if not, write to the Free Software | |
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA | |
23 */ | |
24 | |
25 #include "cipher.h" | |
26 #include "debug.h" | |
27 #include "internal.h" | |
28 | |
29 #ifdef _WIN32 | |
30 #define random rand | |
31 #define srandom srand | |
32 #endif | |
33 | |
34 #include "buddy_info.h" | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
35 #include "group_info.h" |
23050 | 36 #include "group_free.h" |
37 #include "crypt.h" | |
38 #include "header_info.h" | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
39 #include "qq_base.h" |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
40 #include "buddy_list.h" |
23050 | 41 #include "packet_parse.h" |
42 #include "qq_network.h" | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
43 #include "qq_trans.h" |
23050 | 44 #include "utils.h" |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
45 #include "qq_process.h" |
23050 | 46 |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
47 /* set QQ_RECONNECT_MAX to 1, when test reconnecting */ |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
48 #define QQ_RECONNECT_MAX 4 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
49 #define QQ_RECONNECT_INTERVAL 5000 |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
50 #define QQ_KEEP_ALIVE_INTERVAL 60000 |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
51 #define QQ_TRANS_INTERVAL 10000 |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
52 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
53 static gboolean set_new_server(qq_data *qd) |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
54 { |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
55 gint count; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
56 gint index; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
57 GList *it = NULL; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
58 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
59 g_return_val_if_fail(qd != NULL, FALSE); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
60 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
61 if (qd->servers == NULL) { |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
62 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Server list is NULL\n"); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
63 return FALSE; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
64 } |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
65 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
66 if (qd->real_hostname) { |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
67 purple_debug(PURPLE_DEBUG_INFO, "QQ", "free real_hostname\n"); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
68 g_free(qd->real_hostname); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
69 qd->real_hostname = NULL; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
70 } |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
71 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
72 /* remove server used before */ |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
73 if (qd->server_name != NULL) { |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
74 purple_debug(PURPLE_DEBUG_INFO, "QQ", |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
75 "Remove previous server [%s]\n", qd->server_name); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
76 qd->servers = g_list_remove(qd->servers, qd->server_name); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
77 qd->server_name = NULL; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
78 } |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
79 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
80 count = g_list_length(qd->servers); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
81 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Server list has %d\n", count); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
82 if (count <= 0) { |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
83 /* no server left, disconnect when result is false */ |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
84 qd->servers = NULL; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
85 return FALSE; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
86 } |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
87 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
88 /* get new server */ |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
89 index = random() % count; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
90 it = g_list_nth(qd->servers, index); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
91 qd->server_name = it->data; /* do not free server_name */ |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
92 if (qd->server_name == NULL || strlen(qd->server_name) <= 0 ) { |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
93 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Server name at %d is empty\n", index); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
94 return FALSE; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
95 } |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
96 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
97 qd->real_hostname = g_strdup(qd->server_name); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
98 qd->real_port = qd->user_port; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
99 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
100 qd->reconnect_times = QQ_RECONNECT_MAX; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
101 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
102 purple_debug(PURPLE_DEBUG_INFO, "QQ", |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
103 "set new server to %s:%d\n", qd->real_hostname, qd->real_port); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
104 return TRUE; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
105 } |
23050 | 106 |
107 static gint packet_get_header(guint8 *header_tag, guint16 *source_tag, | |
108 guint16 *cmd, guint16 *seq, guint8 *buf) | |
109 { | |
110 gint bytes = 0; | |
111 bytes += qq_get8(header_tag, buf + bytes); | |
112 bytes += qq_get16(source_tag, buf + bytes); | |
113 bytes += qq_get16(cmd, buf + bytes); | |
114 bytes += qq_get16(seq, buf + bytes); | |
115 return bytes; | |
116 } | |
117 | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
118 static gboolean reconnect_later_cb(gpointer data) |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
119 { |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
120 PurpleConnection *gc; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
121 qq_data *qd; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
122 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
123 gc = (PurpleConnection *) data; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
124 g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, FALSE); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
125 qd = (qq_data *) gc->proto_data; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
126 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
127 qd->reconnect_timeout = 0; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
128 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
129 qq_connect(gc->account); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
130 return FALSE; /* timeout callback stops */ |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
131 } |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
132 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
133 static void reconnect_later(PurpleConnection *gc) |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
134 { |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
135 qq_data *qd; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
136 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
137 g_return_if_fail(gc != NULL && gc->proto_data != NULL); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
138 qd = (qq_data *) gc->proto_data; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
139 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
140 qd->reconnect_times--; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
141 if (qd->reconnect_times < 0) { |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
142 if ( set_new_server(qd) != TRUE) { |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
143 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
144 _("Failed to connect server")); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
145 return; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
146 } |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
147 } |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
148 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
149 purple_debug(PURPLE_DEBUG_INFO, "QQ", |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
150 "Reconnect to server %s:%d next retries %d in %d ms\n", |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
151 qd->real_hostname, qd->real_port, |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
152 qd->reconnect_times, QQ_RECONNECT_INTERVAL); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
153 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
154 qd->reconnect_timeout = purple_timeout_add(QQ_RECONNECT_INTERVAL, |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
155 reconnect_later_cb, gc); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
156 } |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
157 |
23050 | 158 /* process the incoming packet from qq_pending */ |
159 static void packet_process(PurpleConnection *gc, guint8 *buf, gint buf_len) | |
160 { | |
161 qq_data *qd; | |
162 gint bytes, bytes_not_read; | |
163 | |
164 gboolean prev_login_status; | |
165 | |
166 guint8 header_tag; | |
167 guint16 source_tag; | |
168 guint16 cmd; | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
169 guint16 seq; /* May be ack_seq or send_seq, depends on cmd */ |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
170 |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
171 qq_transaction *trans; |
23050 | 172 |
173 g_return_if_fail(buf != NULL && buf_len > 0); | |
174 | |
175 qd = (qq_data *) gc->proto_data; | |
176 | |
177 prev_login_status = qd->logged_in; | |
178 | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
179 /* Len, header and tail tag have been checked before */ |
23050 | 180 bytes = 0; |
181 bytes += packet_get_header(&header_tag, &source_tag, &cmd, &seq, buf + bytes); | |
182 | |
183 if (QQ_DEBUG) { | |
184 purple_debug(PURPLE_DEBUG_INFO, "QQ", | |
185 "==> [%05d] 0x%04X %s, from (0x%04X %s)\n", | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
186 seq, cmd, qq_get_cmd_desc(cmd), source_tag, qq_get_ver_desc(source_tag)); |
23050 | 187 } |
188 | |
189 bytes_not_read = buf_len - bytes - 1; | |
190 | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
191 /* ack packet, we need to update send tranactions */ |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
192 /* we do not check duplication for server ack */ |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
193 trans = qq_trans_find_rcved(qd, cmd, seq); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
194 if (trans == NULL) { |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
195 /* new server command */ |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
196 qq_trans_add_server_cmd(qd, cmd, seq, buf + bytes, bytes_not_read); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
197 if ( qd->logged_in ) { |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
198 qq_proc_cmd_server(gc, cmd, seq, buf + bytes, bytes_not_read); |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
199 } |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
200 return; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
201 } |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
202 |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
203 if (qq_trans_is_dup(trans)) { |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
204 purple_debug(PURPLE_DEBUG_WARNING, |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
205 "QQ", "dup [%05d] %s, discard...\n", seq, qq_get_cmd_desc(cmd)); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
206 return; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
207 } |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
208 |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
209 if (qq_trans_is_server(trans)) { |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
210 if ( qd->logged_in ) { |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
211 qq_proc_cmd_server(gc, cmd, seq, buf + bytes, bytes_not_read); |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
212 } |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
213 return; |
23050 | 214 } |
215 | |
216 /* this is the length of all the encrypted data (also remove tail tag */ | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
217 qq_proc_cmd_reply(gc, cmd, seq, buf + bytes, bytes_not_read); |
23050 | 218 |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
219 /* check is redirect or not, and do it now */ |
23050 | 220 if (qd->is_redirect) { |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
221 /* free resource except real_hostname and port */ |
23050 | 222 qq_disconnect(gc); |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
223 qd->reconnect_times = QQ_RECONNECT_MAX; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
224 reconnect_later(gc); |
23050 | 225 return; |
226 } | |
227 | |
228 if (prev_login_status != qd->logged_in && qd->logged_in == TRUE) { | |
229 /* logged_in, but we have packets before login */ | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
230 qq_trans_process_before_login(qd); |
23050 | 231 } |
232 } | |
233 | |
234 static void tcp_pending(gpointer data, gint source, PurpleInputCondition cond) | |
235 { | |
236 PurpleConnection *gc; | |
237 qq_data *qd; | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
238 guint8 buf[1024]; /* set to 16 when test tcp_rxqueue */ |
23050 | 239 gint buf_len; |
240 gint bytes; | |
241 | |
242 guint8 *pkt; | |
243 guint16 pkt_len; | |
244 | |
245 gchar *error_msg; | |
246 guint8 *jump; | |
247 gint jump_len; | |
248 | |
249 gc = (PurpleConnection *) data; | |
250 g_return_if_fail(gc != NULL && gc->proto_data != NULL); | |
251 | |
252 if(cond != PURPLE_INPUT_READ) { | |
253 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | |
254 _("Socket error")); | |
255 return; | |
256 } | |
257 | |
258 qd = (qq_data *) gc->proto_data; | |
259 | |
260 /* test code, not using tcp_rxqueue | |
261 memset(pkt,0, sizeof(pkt)); | |
262 buf_len = read(qd->fd, pkt, sizeof(pkt)); | |
263 if (buf_len > 2) { | |
264 packet_process(gc, pkt + 2, buf_len - 2); | |
265 } | |
266 return; | |
267 */ | |
268 | |
269 buf_len = read(qd->fd, buf, sizeof(buf)); | |
270 if (buf_len < 0) { | |
271 if (errno == EAGAIN) | |
272 /* No worries */ | |
273 return; | |
274 | |
275 error_msg = g_strdup_printf(_("Lost connection with server:\n%d, %s"), errno, g_strerror(errno)); | |
276 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg); | |
277 g_free(error_msg); | |
278 return; | |
279 } else if (buf_len == 0) { | |
280 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | |
281 _("Server closed the connection.")); | |
282 return; | |
283 } | |
284 | |
23561
bdb38a8bf721
20080717-05-1-fix-keep-alive ccpaging <ecc_hy(at)hotmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23052
diff
changeset
|
285 /* keep alive will be sent in 30 seconds since last_receive |
bdb38a8bf721
20080717-05-1-fix-keep-alive ccpaging <ecc_hy(at)hotmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23052
diff
changeset
|
286 * QQ need a keep alive packet in every 60 seconds |
bdb38a8bf721
20080717-05-1-fix-keep-alive ccpaging <ecc_hy(at)hotmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23052
diff
changeset
|
287 gc->last_received = time(NULL); |
bdb38a8bf721
20080717-05-1-fix-keep-alive ccpaging <ecc_hy(at)hotmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23052
diff
changeset
|
288 */ |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
289 /* |
23050 | 290 purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING", |
291 "Read %d bytes from socket, rxlen is %d\n", buf_len, qd->tcp_rxlen); | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
292 */ |
23050 | 293 qd->tcp_rxqueue = g_realloc(qd->tcp_rxqueue, buf_len + qd->tcp_rxlen); |
294 memcpy(qd->tcp_rxqueue + qd->tcp_rxlen, buf, buf_len); | |
295 qd->tcp_rxlen += buf_len; | |
296 | |
297 pkt = g_newa(guint8, MAX_PACKET_SIZE); | |
298 while (1) { | |
299 if (qd->tcp_rxlen < QQ_TCP_HEADER_LENGTH) { | |
300 break; | |
301 } | |
302 | |
303 bytes = 0; | |
304 bytes += qq_get16(&pkt_len, qd->tcp_rxqueue + bytes); | |
305 if (qd->tcp_rxlen < pkt_len) { | |
306 break; | |
307 } | |
308 | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
309 /* |
23050 | 310 purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING", |
311 "Packet len is %d bytes, rxlen is %d\n", pkt_len, qd->tcp_rxlen); | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
312 */ |
23050 | 313 if ( pkt_len < QQ_TCP_HEADER_LENGTH |
314 || *(qd->tcp_rxqueue + bytes) != QQ_PACKET_TAG | |
315 || *(qd->tcp_rxqueue + pkt_len - 1) != QQ_PACKET_TAIL) { | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
316 /* HEY! This isn't even a QQ. What are you trying to pull? */ |
23050 | 317 |
318 purple_debug(PURPLE_DEBUG_ERROR, "TCP_PENDING", | |
319 "Packet error, failed to check header and tail tag\n"); | |
320 | |
321 jump = memchr(qd->tcp_rxqueue + 1, QQ_PACKET_TAIL, qd->tcp_rxlen - 1); | |
322 if ( !jump ) { | |
323 purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING", | |
324 "Failed to find next QQ_PACKET_TAIL, clear receive buffer\n"); | |
325 g_free(qd->tcp_rxqueue); | |
326 qd->tcp_rxqueue = NULL; | |
327 qd->tcp_rxlen = 0; | |
328 return; | |
329 } | |
330 | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
331 /* jump and over QQ_PACKET_TAIL */ |
23050 | 332 jump_len = (jump - qd->tcp_rxqueue) + 1; |
333 purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING", | |
334 "Find next QQ_PACKET_TAIL at %d, jump %d bytes\n", jump_len, jump_len + 1); | |
335 g_memmove(qd->tcp_rxqueue, jump, qd->tcp_rxlen - jump_len); | |
336 qd->tcp_rxlen -= jump_len; | |
337 continue; | |
338 } | |
339 | |
340 memset(pkt, 0, MAX_PACKET_SIZE); | |
341 g_memmove(pkt, qd->tcp_rxqueue + bytes, pkt_len - bytes); | |
342 | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
343 /* jump to next packet */ |
23050 | 344 qd->tcp_rxlen -= pkt_len; |
345 if (qd->tcp_rxlen) { | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
346 /* |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
347 purple_debug(PURPLE_DEBUG_ERROR, "TCP_PENDING", "shrink tcp_rxqueue to %d\n", qd->tcp_rxlen); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
348 */ |
23050 | 349 jump = g_memdup(qd->tcp_rxqueue + pkt_len, qd->tcp_rxlen); |
350 g_free(qd->tcp_rxqueue); | |
351 qd->tcp_rxqueue = jump; | |
352 } else { | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
353 /* purple_debug(PURPLE_DEBUG_ERROR, "TCP_PENDING", "free tcp_rxqueue\n"); */ |
23050 | 354 g_free(qd->tcp_rxqueue); |
355 qd->tcp_rxqueue = NULL; | |
356 } | |
357 | |
358 if (pkt == NULL) { | |
359 continue; | |
360 } | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
361 /* do not call packet_process before jump |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
362 * packet_process may call disconnect and destory tcp_rxqueue */ |
23050 | 363 packet_process(gc, pkt, pkt_len - bytes); |
364 } | |
365 } | |
366 | |
367 static void udp_pending(gpointer data, gint source, PurpleInputCondition cond) | |
368 { | |
369 PurpleConnection *gc; | |
370 qq_data *qd; | |
371 guint8 *buf; | |
372 gint buf_len; | |
373 | |
374 gc = (PurpleConnection *) data; | |
375 g_return_if_fail(gc != NULL && gc->proto_data != NULL); | |
376 | |
377 if(cond != PURPLE_INPUT_READ) { | |
378 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | |
379 _("Socket error")); | |
380 return; | |
381 } | |
382 | |
383 qd = (qq_data *) gc->proto_data; | |
384 g_return_if_fail(qd->fd >= 0); | |
385 | |
386 buf = g_newa(guint8, MAX_PACKET_SIZE); | |
387 | |
388 /* here we have UDP proxy suppport */ | |
389 buf_len = read(qd->fd, buf, MAX_PACKET_SIZE); | |
390 if (buf_len <= 0) { | |
391 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | |
392 _("Unable to read from socket")); | |
393 return; | |
394 } | |
395 | |
23561
bdb38a8bf721
20080717-05-1-fix-keep-alive ccpaging <ecc_hy(at)hotmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23052
diff
changeset
|
396 /* keep alive will be sent in 30 seconds since last_receive |
bdb38a8bf721
20080717-05-1-fix-keep-alive ccpaging <ecc_hy(at)hotmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23052
diff
changeset
|
397 * QQ need a keep alive packet in every 60 seconds |
bdb38a8bf721
20080717-05-1-fix-keep-alive ccpaging <ecc_hy(at)hotmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23052
diff
changeset
|
398 gc->last_received = time(NULL); |
bdb38a8bf721
20080717-05-1-fix-keep-alive ccpaging <ecc_hy(at)hotmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23052
diff
changeset
|
399 */ |
23050 | 400 |
401 if (buf_len < QQ_UDP_HEADER_LENGTH) { | |
402 if (buf[0] != QQ_PACKET_TAG || buf[buf_len - 1] != QQ_PACKET_TAIL) { | |
403 qq_hex_dump(PURPLE_DEBUG_ERROR, "UDP_PENDING", | |
404 buf, buf_len, | |
405 "Received packet is too short, or no header and tail tag"); | |
406 return; | |
407 } | |
408 } | |
409 | |
410 packet_process(gc, buf, buf_len); | |
411 } | |
412 | |
413 static gint udp_send_out(qq_data *qd, guint8 *data, gint data_len) | |
414 { | |
415 gint ret; | |
416 | |
417 g_return_val_if_fail(qd != NULL && qd->fd >= 0 && data != NULL && data_len > 0, -1); | |
418 | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
419 /* |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
420 purple_debug(PURPLE_DEBUG_INFO, "UDP_SEND_OUT", "Send %d bytes to socket %d\n", data_len, qd->fd); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
421 */ |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
422 |
23050 | 423 errno = 0; |
424 ret = send(qd->fd, data, data_len, 0); | |
425 if (ret < 0 && errno == EAGAIN) { | |
426 return ret; | |
427 } | |
428 | |
429 if (ret < 0) { | |
430 /* TODO: what to do here - do we really have to disconnect? */ | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
431 purple_debug(PURPLE_DEBUG_ERROR, "UDP_SEND_OUT", "Send failed: %d, %s\n", errno, g_strerror(errno)); |
23050 | 432 purple_connection_error_reason(qd->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, g_strerror(errno)); |
433 } | |
434 return ret; | |
435 } | |
436 | |
437 static void tcp_can_write(gpointer data, gint source, PurpleInputCondition cond) | |
438 { | |
439 qq_data *qd = data; | |
440 int ret, writelen; | |
441 | |
442 writelen = purple_circ_buffer_get_max_read(qd->tcp_txbuf); | |
443 if (writelen == 0) { | |
444 purple_input_remove(qd->tx_handler); | |
445 qd->tx_handler = 0; | |
446 return; | |
447 } | |
448 | |
449 ret = write(qd->fd, qd->tcp_txbuf->outptr, writelen); | |
450 purple_debug(PURPLE_DEBUG_ERROR, "TCP_CAN_WRITE", | |
451 "total %d bytes is sent %d\n", writelen, ret); | |
452 | |
453 if (ret < 0 && errno == EAGAIN) | |
454 return; | |
455 else if (ret < 0) { | |
456 /* TODO: what to do here - do we really have to disconnect? */ | |
457 purple_connection_error_reason(qd->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | |
458 _("Write Error")); | |
459 return; | |
460 } | |
461 | |
462 purple_circ_buffer_mark_read(qd->tcp_txbuf, ret); | |
463 } | |
464 | |
465 static gint tcp_send_out(qq_data *qd, guint8 *data, gint data_len) | |
466 { | |
467 gint ret; | |
468 | |
469 g_return_val_if_fail(qd != NULL && qd->fd >= 0 && data != NULL && data_len > 0, -1); | |
470 | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
471 /* |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
472 purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", "Send %d bytes to socket %d\n", data_len, qd->fd); |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
473 */ |
23050 | 474 |
475 if (qd->tx_handler == 0) { | |
476 ret = write(qd->fd, data, data_len); | |
477 } else { | |
478 ret = -1; | |
479 errno = EAGAIN; | |
480 } | |
481 | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
482 /* |
23050 | 483 purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", |
484 "Socket %d, total %d bytes is sent %d\n", qd->fd, data_len, ret); | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
485 */ |
23050 | 486 if (ret < 0 && errno == EAGAIN) { |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
487 /* socket is busy, send later */ |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
488 purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", "Socket is busy and send later\n"); |
23050 | 489 ret = 0; |
490 } else if (ret <= 0) { | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
491 /* TODO: what to do here - do we really have to disconnect? */ |
23050 | 492 purple_debug(PURPLE_DEBUG_ERROR, "TCP_SEND_OUT", |
493 "Send to socket %d failed: %d, %s\n", qd->fd, errno, g_strerror(errno)); | |
494 purple_connection_error_reason(qd->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, g_strerror(errno)); | |
495 return ret; | |
496 } | |
497 | |
498 if (ret < data_len) { | |
499 purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", | |
500 "Add %d bytes to buffer\n", data_len - ret); | |
501 if (qd->tx_handler == 0) { | |
502 qd->tx_handler = purple_input_add(qd->fd, PURPLE_INPUT_WRITE, tcp_can_write, qd); | |
503 } | |
504 purple_circ_buffer_append(qd->tcp_txbuf, data + ret, data_len - ret); | |
505 } | |
506 return ret; | |
507 } | |
508 | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
509 static gboolean network_timeout(gpointer data) |
23050 | 510 { |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
511 PurpleConnection *gc = (PurpleConnection *) data; |
23050 | 512 qq_data *qd; |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
513 gboolean is_lost_conn; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
514 |
23050 | 515 g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, TRUE); |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
516 qd = (qq_data *) gc->proto_data; |
23050 | 517 |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
518 is_lost_conn = qq_trans_scan(qd); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
519 if (is_lost_conn) { |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
520 purple_connection_error_reason(gc, |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
521 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Connection lost")); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
522 return TRUE; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
523 } |
23050 | 524 |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
525 if ( !qd->logged_in ) { |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
526 return TRUE; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
527 } |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
528 |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
529 qd->itv_count.keep_alive--; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
530 if (qd->itv_count.keep_alive <= 0) { |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
531 qd->itv_count.keep_alive = qd->itv_config.keep_alive; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
532 qq_send_packet_keep_alive(gc); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
533 return TRUE; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
534 } |
23050 | 535 |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
536 if (qd->itv_config.update <= 0) { |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
537 return TRUE; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
538 } |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
539 |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
540 qd->itv_count.update--; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
541 if (qd->itv_count.update <= 0) { |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
542 qd->itv_count.update = qd->itv_config.update; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
543 qq_send_packet_get_buddies_online(gc, 0); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
544 |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
545 qq_send_cmd_group_all_get_online_members(gc); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
546 return TRUE; |
23050 | 547 } |
548 | |
549 return TRUE; /* if return FALSE, timeout callback stops */ | |
550 } | |
551 | |
552 /* the callback function after socket is built | |
553 * we setup the qq protocol related configuration here */ | |
554 static void qq_connect_cb(gpointer data, gint source, const gchar *error_message) | |
555 { | |
556 qq_data *qd; | |
557 PurpleConnection *gc; | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
558 gchar *conn_msg; |
23050 | 559 const gchar *passwd; |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
560 PurpleAccount *account ; |
23050 | 561 |
562 gc = (PurpleConnection *) data; | |
563 | |
564 if (!PURPLE_CONNECTION_IS_VALID(gc)) { | |
565 purple_debug(PURPLE_DEBUG_INFO, "QQ_CONN", "Invalid connection\n"); | |
566 close(source); | |
567 return; | |
568 } | |
569 | |
570 g_return_if_fail(gc != NULL && gc->proto_data != NULL); | |
571 | |
572 qd = (qq_data *) gc->proto_data; | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
573 account = purple_connection_get_account(gc); |
23050 | 574 |
575 /* Connect is now complete; clear the PurpleProxyConnectData */ | |
576 qd->connect_data = NULL; | |
577 | |
578 if (source < 0) { /* socket returns -1 */ | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
579 purple_debug(PURPLE_DEBUG_INFO, "QQ_CONN", "Invalid connection, source is < 0\n"); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
580 qq_disconnect(gc); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
581 reconnect_later(gc); |
23050 | 582 return; |
583 } | |
584 | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
585 /* _qq_show_socket("Got login socket", source); */ |
23050 | 586 |
587 /* QQ use random seq, to minimize duplicated packets */ | |
588 srandom(time(NULL)); | |
589 qd->send_seq = random() & 0x0000ffff; | |
590 qd->fd = source; | |
591 qd->logged_in = FALSE; | |
592 qd->channel = 1; | |
593 qd->uid = strtol(purple_account_get_username(purple_connection_get_account(gc)), NULL, 10); | |
594 | |
595 /* now generate md5 processed passwd */ | |
596 passwd = purple_account_get_password(purple_connection_get_account(gc)); | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
597 |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
598 /* use twice-md5 of user password as session key since QQ 2003iii */ |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
599 qq_get_md5(qd->password_twice_md5, sizeof(qd->password_twice_md5), |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
600 (guint8 *)passwd, strlen(passwd)); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
601 qq_get_md5(qd->password_twice_md5, sizeof(qd->password_twice_md5), |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
602 qd->password_twice_md5, sizeof(qd->password_twice_md5)); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
603 |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
604 g_return_if_fail(qd->network_timeout == 0); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
605 qd->itv_config.resend = purple_account_get_int(account, "resend_interval", 10); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
606 if (qd->itv_config.resend <= 0) qd->itv_config.resend = 10; |
23050 | 607 |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
608 qd->itv_config.keep_alive = purple_account_get_int(account, "keep_alive_interval", 60); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
609 if (qd->itv_config.keep_alive < 30) qd->itv_config.keep_alive = 30; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
610 qd->itv_config.keep_alive /= qd->itv_config.resend; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
611 qd->itv_count.keep_alive = qd->itv_config.keep_alive; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
612 |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
613 qd->itv_config.update = purple_account_get_int(account, "update_interval", 300); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
614 if (qd->itv_config.update > 0) { |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
615 if (qd->itv_config.update < qd->itv_config.keep_alive) { |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
616 qd->itv_config.update = qd->itv_config.keep_alive; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
617 } |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
618 qd->itv_config.update /= qd->itv_config.resend; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
619 qd->itv_count.update = qd->itv_config.update; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
620 } else { |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
621 qd->itv_config.update = 0; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
622 } |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
623 |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
624 qd->network_timeout = purple_timeout_add(qd->itv_config.resend *1000, network_timeout, gc); |
23050 | 625 |
626 if (qd->use_tcp) | |
627 gc->inpa = purple_input_add(qd->fd, PURPLE_INPUT_READ, tcp_pending, gc); | |
628 else | |
629 gc->inpa = purple_input_add(qd->fd, PURPLE_INPUT_READ, udp_pending, gc); | |
630 | |
631 /* Update the login progress status display */ | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
632 conn_msg = g_strdup_printf("Login as %d", qd->uid); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
633 purple_connection_update_progress(gc, conn_msg, QQ_CONNECT_STEPS - 1, QQ_CONNECT_STEPS); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
634 g_free(conn_msg); |
23050 | 635 |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
636 qq_send_packet_token(gc); |
23050 | 637 } |
638 | |
639 static void udp_can_write(gpointer data, gint source, PurpleInputCondition cond) | |
640 { | |
641 PurpleConnection *gc; | |
642 qq_data *qd; | |
643 socklen_t len; | |
644 int error=0, ret; | |
645 | |
646 gc = (PurpleConnection *) data; | |
647 g_return_if_fail(gc != NULL && gc->proto_data != NULL); | |
648 | |
649 qd = (qq_data *) gc->proto_data; | |
650 | |
651 | |
652 purple_debug_info("proxy", "Connected.\n"); | |
653 | |
654 /* | |
655 * getsockopt after a non-blocking connect returns -1 if something is | |
656 * really messed up (bad descriptor, usually). Otherwise, it returns 0 and | |
657 * error holds what connect would have returned if it blocked until now. | |
658 * Thus, error == 0 is success, error == EINPROGRESS means "try again", | |
659 * and anything else is a real error. | |
660 * | |
661 * (error == EINPROGRESS can happen after a select because the kernel can | |
662 * be overly optimistic sometimes. select is just a hint that you might be | |
663 * able to do something.) | |
664 */ | |
665 len = sizeof(error); | |
666 ret = getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len); | |
667 if (ret == 0 && error == EINPROGRESS) | |
668 return; /* we'll be called again later */ | |
669 | |
670 purple_input_remove(qd->tx_handler); | |
671 qd->tx_handler = 0; | |
672 if (ret < 0 || error != 0) { | |
673 if(ret != 0) | |
674 error = errno; | |
675 | |
676 close(source); | |
677 | |
678 purple_debug_error("proxy", "getsockopt SO_ERROR check: %s\n", g_strerror(error)); | |
679 | |
680 qq_connect_cb(gc, -1, _("Unable to connect")); | |
681 return; | |
682 } | |
683 | |
684 qq_connect_cb(gc, source, NULL); | |
685 } | |
686 | |
687 static void udp_host_resolved(GSList *hosts, gpointer data, const char *error_message) { | |
688 PurpleConnection *gc; | |
689 qq_data *qd; | |
690 struct sockaddr server_addr; | |
691 int addr_size; | |
692 gint fd = -1; | |
693 int flags; | |
694 | |
695 gc = (PurpleConnection *) data; | |
696 g_return_if_fail(gc != NULL && gc->proto_data != NULL); | |
697 | |
698 qd = (qq_data *) gc->proto_data; | |
699 | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
700 /* udp_query_data must be set as NULL. |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
701 * Otherwise purple_dnsquery_destroy in qq_disconnect cause glib double free error */ |
23050 | 702 qd->udp_query_data = NULL; |
703 | |
704 if (!hosts || !hosts->data) { | |
705 purple_connection_error_reason(gc, | |
706 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | |
707 _("Couldn't resolve host")); | |
708 return; | |
709 } | |
710 | |
711 addr_size = GPOINTER_TO_INT(hosts->data); | |
712 hosts = g_slist_remove(hosts, hosts->data); | |
713 memcpy(&server_addr, hosts->data, addr_size); | |
714 g_free(hosts->data); | |
715 | |
716 hosts = g_slist_remove(hosts, hosts->data); | |
717 while(hosts) { | |
718 hosts = g_slist_remove(hosts, hosts->data); | |
719 g_free(hosts->data); | |
720 hosts = g_slist_remove(hosts, hosts->data); | |
721 } | |
722 | |
723 fd = socket(PF_INET, SOCK_DGRAM, 0); | |
724 if (fd < 0) { | |
725 purple_debug(PURPLE_DEBUG_ERROR, "QQ", | |
726 "Unable to create socket: %s\n", g_strerror(errno)); | |
727 return; | |
728 } | |
729 | |
730 /* we use non-blocking mode to speed up connection */ | |
731 flags = fcntl(fd, F_GETFL); | |
732 fcntl(fd, F_SETFL, flags | O_NONBLOCK); | |
733 | |
734 /* From Unix-socket-FAQ: http://www.faqs.org/faqs/unix-faq/socket/ | |
735 * | |
736 * If a UDP socket is unconnected, which is the normal state after a | |
737 * bind() call, then send() or write() are not allowed, since no | |
738 * destination is available; only sendto() can be used to send data. | |
739 * | |
740 * Calling connect() on the socket simply records the specified address | |
741 * and port number as being the desired communications partner. That | |
742 * means that send() or write() are now allowed; they use the destination | |
743 * address and port given on the connect call as the destination of packets. | |
744 */ | |
745 if (connect(fd, &server_addr, addr_size) >= 0) { | |
746 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Connected.\n"); | |
747 flags = fcntl(fd, F_GETFL); | |
748 fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); | |
749 qq_connect_cb(gc, fd, NULL); | |
750 return; | |
751 } | |
752 | |
753 /* [EINPROGRESS] | |
754 * The socket is marked as non-blocking and the connection cannot be | |
755 * completed immediately. It is possible to select for completion by | |
756 * selecting the socket for writing. | |
757 * [EINTR] | |
758 * A signal interrupted the call. | |
759 * The connection is established asynchronously. | |
760 */ | |
761 if ((errno == EINPROGRESS) || (errno == EINTR)) { | |
762 purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Connect in asynchronous mode.\n"); | |
763 qd->tx_handler = purple_input_add(fd, PURPLE_INPUT_WRITE, udp_can_write, gc); | |
764 return; | |
765 } | |
766 | |
23052
ebad75b719f5
Sun Jun 29 22:00:12 CST 2008 csyfek@gmail.com
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23051
diff
changeset
|
767 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Connection failed: %s\n", g_strerror(errno)); |
23050 | 768 close(fd); |
769 } | |
770 | |
771 /* establish a generic QQ connection | |
772 * TCP/UDP, and direct/redirected */ | |
773 void qq_connect(PurpleAccount *account) | |
774 { | |
775 PurpleConnection *gc; | |
776 qq_data *qd; | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
777 gchar *conn_msg; |
23050 | 778 |
779 gc = purple_account_get_connection(account); | |
780 g_return_if_fail(gc != NULL && gc->proto_data != NULL); | |
781 | |
782 qd = (qq_data *) gc->proto_data; | |
783 | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
784 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
785 /* test set_new_server |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
786 while (set_new_server(qd)) { |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
787 purple_debug(PURPLE_DEBUG_INFO, "QQ_TEST", |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
788 "New server %s:%d Real server %s:%d\n", |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
789 qd->server_name, qd->user_port, qd->real_hostname, qd->real_port); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
790 } |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
791 purple_debug(PURPLE_DEBUG_INFO, "QQ_TEST", "qd->servers %lu\n", |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
792 qd->servers); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
793 exit(1); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
794 */ |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
795 if (qd->server_name == NULL) { |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
796 /* must be first call this function */ |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
797 if ( set_new_server(qd) != TRUE) { |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
798 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
799 _("Failed to connect server")); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
800 return; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
801 } |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
802 } |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
803 |
23050 | 804 if (qd->real_hostname == NULL || qd->real_port == 0) { |
805 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | |
806 _("hostname is NULL or port is 0")); | |
807 return; | |
808 } | |
809 | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
810 conn_msg = g_strdup_printf( _("Connecting server %s, retries %d"), |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
811 qd->real_hostname, qd->reconnect_times); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
812 purple_connection_update_progress(gc, conn_msg, 1, QQ_CONNECT_STEPS); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
813 g_free(conn_msg); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
814 |
23050 | 815 if (qd->is_redirect) { |
816 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Redirect to %s:%d\n", | |
817 qd->real_hostname, qd->real_port); | |
818 } | |
819 qd->is_redirect = FALSE; | |
820 | |
821 qd->fd = -1; | |
822 qd->tx_handler = 0; | |
823 | |
824 /* QQ connection via UDP/TCP. | |
825 * Now use Purple proxy function to provide TCP proxy support, | |
826 * and qq_udp_proxy.c to add UDP proxy support (thanks henry) */ | |
827 if(qd->use_tcp) { | |
828 purple_debug(PURPLE_DEBUG_INFO, "QQ", "TCP Connect to %s:%d\n", | |
829 qd->real_hostname, qd->real_port); | |
830 | |
831 /* TODO: is there a good default grow size? */ | |
832 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Create tcp_txbuf\n"); | |
833 qd->tcp_txbuf = purple_circ_buffer_new(0); | |
834 | |
835 qd->connect_data = purple_proxy_connect(NULL, account, | |
836 qd->real_hostname, qd->real_port, qq_connect_cb, gc); | |
837 if (qd->connect_data == NULL) { | |
838 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | |
839 _("Unable to connect.")); | |
840 } | |
841 return; | |
842 } | |
843 | |
844 purple_debug(PURPLE_DEBUG_INFO, "QQ", "UDP Connect to %s:%d\n", | |
845 qd->real_hostname, qd->real_port); | |
846 | |
847 g_return_if_fail(qd->udp_query_data == NULL); | |
848 qd->udp_query_data = purple_dnsquery_a(qd->real_hostname, qd->real_port, | |
849 udp_host_resolved, gc); | |
850 if (qd->udp_query_data == NULL) { | |
851 purple_connection_error_reason(qd->gc, | |
852 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | |
853 _("Could not resolve hostname")); | |
854 } | |
855 } | |
856 | |
857 /* clean up qq_data structure and all its components | |
858 * always used before a redirectly connection */ | |
859 void qq_disconnect(PurpleConnection *gc) | |
860 { | |
861 qq_data *qd; | |
862 | |
863 g_return_if_fail(gc != NULL && gc->proto_data != NULL); | |
864 qd = (qq_data *) gc->proto_data; | |
865 | |
866 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Disconnecting ...\n"); | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
867 |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
868 if (qd->network_timeout > 0) { |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
869 purple_timeout_remove(qd->network_timeout); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
870 qd->network_timeout = 0; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
871 } |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
872 |
23050 | 873 /* finish all I/O */ |
874 if (qd->fd >= 0 && qd->logged_in) { | |
875 qq_send_packet_logout(gc); | |
876 } | |
877 | |
878 if (gc->inpa > 0) { | |
879 purple_input_remove(gc->inpa); | |
880 gc->inpa = 0; | |
881 } | |
882 | |
883 if (qd->fd >= 0) { | |
884 close(qd->fd); | |
885 qd->fd = -1; | |
886 } | |
887 | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
888 if (qd->reconnect_timeout > 0) { |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
889 purple_timeout_remove(qd->reconnect_timeout); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
890 qd->reconnect_timeout = 0; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
891 } |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
892 |
23050 | 893 if (qd->connect_data != NULL) { |
894 purple_debug(PURPLE_DEBUG_INFO, "QQ", "Cancel connect_data\n"); | |
895 purple_proxy_connect_cancel(qd->connect_data); | |
896 } | |
897 | |
898 if(qd->tcp_txbuf != NULL) { | |
899 purple_debug(PURPLE_DEBUG_INFO, "QQ", "destroy tcp_txbuf\n"); | |
900 purple_circ_buffer_destroy(qd->tcp_txbuf); | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
901 qd->tcp_txbuf = NULL; |
23050 | 902 } |
903 | |
904 if (qd->tx_handler) { | |
905 purple_input_remove(qd->tx_handler); | |
906 qd->tx_handler = 0; | |
907 } | |
908 if (qd->tcp_rxqueue != NULL) { | |
909 purple_debug(PURPLE_DEBUG_INFO, "QQ", "destroy tcp_rxqueue\n"); | |
910 g_free(qd->tcp_rxqueue); | |
911 qd->tcp_rxqueue = NULL; | |
912 qd->tcp_rxlen = 0; | |
913 } | |
914 | |
915 if (qd->udp_query_data != NULL) { | |
916 purple_debug(PURPLE_DEBUG_INFO, "QQ", "destroy udp_query_data\n"); | |
917 purple_dnsquery_destroy(qd->udp_query_data); | |
918 qd->udp_query_data = NULL; | |
919 } | |
920 | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
921 qq_trans_remove_all(qd); |
23050 | 922 |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
923 if (qd->token) { |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
924 purple_debug(PURPLE_DEBUG_INFO, "QQ", "free token\n"); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
925 g_free(qd->token); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
926 qd->token = NULL; |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
927 qd->token_len = 0; |
23050 | 928 } |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
929 memset(qd->inikey, 0, sizeof(qd->inikey)); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
930 memset(qd->password_twice_md5, 0, sizeof(qd->password_twice_md5)); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
931 memset(qd->session_key, 0, sizeof(qd->session_key)); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
932 memset(qd->session_md5, 0, sizeof(qd->session_md5)); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
933 |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
934 qd->my_ip.s_addr = 0; |
23050 | 935 |
936 qq_group_packets_free(qd); | |
937 qq_group_free_all(qd); | |
938 qq_add_buddy_request_free(qd); | |
939 qq_info_query_free(qd); | |
940 qq_buddies_list_free(gc->account, qd); | |
941 } | |
942 | |
943 static gint encap(qq_data *qd, guint8 *buf, gint maxlen, guint16 cmd, guint16 seq, | |
944 guint8 *data, gint data_len) | |
945 { | |
946 gint bytes = 0; | |
947 g_return_val_if_fail(qd != NULL && buf != NULL && maxlen > 0, -1); | |
948 | |
949 if (data == NULL) { | |
950 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail encap packet, data is NULL\n"); | |
951 return -1; | |
952 } | |
953 if (data_len <= 0) { | |
954 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail encap packet, data len <= 0\n"); | |
955 return -1; | |
956 } | |
957 | |
958 /* QQ TCP packet has two bytes in the begining defines packet length | |
959 * so leave room here to store packet size */ | |
960 if (qd->use_tcp) { | |
961 bytes += qq_put16(buf + bytes, 0x0000); | |
962 } | |
963 /* now comes the normal QQ packet as UDP */ | |
964 bytes += qq_put8(buf + bytes, QQ_PACKET_TAG); | |
965 bytes += qq_put16(buf + bytes, QQ_CLIENT); | |
966 bytes += qq_put16(buf + bytes, cmd); | |
967 | |
968 bytes += qq_put16(buf + bytes, seq); | |
969 | |
970 bytes += qq_put32(buf + bytes, qd->uid); | |
971 bytes += qq_putdata(buf + bytes, data, data_len); | |
972 bytes += qq_put8(buf + bytes, QQ_PACKET_TAIL); | |
973 | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
974 /* set TCP packet length at begin of the packet */ |
23050 | 975 if (qd->use_tcp) { |
976 qq_put16(buf, bytes); | |
977 } | |
978 | |
979 return bytes; | |
980 } | |
981 | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
982 /* data has been encrypted before */ |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
983 gint qq_send_data(qq_data *qd, guint16 cmd, guint16 seq, gboolean need_ack, |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
984 guint8 *data, gint data_len) |
23050 | 985 { |
986 guint8 *buf; | |
987 gint buf_len; | |
988 gint bytes_sent; | |
989 | |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
990 g_return_val_if_fail(qd != NULL, -1); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
991 g_return_val_if_fail(data != NULL && data_len > 0, -1); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
992 |
23050 | 993 buf = g_newa(guint8, MAX_PACKET_SIZE); |
994 memset(buf, 0, MAX_PACKET_SIZE); | |
995 buf_len = encap(qd, buf, MAX_PACKET_SIZE, cmd, seq, data, data_len); | |
996 if (buf_len <= 0) { | |
997 return -1; | |
998 } | |
999 | |
1000 if (qd->use_tcp) { | |
1001 bytes_sent = tcp_send_out(qd, buf, buf_len); | |
1002 } else { | |
1003 bytes_sent = udp_send_out(qd, buf, buf_len); | |
1004 } | |
1005 | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
1006 if (need_ack) { |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
1007 qq_trans_add_client_cmd(qd, cmd, seq, data, data_len); |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
1008 } |
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
1009 |
23050 | 1010 if (QQ_DEBUG) { |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
1011 /* qq_show_packet("QQ_SEND_DATA", buf, buf_len); */ |
23050 | 1012 purple_debug(PURPLE_DEBUG_INFO, "QQ", |
1013 "<== [%05d], %s, total %d bytes is sent %d\n", | |
1014 seq, qq_get_cmd_desc(cmd), buf_len, bytes_sent); | |
1015 } | |
1016 return bytes_sent; | |
1017 } | |
1018 | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
1019 /* Encrypt data with session_key, then call qq_send_data */ |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
1020 gint qq_send_cmd_detail(qq_data *qd, guint16 cmd, guint16 seq, gboolean need_ack, |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
1021 guint8 *data, gint data_len) |
23050 | 1022 { |
1023 guint8 *encrypted_data; | |
1024 gint encrypted_len; | |
1025 | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
1026 g_return_val_if_fail(qd != NULL, -1); |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
1027 g_return_val_if_fail(data != NULL && data_len > 0, -1); |
23050 | 1028 |
1029 encrypted_len = data_len + 16; /* at most 16 bytes more */ | |
1030 encrypted_data = g_newa(guint8, encrypted_len); | |
1031 | |
1032 qq_encrypt(data, data_len, qd->session_key, encrypted_data, &encrypted_len); | |
1033 | |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
1034 return qq_send_data(qd, cmd, seq, need_ack, encrypted_data, encrypted_len); |
23050 | 1035 } |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
1036 |
23638
1c50f12b1c52
2008.08.02 - csyfek <csyfek(at)gmail.com>
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23561
diff
changeset
|
1037 /* set seq and need_ack, then call qq_send_cmd_detail */ |
23051
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
1038 gint qq_send_cmd(qq_data *qd, guint16 cmd, guint8 *data, gint data_len) |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
1039 { |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
1040 g_return_val_if_fail(qd != NULL, -1); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
1041 g_return_val_if_fail(data != NULL && data_len > 0, -1); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
1042 |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
1043 qd->send_seq++; |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
1044 return qq_send_cmd_detail(qd, cmd, qd->send_seq, TRUE, data, data_len); |
55f986ccbb6a
patch-05-reconnect-and-code-cleanup
SHiNE CsyFeK <csyfek@gmail.com>
parents:
23050
diff
changeset
|
1045 } |