| 1 /** |
|
| 2 * @file directconn.c MSN direct connection functions |
|
| 3 * |
|
| 4 * gaim |
|
| 5 * |
|
| 6 * Gaim 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 static int |
|
| 80 create_listener(int port) |
|
| 81 { |
|
| 82 int fd; |
|
| 83 const int on = 1; |
|
| 84 |
|
| 85 #if 0 |
|
| 86 struct addrinfo hints; |
|
| 87 struct addrinfo *c, *res; |
|
| 88 char port_str[5]; |
|
| 89 |
|
| 90 snprintf(port_str, sizeof(port_str), "%d", port); |
|
| 91 |
|
| 92 memset(&hints, 0, sizeof(hints)); |
|
| 93 |
|
| 94 hints.ai_flags = AI_PASSIVE; |
|
| 95 hints.ai_family = AF_UNSPEC; |
|
| 96 hints.ai_socktype = SOCK_STREAM; |
|
| 97 |
|
| 98 if (getaddrinfo(NULL, port_str, &hints, &res) != 0) |
|
| 99 { |
|
| 100 gaim_debug_error("msn", "Could not get address info: %s.\n", |
|
| 101 port_str); |
|
| 102 return -1; |
|
| 103 } |
|
| 104 |
|
| 105 for (c = res; c != NULL; c = c->ai_next) |
|
| 106 { |
|
| 107 fd = socket(c->ai_family, c->ai_socktype, c->ai_protocol); |
|
| 108 |
|
| 109 if (fd < 0) |
|
| 110 continue; |
|
| 111 |
|
| 112 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); |
|
| 113 |
|
| 114 if (bind(fd, c->ai_addr, c->ai_addrlen) == 0) |
|
| 115 break; |
|
| 116 |
|
| 117 close(fd); |
|
| 118 } |
|
| 119 |
|
| 120 if (c == NULL) |
|
| 121 { |
|
| 122 gaim_debug_error("msn", "Could not find socket: %s.\n", port_str); |
|
| 123 return -1; |
|
| 124 } |
|
| 125 |
|
| 126 freeaddrinfo(res); |
|
| 127 #else |
|
| 128 struct sockaddr_in sockin; |
|
| 129 |
|
| 130 fd = socket(AF_INET, SOCK_STREAM, 0); |
|
| 131 |
|
| 132 if (fd < 0) |
|
| 133 return -1; |
|
| 134 |
|
| 135 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0) |
|
| 136 { |
|
| 137 close(fd); |
|
| 138 return -1; |
|
| 139 } |
|
| 140 |
|
| 141 memset(&sockin, 0, sizeof(struct sockaddr_in)); |
|
| 142 sockin.sin_family = AF_INET; |
|
| 143 sockin.sin_port = htons(port); |
|
| 144 |
|
| 145 if (bind(fd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) |
|
| 146 { |
|
| 147 close(fd); |
|
| 148 return -1; |
|
| 149 } |
|
| 150 #endif |
|
| 151 |
|
| 152 if (listen (fd, 4) != 0) |
|
| 153 { |
|
| 154 close (fd); |
|
| 155 return -1; |
|
| 156 } |
|
| 157 |
|
| 158 fcntl(fd, F_SETFL, O_NONBLOCK); |
|
| 159 |
|
| 160 return fd; |
|
| 161 } |
|
| 162 |
|
| 163 static size_t |
|
| 164 msn_directconn_write(MsnDirectConn *directconn, |
|
| 165 const char *data, size_t len) |
|
| 166 { |
|
| 167 char *buffer, *tmp; |
|
| 168 size_t buf_size; |
|
| 169 size_t ret; |
|
| 170 guint32 sent_len; |
|
| 171 |
|
| 172 g_return_val_if_fail(directconn != NULL, 0); |
|
| 173 |
|
| 174 buf_size = len + 4; |
|
| 175 buffer = tmp = g_malloc(buf_size); |
|
| 176 |
|
| 177 sent_len = GUINT32_TO_LE(len); |
|
| 178 |
|
| 179 memcpy(tmp, &sent_len, 4); |
|
| 180 tmp += 4; |
|
| 181 memcpy(tmp, data, len); |
|
| 182 tmp += len; |
|
| 183 |
|
| 184 ret = write(directconn->fd, buffer, buf_size); |
|
| 185 |
|
| 186 #ifdef DEBUG_DC |
|
| 187 char *str; |
|
| 188 str = g_strdup_printf("%s/msntest/w%.4d.bin", g_get_home_dir(), directconn->c); |
|
| 189 |
|
| 190 FILE *tf = g_fopen(str, "w"); |
|
| 191 fwrite(buffer, 1, buf_size, tf); |
|
| 192 fclose(tf); |
|
| 193 |
|
| 194 g_free(str); |
|
| 195 #endif |
|
| 196 |
|
| 197 g_free(buffer); |
|
| 198 |
|
| 199 #if 0 |
|
| 200 /* Let's write the length of the data. */ |
|
| 201 ret = write(directconn->fd, &len, sizeof(len)); |
|
| 202 |
|
| 203 /* Let's write the data. */ |
|
| 204 ret = write(directconn->fd, data, len); |
|
| 205 |
|
| 206 char *str; |
|
| 207 str = g_strdup_printf("/home/revo/msntest/w%.4d.bin", directconn->c); |
|
| 208 |
|
| 209 FILE *tf = g_fopen(str, "w"); |
|
| 210 fwrite(&len, 1, sizeof(len), tf); |
|
| 211 fwrite(data, 1, len, tf); |
|
| 212 fclose(tf); |
|
| 213 |
|
| 214 g_free(str); |
|
| 215 #endif |
|
| 216 |
|
| 217 directconn->c++; |
|
| 218 |
|
| 219 return ret; |
|
| 220 } |
|
| 221 |
|
| 222 #if 0 |
|
| 223 void |
|
| 224 msn_directconn_parse_nonce(MsnDirectConn *directconn, const char *nonce) |
|
| 225 { |
|
| 226 guint32 t1; |
|
| 227 guint16 t2; |
|
| 228 guint16 t3; |
|
| 229 guint16 t4; |
|
| 230 guint64 t5; |
|
| 231 |
|
| 232 g_return_if_fail(directconn != NULL); |
|
| 233 g_return_if_fail(nonce != NULL); |
|
| 234 |
|
| 235 sscanf (nonce, "%08X-%04hX-%04hX-%04hX-%012llX", &t1, &t2, &t3, &t4, &t5); |
|
| 236 |
|
| 237 t1 = GUINT32_TO_LE(t1); |
|
| 238 t2 = GUINT16_TO_LE(t2); |
|
| 239 t3 = GUINT16_TO_LE(t3); |
|
| 240 t4 = GUINT16_TO_BE(t4); |
|
| 241 t5 = GUINT64_TO_BE(t5); |
|
| 242 |
|
| 243 directconn->slpheader = g_new0(MsnSlpHeader, 1); |
|
| 244 |
|
| 245 directconn->slpheader->ack_id = t1; |
|
| 246 directconn->slpheader->ack_sub_id = t2 | (t3 << 16); |
|
| 247 directconn->slpheader->ack_size = t4 | t5; |
|
| 248 } |
|
| 249 #endif |
|
| 250 |
|
| 251 void |
|
| 252 msn_directconn_send_msg(MsnDirectConn *directconn, MsnMessage *msg) |
|
| 253 { |
|
| 254 char *body; |
|
| 255 size_t body_len; |
|
| 256 |
|
| 257 body = msn_message_gen_slp_body(msg, &body_len); |
|
| 258 |
|
| 259 msn_directconn_write(directconn, body, body_len); |
|
| 260 } |
|
| 261 |
|
| 262 static void |
|
| 263 msn_directconn_process_msg(MsnDirectConn *directconn, MsnMessage *msg) |
|
| 264 { |
|
| 265 gaim_debug_info("msn", "directconn: process_msg\n"); |
|
| 266 |
|
| 267 msn_slplink_process_msg(directconn->slplink, msg); |
|
| 268 } |
|
| 269 |
|
| 270 static void |
|
| 271 read_cb(gpointer data, gint source, GaimInputCondition cond) |
|
| 272 { |
|
| 273 MsnDirectConn* directconn; |
|
| 274 char *body; |
|
| 275 size_t len, body_len; |
|
| 276 |
|
| 277 gaim_debug_info("msn", "read_cb: %d, %d\n", source, cond); |
|
| 278 |
|
| 279 directconn = data; |
|
| 280 |
|
| 281 /* Let's read the length of the data. */ |
|
| 282 len = read(directconn->fd, &body_len, sizeof(body_len)); |
|
| 283 |
|
| 284 if (len <= 0) |
|
| 285 { |
|
| 286 /* ERROR */ |
|
| 287 gaim_debug_error("msn", "error reading\n"); |
|
| 288 |
|
| 289 if (directconn->inpa) |
|
| 290 gaim_input_remove(directconn->inpa); |
|
| 291 |
|
| 292 close(directconn->fd); |
|
| 293 |
|
| 294 msn_directconn_destroy(directconn); |
|
| 295 |
|
| 296 return; |
|
| 297 } |
|
| 298 |
|
| 299 body_len = GUINT32_FROM_LE(body_len); |
|
| 300 |
|
| 301 gaim_debug_info("msn", "body_len=%d\n", body_len); |
|
| 302 |
|
| 303 if (body_len <= 0) |
|
| 304 { |
|
| 305 /* ERROR */ |
|
| 306 gaim_debug_error("msn", "error reading\n"); |
|
| 307 |
|
| 308 if (directconn->inpa) |
|
| 309 gaim_input_remove(directconn->inpa); |
|
| 310 |
|
| 311 close(directconn->fd); |
|
| 312 |
|
| 313 msn_directconn_destroy(directconn); |
|
| 314 |
|
| 315 return; |
|
| 316 } |
|
| 317 |
|
| 318 body = g_try_malloc(body_len); |
|
| 319 |
|
| 320 if (body != NULL) |
|
| 321 { |
|
| 322 /* Let's read the data. */ |
|
| 323 len = read(directconn->fd, body, body_len); |
|
| 324 |
|
| 325 gaim_debug_info("msn", "len=%d\n", len); |
|
| 326 } |
|
| 327 else |
|
| 328 { |
|
| 329 gaim_debug_error("msn", "Failed to allocate memory for read\n"); |
|
| 330 len = 0; |
|
| 331 } |
|
| 332 |
|
| 333 if (len > 0) |
|
| 334 { |
|
| 335 MsnMessage *msg; |
|
| 336 |
|
| 337 #ifdef DEBUG_DC |
|
| 338 str = g_strdup_printf("/home/revo/msntest/r%.4d.bin", directconn->c); |
|
| 339 |
|
| 340 FILE *tf = g_fopen(str, "w"); |
|
| 341 fwrite(body, 1, len, tf); |
|
| 342 fclose(tf); |
|
| 343 |
|
| 344 g_free(str); |
|
| 345 #endif |
|
| 346 |
|
| 347 directconn->c++; |
|
| 348 |
|
| 349 msg = msn_message_new_msnslp(); |
|
| 350 msn_message_parse_slp_body(msg, body, body_len); |
|
| 351 |
|
| 352 msn_directconn_process_msg(directconn, msg); |
|
| 353 } |
|
| 354 else |
|
| 355 { |
|
| 356 /* ERROR */ |
|
| 357 gaim_debug_error("msn", "error reading\n"); |
|
| 358 |
|
| 359 if (directconn->inpa) |
|
| 360 gaim_input_remove(directconn->inpa); |
|
| 361 |
|
| 362 close(directconn->fd); |
|
| 363 |
|
| 364 msn_directconn_destroy(directconn); |
|
| 365 } |
|
| 366 } |
|
| 367 |
|
| 368 static void |
|
| 369 connect_cb(gpointer data, gint source, GaimInputCondition cond) |
|
| 370 { |
|
| 371 MsnDirectConn* directconn; |
|
| 372 int fd; |
|
| 373 |
|
| 374 gaim_debug_misc("msn", "directconn: connect_cb: %d, %d.\n", source, cond); |
|
| 375 |
|
| 376 directconn = data; |
|
| 377 |
|
| 378 if (TRUE) |
|
| 379 { |
|
| 380 fd = source; |
|
| 381 } |
|
| 382 else |
|
| 383 { |
|
| 384 struct sockaddr_in client_addr; |
|
| 385 unsigned int client; |
|
| 386 fd = accept (source, (struct sockaddr *)&client_addr, &client); |
|
| 387 } |
|
| 388 |
|
| 389 directconn->fd = fd; |
|
| 390 |
|
| 391 if (fd > 0) |
|
| 392 { |
|
| 393 directconn->inpa = gaim_input_add(fd, GAIM_INPUT_READ, read_cb, |
|
| 394 directconn); |
|
| 395 |
|
| 396 if (TRUE) |
|
| 397 { |
|
| 398 /* Send foo. */ |
|
| 399 msn_directconn_write(directconn, "foo", strlen("foo") + 1); |
|
| 400 |
|
| 401 /* Send Handshake */ |
|
| 402 msn_directconn_send_handshake(directconn); |
|
| 403 } |
|
| 404 else |
|
| 405 { |
|
| 406 } |
|
| 407 } |
|
| 408 else |
|
| 409 { |
|
| 410 /* ERROR */ |
|
| 411 gaim_debug_error("msn", "could not add input\n"); |
|
| 412 |
|
| 413 if (directconn->inpa) |
|
| 414 gaim_input_remove(directconn->inpa); |
|
| 415 |
|
| 416 close(directconn->fd); |
|
| 417 } |
|
| 418 } |
|
| 419 |
|
| 420 gboolean |
|
| 421 msn_directconn_connect(MsnDirectConn *directconn, const char *host, int port) |
|
| 422 { |
|
| 423 MsnSession *session; |
|
| 424 int r; |
|
| 425 |
|
| 426 g_return_val_if_fail(directconn != NULL, FALSE); |
|
| 427 g_return_val_if_fail(host != NULL, TRUE); |
|
| 428 g_return_val_if_fail(port > 0, FALSE); |
|
| 429 |
|
| 430 session = directconn->slplink->session; |
|
| 431 |
|
| 432 #if 0 |
|
| 433 if (session->http_method) |
|
| 434 { |
|
| 435 servconn->http_data->gateway_host = g_strdup(host); |
|
| 436 } |
|
| 437 #endif |
|
| 438 |
|
| 439 r = gaim_proxy_connect(session->account, host, port, connect_cb, |
|
| 440 directconn); |
|
| 441 |
|
| 442 if (r == 0) |
|
| 443 { |
|
| 444 return TRUE; |
|
| 445 } |
|
| 446 else |
|
| 447 return FALSE; |
|
| 448 } |
|
| 449 |
|
| 450 void |
|
| 451 msn_directconn_listen(MsnDirectConn *directconn) |
|
| 452 { |
|
| 453 int port; |
|
| 454 int fd; |
|
| 455 |
|
| 456 port = 7000; |
|
| 457 |
|
| 458 for (fd = -1; fd < 0;) |
|
| 459 fd = create_listener(++port); |
|
| 460 |
|
| 461 directconn->fd = fd; |
|
| 462 |
|
| 463 directconn->inpa = gaim_input_add(fd, GAIM_INPUT_READ, |
|
| 464 connect_cb, directconn); |
|
| 465 |
|
| 466 directconn->port = port; |
|
| 467 directconn->c = 0; |
|
| 468 } |
|
| 469 |
|
| 470 MsnDirectConn* |
|
| 471 msn_directconn_new(MsnSlpLink *slplink) |
|
| 472 { |
|
| 473 MsnDirectConn *directconn; |
|
| 474 |
|
| 475 directconn = g_new0(MsnDirectConn, 1); |
|
| 476 |
|
| 477 directconn->slplink = slplink; |
|
| 478 |
|
| 479 if (slplink->directconn != NULL) |
|
| 480 gaim_debug_info("msn", "got_transresp: LEAK\n"); |
|
| 481 |
|
| 482 slplink->directconn = directconn; |
|
| 483 |
|
| 484 return directconn; |
|
| 485 } |
|
| 486 |
|
| 487 void |
|
| 488 msn_directconn_destroy(MsnDirectConn *directconn) |
|
| 489 { |
|
| 490 if (directconn->nonce != NULL) |
|
| 491 g_free(directconn->nonce); |
|
| 492 |
|
| 493 directconn->slplink->directconn = NULL; |
|
| 494 |
|
| 495 g_free(directconn); |
|
| 496 } |
|