/loudmouth/lm-old-socket.c
C | 1064 lines | 791 code | 209 blank | 64 comment | 116 complexity | e3e3c30e6bdadb607f9401498fe882b4 MD5 | raw file
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2/* 3 * Copyright (C) 2006-2008 Imendio AB 4 * Copyright (C) 2006 Nokia Corporation. All rights reserved. 5 * Copyright (C) 2007 Collabora Ltd. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public License as 9 * published by the Free Software Foundation; either version 2 of the 10 * License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this program; if not, see <https://www.gnu.org/licenses> 19 */ 20 21#include <config.h> 22 23#include <string.h> 24#include <sys/types.h> 25 26/* Needed on Mac OS X */ 27#if HAVE_NETINET_IN_H 28#include <netinet/in.h> 29#endif 30 31/* Needed on Mac OS X */ 32#if HAVE_ARPA_NAMESER_COMPAT_H 33#include <arpa/nameser_compat.h> 34#endif 35 36#include <arpa/inet.h> 37#include <arpa/nameser.h> 38#include <resolv.h> 39 40#include "lm-debug.h" 41#include "lm-error.h" 42#include "lm-internals.h" 43#include "lm-misc.h" 44#include "lm-proxy.h" 45#include "lm-resolver.h" 46#include "lm-ssl.h" 47#include "lm-ssl-internals.h" 48#include "lm-sock.h" 49#include "lm-old-socket.h" 50 51#define IN_BUFFER_SIZE 1024 52#define SRV_LEN 8192 53 54struct _LmOldSocket { 55 LmConnection *connection; 56 GMainContext *context; 57 58 gchar *domain; 59 gchar *server; 60 guint port; 61 62 LmSSL *ssl; 63 gboolean ssl_started; 64 LmProxy *proxy; 65 66 GIOChannel *io_channel; 67 GSource *watch_in; 68 GSource *watch_err; 69 GSource *watch_hup; 70 71 LmOldSocketT fd; 72 73 GSource *watch_connect; 74 75 gboolean cancel_open; 76 77 GSource *watch_out; 78 GString *out_buf; 79 80 LmConnectData *connect_data; 81 82 IncomingDataFunc data_func; 83 SocketClosedFunc closed_func; 84 ConnectResultFunc connect_func; 85 gpointer user_data; 86 87 guint ref_count; 88 89 LmResolver *resolver; 90}; 91 92static void socket_free (LmOldSocket *socket); 93static gboolean socket_do_connect (LmConnectData *connect_data); 94static gboolean socket_connect_cb (GIOChannel *source, 95 GIOCondition condition, 96 LmConnectData *connect_data); 97static gboolean socket_in_event (GIOChannel *source, 98 GIOCondition condition, 99 LmOldSocket *socket); 100static gboolean socket_hup_event (GIOChannel *source, 101 GIOCondition condition, 102 LmOldSocket *socket); 103static gboolean socket_error_event (GIOChannel *source, 104 GIOCondition condition, 105 LmOldSocket *socket); 106static gboolean socket_buffered_write_cb (GIOChannel *source, 107 GIOCondition condition, 108 LmOldSocket *socket); 109static void socket_close_io_channel (GIOChannel *io_channel); 110static gboolean old_socket_output_is_buffered (LmOldSocket *socket, 111 const gchar *buffer, 112 gint len); 113static void old_socket_setup_output_buffer (LmOldSocket *socket, 114 const gchar *buffer, 115 gint len); 116 117static void 118socket_free (LmOldSocket *socket) 119{ 120 g_free (socket->server); 121 g_free (socket->domain); 122 123 if (socket->ssl) { 124 lm_ssl_unref (socket->ssl); 125 } 126 127 if (socket->proxy) { 128 lm_proxy_unref (socket->proxy); 129 } 130 131 if (socket->out_buf) { 132 g_string_free (socket->out_buf, TRUE); 133 } 134 135 if (socket->resolver) { 136 g_object_unref (socket->resolver); 137 } 138 139 g_free (socket); 140} 141 142static gint 143old_socket_do_write (LmOldSocket *socket, const gchar *buf, guint len) 144{ 145 gint b_written; 146 147 if (socket->ssl_started) { 148 b_written = _lm_ssl_send (socket->ssl, buf, len); 149 } else { 150 GIOStatus io_status = G_IO_STATUS_AGAIN; 151 gsize bytes_written; 152 153 while (io_status == G_IO_STATUS_AGAIN) { 154 io_status = g_io_channel_write_chars (socket->io_channel, 155 buf, len, 156 &bytes_written, 157 NULL); 158 } 159 160 b_written = bytes_written; 161 162 if (io_status != G_IO_STATUS_NORMAL) { 163 b_written = -1; 164 } 165 } 166 167 return b_written; 168} 169 170gint 171lm_old_socket_write (LmOldSocket *socket, const gchar *buf, gint len) 172{ 173 gint b_written; 174 175 if (old_socket_output_is_buffered (socket, buf, len)) { 176 return len; 177 } 178 179 b_written = old_socket_do_write (socket, buf, len); 180 181 if (b_written < len && b_written != -1) { 182 old_socket_setup_output_buffer (socket, 183 buf + b_written, 184 len - b_written); 185 return len; 186 } 187 188 return b_written; 189} 190 191static gboolean 192socket_read_incoming (LmOldSocket *socket, 193 gchar *buf, 194 gsize buf_size, 195 gsize *bytes_read, 196 gboolean *hangup, 197 gint *reason) 198{ 199 GIOStatus status; 200 201 *hangup = FALSE; 202 203 if (socket->ssl_started) { 204 status = _lm_ssl_read (socket->ssl, 205 buf, buf_size - 1, bytes_read); 206 } else { 207 status = g_io_channel_read_chars (socket->io_channel, 208 buf, buf_size - 1, 209 bytes_read, 210 NULL); 211 } 212 213 if (status != G_IO_STATUS_NORMAL) { 214 switch (status) { 215 case G_IO_STATUS_EOF: 216 *reason = LM_DISCONNECT_REASON_HUP; 217 break; 218 case G_IO_STATUS_AGAIN: 219 /* No data readable but we didn't hangup */ 220 return FALSE; 221 break; 222 case G_IO_STATUS_ERROR: 223 *reason = LM_DISCONNECT_REASON_ERROR; 224 break; 225 default: 226 *reason = LM_DISCONNECT_REASON_UNKNOWN; 227 } 228 229 /* Notify connection_in_event that we hangup the connection */ 230 *hangup = TRUE; 231 232 return FALSE; 233 } 234 235 buf[*bytes_read] = '\0'; 236 237 /* There is more data to be read */ 238 return TRUE; 239} 240 241static gboolean 242socket_in_event (GIOChannel *source, 243 GIOCondition condition, 244 LmOldSocket *socket) 245{ 246 gchar buf[IN_BUFFER_SIZE]; 247 gsize bytes_read = 0; 248 gboolean read_anything = FALSE; 249 gboolean hangup = 0; 250 gint reason = 0; 251 252 if (!socket->io_channel) { 253 return FALSE; 254 } 255 256 while (socket_read_incoming (socket, buf, IN_BUFFER_SIZE, 257 &bytes_read, &hangup, &reason)) { 258 259 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, "\nRECV [%d]:\n", 260 (int)bytes_read); 261 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, 262 "-----------------------------------\n"); 263 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, "'%s'\n", buf); 264 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, 265 "-----------------------------------\n"); 266 267 lm_verbose ("Read: %d chars\n", (int)bytes_read); 268 269 (socket->data_func) (socket, buf, socket->user_data); 270 271 read_anything = TRUE; 272 } 273 274 /* If we have read something, delay the hangup so that the data can be 275 * processed. */ 276 if (hangup && !read_anything) { 277 (socket->closed_func) (socket, reason, socket->user_data); 278 return FALSE; 279 } 280 281 return TRUE; 282} 283 284static gboolean 285socket_hup_event (GIOChannel *source, 286 GIOCondition condition, 287 LmOldSocket *socket) 288{ 289 lm_verbose ("HUP event: %d->'%s'\n", 290 condition, lm_misc_io_condition_to_str (condition)); 291 292 if (!socket->io_channel) { 293 return FALSE; 294 } 295 296 (socket->closed_func) (socket, LM_DISCONNECT_REASON_HUP, 297 socket->user_data); 298 299 return TRUE; 300} 301 302static gboolean 303socket_error_event (GIOChannel *source, 304 GIOCondition condition, 305 LmOldSocket *socket) 306{ 307 lm_verbose ("ERROR event: %d->'%s'\n", 308 condition, lm_misc_io_condition_to_str (condition)); 309 310 if (!socket->io_channel) { 311 return FALSE; 312 } 313 314 (socket->closed_func) (socket, LM_DISCONNECT_REASON_ERROR, 315 socket->user_data); 316 317 return TRUE; 318} 319 320static gboolean 321_lm_old_socket_ssl_init (LmOldSocket *socket, gboolean delayed) 322{ 323 GError *error = NULL; 324 const gchar *ssl_verify_domain = NULL; 325 326 lm_verbose ("Setting up SSL...\n"); 327 328 _lm_ssl_initialize (socket->ssl); 329 330#ifdef HAVE_GNUTLS 331 /* GNU TLS requires the socket to be blocking */ 332 _lm_sock_set_blocking (socket->fd, TRUE); 333#endif 334 335 /* If we're using StartTLS, the correct thing is to verify against 336 * the domain. If we're using old SSL, we should verify against the 337 * hostname. */ 338 if (delayed) 339 ssl_verify_domain = socket->domain; 340 else 341 ssl_verify_domain = socket->server; 342 343 if (!_lm_ssl_begin (socket->ssl, socket->fd, ssl_verify_domain, &error)) { 344 lm_verbose ("Could not begin SSL\n"); 345 346 if (error) { 347 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, 348 "%s\n", error->message); 349 g_error_free (error); 350 } 351 352 _lm_sock_shutdown (socket->fd); 353 _lm_sock_close (socket->fd); 354 355 if (!delayed && socket->connect_func) { 356 (socket->connect_func) (socket, FALSE, socket->user_data); 357 } 358 359 return FALSE; 360 } 361 362#ifdef HAVE_GNUTLS 363 _lm_sock_set_blocking (socket->fd, FALSE); 364#endif 365 366 socket->ssl_started = TRUE; 367 368 return TRUE; 369} 370 371gboolean 372lm_old_socket_starttls (LmOldSocket *socket) 373{ 374 g_return_val_if_fail (lm_ssl_get_use_starttls (socket->ssl) == TRUE, FALSE); 375 376 return _lm_old_socket_ssl_init (socket, TRUE); 377} 378 379 380 381void 382_lm_old_socket_succeeded (LmConnectData *connect_data) 383{ 384 LmOldSocket *socket; 385 386 socket = connect_data->socket; 387 388 if (socket->watch_connect) { 389 g_source_destroy (socket->watch_connect); 390 socket->watch_connect = NULL; 391 } 392 393 /* Need some way to report error/success */ 394 if (socket->cancel_open) { 395 lm_verbose ("Cancelling connection...\n"); 396 if (socket->connect_func) { 397 (socket->connect_func) (socket, FALSE, socket->user_data); 398 } 399 return; 400 } 401 402 socket->fd = connect_data->fd; 403 socket->io_channel = connect_data->io_channel; 404 405 g_object_unref (socket->resolver); 406 socket->resolver = NULL; 407 408 socket->connect_data = NULL; 409 g_free (connect_data); 410 411 /* old-style ssl should be started immediately */ 412 if (socket->ssl && (lm_ssl_get_use_starttls (socket->ssl) == FALSE)) { 413 if (!_lm_old_socket_ssl_init (socket, FALSE)) { 414 return; 415 } 416 } 417 418 socket->watch_in = 419 lm_misc_add_io_watch (socket->context, 420 socket->io_channel, 421 G_IO_IN, 422 (GIOFunc) socket_in_event, 423 socket); 424 425 /* FIXME: if we add these, we don't get ANY 426 * response from the server, this is to do with the way that 427 * windows handles watches, see bug #331214. 428 */ 429#ifndef G_OS_WIN32 430 socket->watch_err = 431 lm_misc_add_io_watch (socket->context, 432 socket->io_channel, 433 G_IO_ERR, 434 (GIOFunc) socket_error_event, 435 socket); 436 437 socket->watch_hup = 438 lm_misc_add_io_watch (socket->context, 439 socket->io_channel, 440 G_IO_HUP, 441 (GIOFunc) socket_hup_event, 442 socket); 443#endif 444 445 if (socket->connect_func) { 446 (socket->connect_func) (socket, TRUE, socket->user_data); 447 } 448} 449 450gboolean 451_lm_old_socket_failed_with_error (LmConnectData *connect_data, int error) 452{ 453 LmOldSocket *socket; 454 455 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, 456 "Connection failed: %s (error %d)\n", 457 _lm_sock_get_error_str (error), error); 458 459 socket = lm_old_socket_ref (connect_data->socket); 460 461 connect_data->current_addr = lm_resolver_results_get_next (socket->resolver); 462 463 if (socket->watch_connect) { 464 g_source_destroy (socket->watch_connect); 465 socket->watch_connect = NULL; 466 } 467 468 if (connect_data->io_channel != NULL) { 469 socket_close_io_channel (connect_data->io_channel); 470 connect_data->io_channel = NULL; 471 } 472 473 if (connect_data->current_addr == NULL) { /*Ran Out Of Addresses*/ 474 if (socket->connect_func) { 475 (socket->connect_func) (socket, FALSE, socket->user_data); 476 } 477 478 /* if the user callback called connection_close(), this is already freed */ 479 if (socket->connect_data != NULL) { 480 if (socket->resolver) { 481 g_object_unref (socket->resolver); 482 } 483 484 socket->connect_data = NULL; 485 g_free (connect_data); 486 } 487 } else { 488 /* try to connect to the next host */ 489 return socket_do_connect (connect_data); 490 } 491 492 lm_old_socket_unref (socket); 493 494 return FALSE; 495} 496 497gboolean 498_lm_old_socket_failed (LmConnectData *connect_data) 499{ 500 return _lm_old_socket_failed_with_error (connect_data, 501 _lm_sock_get_last_error()); 502} 503 504static gboolean 505socket_connect_cb (GIOChannel *source, 506 GIOCondition condition, 507 LmConnectData *connect_data) 508{ 509 LmOldSocket *socket; 510 /* struct addrinfo *addr; */ 511 int err; 512 socklen_t len; 513 LmOldSocketT fd; 514 gboolean result = FALSE; 515 516 socket = lm_old_socket_ref (connect_data->socket); 517 /* addr = connect_data->current_addr; */ 518 fd = g_io_channel_unix_get_fd (source); 519 520 if (condition == G_IO_ERR) { 521 len = sizeof (err); 522 _lm_sock_get_error (fd, &err, &len); 523 if (!_lm_sock_is_blocking_error (err)) { 524 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE, 525 "Connection failed.\n"); 526 527 /* error condition, but might be possible to recover 528 * from it (by connecting to the next host) */ 529 if (!_lm_old_socket_failed_with_error (connect_data, err)) { 530 socket->watch_connect = NULL; 531 goto out; 532 } 533 } 534 } 535 536#if 0 537 if (_lm_connection_async_connect_waiting (socket->connection)) { 538 gint res; 539 540 fd = g_io_channel_unix_get_fd (source); 541 542 res = _lm_sock_connect (fd, addr->ai_addr, (int)addr->ai_addrlen); 543 if (res < 0) { 544 err = _lm_sock_get_last_error (); 545 if (_lm_sock_is_blocking_success (err)) { 546 _lm_connection_set_async_connect_waiting (socket->connection, FALSE); 547 548 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, 549 "Connection success (1).\n"); 550 551 _lm_old_socket_succeeded (connect_data); 552 } 553 554 if (_lm_connection_async_connect_waiting (socket->connection) && 555 !_lm_sock_is_blocking_error (err)) { 556 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, 557 "Connection failed.\n"); 558 559 _lm_sock_close (connect_data->fd); 560 _lm_old_socket_failed_with_error (connect_data, err); 561 562 socket->watch_connect = NULL; 563 goto out; 564 } 565 } 566 } else { 567#endif 568 { 569 /* for blocking sockets, G_IO_OUT means we are connected */ 570 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE, 571 "Connection success (2).\n"); 572 573 _lm_old_socket_succeeded (connect_data); 574 } 575 576 result = TRUE; 577 578 out: 579 lm_old_socket_unref(socket); 580 581 return result; 582} 583 584static gboolean 585socket_do_connect (LmConnectData *connect_data) 586{ 587 LmOldSocket *socket; 588 LmOldSocketT fd; 589 int res, err; 590 int port; 591 char name[NI_MAXHOST]; 592 char portname[NI_MAXSERV]; 593 struct addrinfo *addr; 594 595 socket = connect_data->socket; 596 addr = connect_data->current_addr; 597 598 if (socket->port == 0) { 599 socket->port = 5222; 600 } 601 602 if (socket->proxy) { 603 port = htons (lm_proxy_get_port (socket->proxy)); 604 } else { 605 port = htons (socket->port); 606 } 607 608 ((struct sockaddr_in *) addr->ai_addr)->sin_port = port; 609 610 res = getnameinfo (addr->ai_addr, 611 (socklen_t)addr->ai_addrlen, 612 name, sizeof (name), 613 portname, sizeof (portname), 614 NI_NUMERICHOST | NI_NUMERICSERV); 615 616 if (res < 0) { 617 return _lm_old_socket_failed (connect_data); 618 } 619 620 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, 621 "Trying %s port %s...\n", name, portname); 622 623 fd = _lm_sock_makesocket (addr->ai_family, 624 addr->ai_socktype, 625 addr->ai_protocol); 626 627 if (!_LM_SOCK_VALID (fd)) { 628 g_print("invalid fd\n"); 629 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, 630 "Failed making socket, error:%d...\n", 631 _lm_sock_get_last_error ()); 632 633 return _lm_old_socket_failed (connect_data); 634 } 635 636 /* Even though it says _unix_new(), it is supported by glib on 637 * win32 because glib does some cool stuff to find out if it 638 * can treat it as a FD or a windows SOCKET. 639 */ 640 connect_data->fd = fd; 641 connect_data->io_channel = g_io_channel_unix_new (fd); 642 643 g_io_channel_set_encoding (connect_data->io_channel, NULL, NULL); 644 g_io_channel_set_buffered (connect_data->io_channel, FALSE); 645 646 _lm_sock_set_blocking (connect_data->fd, FALSE); 647 648 if (socket->proxy) { 649 socket->watch_connect = 650 lm_misc_add_io_watch (socket->context, 651 connect_data->io_channel, 652 G_IO_OUT|G_IO_ERR, 653 (GIOFunc) _lm_proxy_connect_cb, 654 connect_data); 655 } else { 656 socket->watch_connect = 657 lm_misc_add_io_watch (socket->context, 658 connect_data->io_channel, 659 G_IO_OUT|G_IO_ERR, 660 (GIOFunc) socket_connect_cb, 661 connect_data); 662 } 663 664 res = _lm_sock_connect (connect_data->fd, 665 addr->ai_addr, (int)addr->ai_addrlen); 666 if (res < 0) { 667 err = _lm_sock_get_last_error (); 668 if (!_lm_sock_is_blocking_error (err)) { 669 _lm_sock_close (connect_data->fd); 670 g_print("unable to connect\n"); 671 return _lm_old_socket_failed_with_error (connect_data, err); 672 } 673 } 674 675 return TRUE; 676} 677 678static gboolean 679old_socket_output_is_buffered (LmOldSocket *socket, 680 const gchar *buffer, 681 gint len) 682{ 683 if (socket->out_buf) { 684 lm_verbose ("Appending %d bytes to output buffer\n", len); 685 g_string_append_len (socket->out_buf, buffer, len); 686 return TRUE; 687 } 688 689 return FALSE; 690} 691 692static void 693old_socket_setup_output_buffer (LmOldSocket *socket, const gchar *buffer, gint len) 694{ 695 lm_verbose ("OUTPUT BUFFER ENABLED\n"); 696 697 socket->out_buf = g_string_new_len (buffer, len); 698 699 socket->watch_out = 700 lm_misc_add_io_watch (socket->context, 701 socket->io_channel, 702 G_IO_OUT, 703 (GIOFunc) socket_buffered_write_cb, 704 socket); 705} 706 707static gboolean 708socket_buffered_write_cb (GIOChannel *source, 709 GIOCondition condition, 710 LmOldSocket *socket) 711{ 712 gint b_written; 713 GString *out_buf; 714 715 out_buf = socket->out_buf; 716 if (!out_buf) { 717 /* Should not be possible */ 718 return FALSE; 719 } 720 721 b_written = old_socket_do_write (socket, out_buf->str, out_buf->len); 722 723 if (b_written < 0) { 724 (socket->closed_func) (socket, LM_DISCONNECT_REASON_ERROR, 725 socket->user_data); 726 return FALSE; 727 } 728 729 g_string_erase (out_buf, 0, (gsize) b_written); 730 if (out_buf->len == 0) { 731 lm_verbose ("Output buffer is empty, going back to normal output\n"); 732 733 if (socket->watch_out) { 734 g_source_destroy (socket->watch_out); 735 socket->watch_out = NULL; 736 } 737 738 g_string_free (out_buf, TRUE); 739 socket->out_buf = NULL; 740 return FALSE; 741 } 742 743 return TRUE; 744} 745 746static void 747socket_close_io_channel (GIOChannel *io_channel) 748{ 749 gint fd; 750 751 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, 752 "Freeing up IOChannel and file descriptor\n"); 753 754 fd = g_io_channel_unix_get_fd (io_channel); 755 756 g_io_channel_unref (io_channel); 757 758 _lm_sock_close (fd); 759} 760 761static void 762old_socket_resolver_host_cb (LmResolver *resolver, 763 LmResolverResult result, 764 gpointer user_data) 765{ 766 LmOldSocket *socket = (LmOldSocket *) user_data; 767 char dispbuf[128]; 768 struct sockaddr_in *addr; /* FIXME:IPv6 */ 769 const char *converr; 770 771 lm_verbose ("LmOldSocket::host_cb (result=%d)\n", result); 772 773 if (result != LM_RESOLVER_RESULT_OK) { 774 lm_verbose ("error while resolving, bailing out\n"); 775 if (socket->connect_func) { 776 (socket->connect_func) (socket, FALSE, socket->user_data); 777 } 778 /*FIXME: Leaking Resolvers Until Clean Up Can Be Properly Handled 779 g_object_unref (socket->resolver); 780 socket->resolver = NULL;*/ 781 g_free (socket->connect_data); 782 socket->connect_data = NULL; 783 784 return; 785 } 786 787 socket->connect_data->current_addr = 788 lm_resolver_results_get_next (resolver); 789 790 if (socket->connect_data->current_addr) { /* FIXME:IPv6 */ 791 addr = (struct sockaddr_in *) (socket->connect_data->current_addr->ai_addr); 792 converr = inet_ntop(AF_INET,&(addr->sin_addr),dispbuf,sizeof(dispbuf)); 793 if (converr) { 794 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE, 795 "Attempting Connection to %s\n",dispbuf); 796 } else { 797 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE, 798 "Attempting Connection (unable to convert address to presentable format)\n"); 799 }; 800 socket_do_connect (socket->connect_data); 801 } else { /* FIXME: IPv6 Support? */ 802 g_log (LM_LOG_DOMAIN,G_LOG_LEVEL_ERROR, 803 "Unable to locate server available over IPv4.\n"); 804 }; 805 806 /* FIXME: What do we do here? How to make the mainloop exit with an 807 error, while having no ref to said mainloop */ 808} 809 810/* FIXME: Need to have a way to only get srv reply and then decide if the 811 * resolver should continue to look the host up. 812 * 813 * This is needed for the case when we do a SRV lookup to lookup the 814 * real host of the service and then connect to it through a proxy. 815 */ 816static void 817old_socket_resolver_srv_cb (LmResolver *resolver, 818 LmResolverResult result, 819 gpointer user_data) 820{ 821 LmOldSocket *socket = (LmOldSocket *) user_data; 822 const gchar *remote_addr; 823 824 lm_verbose ("LmOldSocket::srv_cb (result=%d)\n", result); 825 826 if (result != LM_RESOLVER_RESULT_OK) { 827 lm_verbose ("SRV lookup failed, trying jid domain\n"); 828 socket->server = g_strdup (socket->domain); 829 } else { 830 g_object_get (resolver, "host", &socket->server, NULL); 831 g_object_get (resolver, "port", &socket->port, NULL); 832 } 833 834 if (socket->proxy) { 835 remote_addr = lm_proxy_get_server (socket->proxy); 836 } else if (socket->server) { 837 remote_addr = socket->server; 838 } 839 else { 840 remote_addr = socket->domain; 841 } 842 843 g_object_unref (socket->resolver); 844 845 socket->resolver = 846 lm_resolver_new_for_host (remote_addr, 847 old_socket_resolver_host_cb, 848 socket); 849 850 lm_resolver_lookup (socket->resolver); 851} 852 853LmOldSocket * 854lm_old_socket_create (GMainContext *context, 855 IncomingDataFunc data_func, 856 SocketClosedFunc closed_func, 857 ConnectResultFunc connect_func, 858 gpointer user_data, 859 LmConnection *connection, 860 const gchar *server, 861 const gchar *domain, 862 guint port, 863 LmSSL *ssl, 864 LmProxy *proxy, 865 GError **error) 866{ 867 LmOldSocket *socket; 868 LmConnectData *data; 869 870 g_return_val_if_fail (domain != NULL, NULL); 871 g_return_val_if_fail ((port >= LM_MIN_PORT && port <= LM_MAX_PORT), NULL); 872 g_return_val_if_fail (data_func != NULL, NULL); 873 g_return_val_if_fail (closed_func != NULL, NULL); 874 g_return_val_if_fail (connect_func != NULL, NULL); 875 876 socket = g_new0 (LmOldSocket, 1); 877 878 socket->ref_count = 1; 879 880 socket->connection = connection; 881 socket->domain = g_strdup (domain); 882 socket->server = g_strdup (server); 883 socket->port = port; 884 socket->cancel_open = FALSE; 885 socket->ssl = ssl; 886 socket->ssl_started = FALSE; 887 socket->proxy = NULL; 888 889 if (context) { 890 socket->context = g_main_context_ref (context); 891 } 892 893 if (proxy) { 894 socket->proxy = lm_proxy_ref (proxy); 895 } 896 897 data = g_new0 (LmConnectData, 1); 898 data->socket = socket; 899 data->connection = socket->connection; 900 data->fd = -1; 901 socket->connect_data = data; 902 903 if (!server) { 904 socket->resolver = lm_resolver_new_for_service (socket->domain, 905 "xmpp-client", 906 "tcp", 907 old_socket_resolver_srv_cb, 908 socket); 909 } else { 910 socket->resolver = 911 lm_resolver_new_for_host (socket->server ? socket->server : socket->domain, 912 old_socket_resolver_host_cb, 913 socket); 914 } 915 916 if (socket->context) { 917 g_object_set (socket->resolver, "context", context, NULL); 918 } 919 920 socket->data_func = data_func; 921 socket->closed_func = closed_func; 922 socket->connect_func = connect_func; 923 socket->user_data = user_data; 924 925 lm_resolver_lookup (socket->resolver); 926 927 return socket; 928} 929 930void 931lm_old_socket_flush (LmOldSocket *socket) 932{ 933 g_return_if_fail (socket != NULL); 934 g_return_if_fail (socket->io_channel != NULL); 935 936 g_io_channel_flush (socket->io_channel, NULL); 937} 938 939void 940lm_old_socket_close (LmOldSocket *socket) 941{ 942 LmConnectData *data; 943 944 g_return_if_fail (socket != NULL); 945 946 if (socket->watch_connect) { 947 g_source_destroy (socket->watch_connect); 948 socket->watch_connect = NULL; 949 } 950 951 data = socket->connect_data; 952 if (data) { 953 if (data->io_channel) { 954 socket_close_io_channel (data->io_channel); 955 } 956 socket->connect_data = NULL; 957 g_free (data); 958 } 959 960 /* FIXME: Leaking Resolvers Until Clean Up Can Be Corrected 961 if (socket->resolver) { 962 g_object_unref (socket->resolver); 963 socket->resolver = NULL; 964 } */ 965 966 if (socket->io_channel) { 967 if (socket->watch_in) { 968 g_source_destroy (socket->watch_in); 969 socket->watch_in = NULL; 970 } 971 972 if (socket->watch_err) { 973 g_source_destroy (socket->watch_err); 974 socket->watch_err = NULL; 975 } 976 977 if (socket->watch_hup) { 978 g_source_destroy (socket->watch_hup); 979 socket->watch_hup = NULL; 980 } 981 982 if (socket->watch_out) { 983 g_source_destroy (socket->watch_out); 984 socket->watch_out = NULL; 985 } 986 987 socket_close_io_channel (socket->io_channel); 988 989 socket->io_channel = NULL; 990 socket->fd = -1; 991 } 992 993 if (socket->ssl) { 994 _lm_ssl_close (socket->ssl); 995 } 996} 997 998gchar * 999lm_old_socket_get_local_host (LmOldSocket *socket) 1000{ 1001 return _lm_sock_get_local_host (socket->fd); 1002} 1003 1004LmOldSocket * 1005lm_old_socket_ref (LmOldSocket *socket) 1006{ 1007 g_return_val_if_fail (socket != NULL, NULL); 1008 1009 socket->ref_count++; 1010 1011 return socket; 1012} 1013 1014void 1015lm_old_socket_unref (LmOldSocket *socket) 1016{ 1017 g_return_if_fail (socket != NULL); 1018 1019 socket->ref_count--; 1020 1021 if (socket->ref_count <= 0) { 1022 socket_free (socket); 1023 } 1024} 1025 1026gboolean 1027lm_old_socket_set_keepalive (LmOldSocket *socket, int delay) 1028{ 1029#ifdef USE_TCP_KEEPALIVES 1030 return _lm_sock_set_keepalive (socket->fd, delay); 1031#else 1032 return FALSE; 1033#endif /* USE_TCP_KEEPALIVES */ 1034} 1035 1036void 1037lm_old_socket_asyncns_cancel (LmOldSocket *socket) 1038{ 1039 if (!socket->resolver) { 1040 return; 1041 } 1042 1043 lm_resolver_cancel (socket->resolver); 1044} 1045 1046gboolean 1047lm_old_socket_get_use_starttls (LmOldSocket *socket) 1048{ 1049 if (!socket->ssl) { 1050 return FALSE; 1051 } 1052 1053 return lm_ssl_get_use_starttls (socket->ssl); 1054} 1055 1056gboolean 1057lm_old_socket_get_require_starttls (LmOldSocket *socket) 1058{ 1059 if (!socket->ssl) { 1060 return FALSE; 1061 } 1062 1063 return lm_ssl_get_require_starttls (socket->ssl); 1064}