comparison libpurple/protocols/msnp9/directconn.c @ 21312:a07cfce78345

Add MSNP9 back as an alternative alongside the existing MSN prpl. Cowardly old fools like me who prefer the stability of our MSNP9 code over the features of MSNP14 can enable this using the --disable-msnp14 ./configure option. If we want to release from i.p.p and MSN stability is the only blocker, we can trivially flick the default to use MSNP9 in configure.ac
author Stu Tomlinson <stu@nosnilmot.com>
date Sun, 11 Nov 2007 12:57:52 +0000
parents
children 960c07f6f052
comparison
equal deleted inserted replaced
21311:7d031cec5ba2 21312:a07cfce78345
1 /**
2 * @file directconn.c MSN direct connection functions
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 #include "msn.h"
25 #include "directconn.h"
26
27 #include "slp.h"
28 #include "slpmsg.h"
29
30 /**************************************************************************
31 * Directconn Specific
32 **************************************************************************/
33
34 void
35 msn_directconn_send_handshake(MsnDirectConn *directconn)
36 {
37 MsnSlpLink *slplink;
38 MsnSlpMessage *slpmsg;
39
40 g_return_if_fail(directconn != NULL);
41
42 slplink = directconn->slplink;
43
44 slpmsg = msn_slpmsg_new(slplink);
45 slpmsg->flags = 0x100;
46
47 if (directconn->nonce != NULL)
48 {
49 guint32 t1;
50 guint16 t2;
51 guint16 t3;
52 guint16 t4;
53 guint64 t5;
54
55 sscanf (directconn->nonce, "%08X-%04hX-%04hX-%04hX-%012" G_GINT64_MODIFIER "X", &t1, &t2, &t3, &t4, &t5);
56
57 t1 = GUINT32_TO_LE(t1);
58 t2 = GUINT16_TO_LE(t2);
59 t3 = GUINT16_TO_LE(t3);
60 t4 = GUINT16_TO_BE(t4);
61 t5 = GUINT64_TO_BE(t5);
62
63 slpmsg->ack_id = t1;
64 slpmsg->ack_sub_id = t2 | (t3 << 16);
65 slpmsg->ack_size = t4 | t5;
66 }
67
68 g_free(directconn->nonce);
69
70 msn_slplink_send_slpmsg(slplink, slpmsg);
71
72 directconn->acked =TRUE;
73 }
74
75 /**************************************************************************
76 * Connection Functions
77 **************************************************************************/
78
79 #if 0
80 static int
81 create_listener(int port)
82 {
83 int fd;
84 const int on = 1;
85
86 #if 0
87 struct addrinfo hints;
88 struct addrinfo *c, *res;
89 char port_str[5];
90
91 snprintf(port_str, sizeof(port_str), "%d", port);
92
93 memset(&hints, 0, sizeof(hints));
94
95 hints.ai_flags = AI_PASSIVE;
96 hints.ai_family = AF_UNSPEC;
97 hints.ai_socktype = SOCK_STREAM;
98
99 if (getaddrinfo(NULL, port_str, &hints, &res) != 0)
100 {
101 purple_debug_error("msn", "Could not get address info: %s.\n",
102 port_str);
103 return -1;
104 }
105
106 for (c = res; c != NULL; c = c->ai_next)
107 {
108 fd = socket(c->ai_family, c->ai_socktype, c->ai_protocol);
109
110 if (fd < 0)
111 continue;
112
113 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
114
115 if (bind(fd, c->ai_addr, c->ai_addrlen) == 0)
116 break;
117
118 close(fd);
119 }
120
121 if (c == NULL)
122 {
123 purple_debug_error("msn", "Could not find socket: %s.\n", port_str);
124 return -1;
125 }
126
127 freeaddrinfo(res);
128 #else
129 struct sockaddr_in sockin;
130
131 fd = socket(AF_INET, SOCK_STREAM, 0);
132
133 if (fd < 0)
134 return -1;
135
136 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0)
137 {
138 close(fd);
139 return -1;
140 }
141
142 memset(&sockin, 0, sizeof(struct sockaddr_in));
143 sockin.sin_family = AF_INET;
144 sockin.sin_port = htons(port);
145
146 if (bind(fd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0)
147 {
148 close(fd);
149 return -1;
150 }
151 #endif
152
153 if (listen (fd, 4) != 0)
154 {
155 close (fd);
156 return -1;
157 }
158
159 fcntl(fd, F_SETFL, O_NONBLOCK);
160
161 return fd;
162 }
163 #endif
164
165 static size_t
166 msn_directconn_write(MsnDirectConn *directconn,
167 const char *data, size_t len)
168 {
169 char *buffer, *tmp;
170 size_t buf_size;
171 size_t ret;
172 guint32 sent_len;
173
174 g_return_val_if_fail(directconn != NULL, 0);
175
176 buf_size = len + 4;
177 buffer = tmp = g_malloc(buf_size);
178
179 sent_len = GUINT32_TO_LE(len);
180
181 memcpy(tmp, &sent_len, 4);
182 tmp += 4;
183 memcpy(tmp, data, len);
184 tmp += len;
185
186 ret = write(directconn->fd, buffer, buf_size);
187
188 #ifdef DEBUG_DC
189 char *str;
190 str = g_strdup_printf("%s/msntest/w%.4d.bin", g_get_home_dir(), directconn->c);
191
192 FILE *tf = g_fopen(str, "w");
193 fwrite(buffer, 1, buf_size, tf);
194 fclose(tf);
195
196 g_free(str);
197 #endif
198
199 g_free(buffer);
200
201 #if 0
202 /* Let's write the length of the data. */
203 ret = write(directconn->fd, &len, sizeof(len));
204
205 /* Let's write the data. */
206 ret = write(directconn->fd, data, len);
207
208 char *str;
209 str = g_strdup_printf("/home/revo/msntest/w%.4d.bin", directconn->c);
210
211 FILE *tf = g_fopen(str, "w");
212 fwrite(&len, 1, sizeof(len), tf);
213 fwrite(data, 1, len, tf);
214 fclose(tf);
215
216 g_free(str);
217 #endif
218
219 directconn->c++;
220
221 return ret;
222 }
223
224 #if 0
225 void
226 msn_directconn_parse_nonce(MsnDirectConn *directconn, const char *nonce)
227 {
228 guint32 t1;
229 guint16 t2;
230 guint16 t3;
231 guint16 t4;
232 guint64 t5;
233
234 g_return_if_fail(directconn != NULL);
235 g_return_if_fail(nonce != NULL);
236
237 sscanf (nonce, "%08X-%04hX-%04hX-%04hX-%012llX", &t1, &t2, &t3, &t4, &t5);
238
239 t1 = GUINT32_TO_LE(t1);
240 t2 = GUINT16_TO_LE(t2);
241 t3 = GUINT16_TO_LE(t3);
242 t4 = GUINT16_TO_BE(t4);
243 t5 = GUINT64_TO_BE(t5);
244
245 directconn->slpheader = g_new0(MsnSlpHeader, 1);
246
247 directconn->slpheader->ack_id = t1;
248 directconn->slpheader->ack_sub_id = t2 | (t3 << 16);
249 directconn->slpheader->ack_size = t4 | t5;
250 }
251 #endif
252
253 void
254 msn_directconn_send_msg(MsnDirectConn *directconn, MsnMessage *msg)
255 {
256 char *body;
257 size_t body_len;
258
259 body = msn_message_gen_slp_body(msg, &body_len);
260
261 msn_directconn_write(directconn, body, body_len);
262 }
263
264 static void
265 msn_directconn_process_msg(MsnDirectConn *directconn, MsnMessage *msg)
266 {
267 purple_debug_info("msn", "directconn: process_msg\n");
268
269 msn_slplink_process_msg(directconn->slplink, msg);
270 }
271
272 static void
273 read_cb(gpointer data, gint source, PurpleInputCondition cond)
274 {
275 MsnDirectConn* directconn;
276 char *body;
277 size_t len, body_len;
278
279 purple_debug_info("msn", "read_cb: %d, %d\n", source, cond);
280
281 directconn = data;
282
283 /* Let's read the length of the data. */
284 len = read(directconn->fd, &body_len, sizeof(body_len));
285
286 if (len <= 0)
287 {
288 /* ERROR */
289 purple_debug_error("msn", "error reading\n");
290
291 msn_directconn_destroy(directconn);
292
293 return;
294 }
295
296 body_len = GUINT32_FROM_LE(body_len);
297
298 purple_debug_info("msn", "body_len=%d\n", body_len);
299
300 if (body_len <= 0)
301 {
302 /* ERROR */
303 purple_debug_error("msn", "error reading\n");
304
305 msn_directconn_destroy(directconn);
306
307 return;
308 }
309
310 body = g_try_malloc(body_len);
311
312 if (body != NULL)
313 {
314 /* Let's read the data. */
315 len = read(directconn->fd, body, body_len);
316
317 purple_debug_info("msn", "len=%d\n", len);
318 }
319 else
320 {
321 purple_debug_error("msn", "Failed to allocate memory for read\n");
322 len = 0;
323 }
324
325 if (len > 0)
326 {
327 MsnMessage *msg;
328
329 #ifdef DEBUG_DC
330 str = g_strdup_printf("/home/revo/msntest/r%.4d.bin", directconn->c);
331
332 FILE *tf = g_fopen(str, "w");
333 fwrite(body, 1, len, tf);
334 fclose(tf);
335
336 g_free(str);
337 #endif
338
339 directconn->c++;
340
341 msg = msn_message_new_msnslp();
342 msn_message_parse_slp_body(msg, body, body_len);
343
344 msn_directconn_process_msg(directconn, msg);
345 }
346 else
347 {
348 /* ERROR */
349 purple_debug_error("msn", "error reading\n");
350
351 msn_directconn_destroy(directconn);
352 }
353 }
354
355 static void
356 connect_cb(gpointer data, gint source, const gchar *error_message)
357 {
358 MsnDirectConn* directconn;
359 int fd;
360
361 purple_debug_misc("msn", "directconn: connect_cb: %d\n", source);
362
363 directconn = data;
364 directconn->connect_data = NULL;
365
366 if (TRUE)
367 {
368 fd = source;
369 }
370 else
371 {
372 struct sockaddr_in client_addr;
373 socklen_t client;
374 fd = accept (source, (struct sockaddr *)&client_addr, &client);
375 }
376
377 directconn->fd = fd;
378
379 if (fd > 0)
380 {
381 directconn->inpa = purple_input_add(fd, PURPLE_INPUT_READ, read_cb,
382 directconn);
383
384 if (TRUE)
385 {
386 /* Send foo. */
387 msn_directconn_write(directconn, "foo", strlen("foo") + 1);
388
389 /* Send Handshake */
390 msn_directconn_send_handshake(directconn);
391 }
392 else
393 {
394 }
395 }
396 else
397 {
398 /* ERROR */
399 purple_debug_error("msn", "could not add input\n");
400
401 if (directconn->inpa)
402 purple_input_remove(directconn->inpa);
403
404 close(directconn->fd);
405 }
406 }
407
408 gboolean
409 msn_directconn_connect(MsnDirectConn *directconn, const char *host, int port)
410 {
411 MsnSession *session;
412
413 g_return_val_if_fail(directconn != NULL, FALSE);
414 g_return_val_if_fail(host != NULL, TRUE);
415 g_return_val_if_fail(port > 0, FALSE);
416
417 session = directconn->slplink->session;
418
419 #if 0
420 if (session->http_method)
421 {
422 servconn->http_data->gateway_host = g_strdup(host);
423 }
424 #endif
425
426 directconn->connect_data = purple_proxy_connect(NULL, session->account,
427 host, port, connect_cb, directconn);
428
429 if (directconn->connect_data != NULL)
430 {
431 return TRUE;
432 }
433 else
434 return FALSE;
435 }
436
437 #if 0
438 void
439 msn_directconn_listen(MsnDirectConn *directconn)
440 {
441 int port;
442 int fd;
443
444 port = 7000;
445
446 for (fd = -1; fd < 0;)
447 fd = create_listener(++port);
448
449 directconn->fd = fd;
450
451 directconn->inpa = purple_input_add(fd, PURPLE_INPUT_READ, connect_cb,
452 directconn);
453
454 directconn->port = port;
455 directconn->c = 0;
456 }
457 #endif
458
459 MsnDirectConn*
460 msn_directconn_new(MsnSlpLink *slplink)
461 {
462 MsnDirectConn *directconn;
463
464 directconn = g_new0(MsnDirectConn, 1);
465
466 directconn->slplink = slplink;
467
468 if (slplink->directconn != NULL)
469 purple_debug_info("msn", "got_transresp: LEAK\n");
470
471 slplink->directconn = directconn;
472
473 return directconn;
474 }
475
476 void
477 msn_directconn_destroy(MsnDirectConn *directconn)
478 {
479 if (directconn->connect_data != NULL)
480 purple_proxy_connect_cancel(directconn->connect_data);
481
482 if (directconn->inpa != 0)
483 purple_input_remove(directconn->inpa);
484
485 if (directconn->fd >= 0)
486 close(directconn->fd);
487
488 if (directconn->nonce != NULL)
489 g_free(directconn->nonce);
490
491 directconn->slplink->directconn = NULL;
492
493 g_free(directconn);
494 }