PageRenderTime 84ms CodeModel.GetById 2ms app.highlight 75ms RepoModel.GetById 1ms app.codeStats 0ms

/loudmouth/lm-old-socket.c

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