PageRenderTime 54ms CodeModel.GetById 2ms app.highlight 45ms RepoModel.GetById 1ms app.codeStats 0ms

/loudmouth/lm-old-socket.c

https://github.com/engineyard/loudmouth
C | 1062 lines | 789 code | 209 blank | 64 comment | 116 complexity | ccf2ea3c7b2901d85e56f9ee2926d996 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 || *bytes_read < 0) {
 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    }
 473
 474    if (connect_data->current_addr == NULL) { /*Ran Out Of Addresses*/
 475        if (socket->connect_func) {
 476            (socket->connect_func) (socket, FALSE, socket->user_data);
 477        }
 478
 479        /* if the user callback called connection_close(), this is already freed */
 480        if (socket->connect_data != NULL) {
 481            if (socket->resolver) {
 482                g_object_unref (socket->resolver);
 483            }
 484
 485            socket->connect_data = NULL;
 486            g_free (connect_data);
 487        }
 488    } else {
 489        /* try to connect to the next host */
 490        return socket_do_connect (connect_data);
 491    }
 492
 493    lm_old_socket_unref (socket);
 494
 495    return FALSE;
 496}
 497
 498gboolean
 499_lm_old_socket_failed (LmConnectData *connect_data)
 500{
 501    return _lm_old_socket_failed_with_error (connect_data,
 502                                             _lm_sock_get_last_error());
 503}
 504
 505static gboolean
 506socket_connect_cb (GIOChannel   *source,
 507                   GIOCondition  condition,
 508                   LmConnectData *connect_data)
 509{
 510    LmOldSocket     *socket;
 511    struct addrinfo *addr;
 512    int              err;
 513    socklen_t        len;
 514    LmOldSocketT     fd;
 515    gboolean         result = FALSE;
 516
 517    socket = lm_old_socket_ref (connect_data->socket);
 518    addr = connect_data->current_addr;
 519    fd = g_io_channel_unix_get_fd (source);
 520
 521    if (condition == G_IO_ERR) {
 522        len = sizeof (err);
 523        _lm_sock_get_error (fd, &err, &len);
 524        if (!_lm_sock_is_blocking_error (err)) {
 525            g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE,
 526                   "Connection failed.\n");
 527
 528            /* error condition, but might be possible to recover
 529             * from it (by connecting to the next host) */
 530            if (!_lm_old_socket_failed_with_error (connect_data, err)) {
 531                socket->watch_connect = NULL;
 532                goto out;
 533            }
 534        }
 535    }
 536
 537#if 0
 538    if (_lm_connection_async_connect_waiting (socket->connection)) {
 539        gint res;
 540
 541        fd = g_io_channel_unix_get_fd (source);
 542
 543        res = _lm_sock_connect (fd, addr->ai_addr, (int)addr->ai_addrlen);
 544        if (res < 0) {
 545            err = _lm_sock_get_last_error ();
 546            if (_lm_sock_is_blocking_success (err)) {
 547                _lm_connection_set_async_connect_waiting (socket->connection, FALSE);
 548
 549                g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
 550                       "Connection success (1).\n");
 551
 552                _lm_old_socket_succeeded (connect_data);
 553            }
 554
 555            if (_lm_connection_async_connect_waiting (socket->connection) &&
 556                !_lm_sock_is_blocking_error (err)) {
 557                g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
 558                       "Connection failed.\n");
 559
 560                _lm_sock_close (connect_data->fd);
 561                _lm_old_socket_failed_with_error (connect_data, err);
 562
 563                socket->watch_connect = NULL;
 564                goto out;
 565            }
 566        }
 567    } else {
 568#endif
 569    {
 570        /* for blocking sockets, G_IO_OUT means we are connected */
 571        g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE,
 572               "Connection success (2).\n");
 573
 574        _lm_old_socket_succeeded (connect_data);
 575    }
 576
 577    result = TRUE;
 578
 579 out:
 580    lm_old_socket_unref(socket);
 581
 582    return result;
 583}
 584
 585static gboolean
 586socket_do_connect (LmConnectData *connect_data)
 587{
 588    LmOldSocket     *socket;
 589    LmOldSocketT     fd;
 590    int              res, err;
 591    int              port;
 592    char             name[NI_MAXHOST];
 593    char             portname[NI_MAXSERV];
 594    struct addrinfo *addr;
 595
 596    socket = connect_data->socket;
 597    addr = connect_data->current_addr;
 598
 599    if (socket->port == 0) {
 600        socket->port = 5222;
 601    }
 602
 603    if (socket->proxy) {
 604        port = htons (lm_proxy_get_port (socket->proxy));
 605    } else {
 606        port = htons (socket->port);
 607    }
 608
 609    ((struct sockaddr_in *) addr->ai_addr)->sin_port = port;
 610
 611    res = getnameinfo (addr->ai_addr,
 612                       (socklen_t)addr->ai_addrlen,
 613                       name,     sizeof (name),
 614                       portname, sizeof (portname),
 615                       NI_NUMERICHOST | NI_NUMERICSERV);
 616
 617    if (res < 0) {
 618        return _lm_old_socket_failed (connect_data);
 619    }
 620
 621    g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
 622           "Trying %s port %s...\n", name, portname);
 623
 624    fd = _lm_sock_makesocket (addr->ai_family,
 625                              addr->ai_socktype,
 626                              addr->ai_protocol);
 627
 628    if (!_LM_SOCK_VALID (fd)) {
 629        g_print("invalid fd\n");
 630        g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
 631               "Failed making socket, error:%d...\n",
 632               _lm_sock_get_last_error ());
 633
 634        return _lm_old_socket_failed (connect_data);
 635    }
 636
 637    /* Even though it says _unix_new(), it is supported by glib on
 638     * win32 because glib does some cool stuff to find out if it
 639     * can treat it as a FD or a windows SOCKET.
 640     */
 641    connect_data->fd = fd;
 642    connect_data->io_channel = g_io_channel_unix_new (fd);
 643
 644    g_io_channel_set_encoding (connect_data->io_channel, NULL, NULL);
 645    g_io_channel_set_buffered (connect_data->io_channel, FALSE);
 646
 647    _lm_sock_set_blocking (connect_data->fd, FALSE);
 648
 649    if (socket->proxy) {
 650        socket->watch_connect =
 651            lm_misc_add_io_watch (socket->context,
 652                                  connect_data->io_channel,
 653                                  G_IO_OUT|G_IO_ERR,
 654                                  (GIOFunc) _lm_proxy_connect_cb,
 655                                  connect_data);
 656    } else {
 657        socket->watch_connect =
 658            lm_misc_add_io_watch (socket->context,
 659                                  connect_data->io_channel,
 660                                  G_IO_OUT|G_IO_ERR,
 661                                  (GIOFunc) socket_connect_cb,
 662                                  connect_data);
 663    }
 664
 665    res = _lm_sock_connect (connect_data->fd,
 666                            addr->ai_addr, (int)addr->ai_addrlen);
 667    if (res < 0) {
 668        err = _lm_sock_get_last_error ();
 669        if (!_lm_sock_is_blocking_error (err)) {
 670            _lm_sock_close (connect_data->fd);
 671            g_print("unable to connect\n");
 672            return _lm_old_socket_failed_with_error (connect_data, err);
 673        }
 674    }
 675
 676    return TRUE;
 677}
 678
 679static gboolean
 680old_socket_output_is_buffered (LmOldSocket     *socket,
 681                               const gchar  *buffer,
 682                               gint          len)
 683{
 684    if (socket->out_buf) {
 685        lm_verbose ("Appending %d bytes to output buffer\n", len);
 686        g_string_append_len (socket->out_buf, buffer, len);
 687        return TRUE;
 688    }
 689
 690    return FALSE;
 691}
 692
 693static void
 694old_socket_setup_output_buffer (LmOldSocket *socket, const gchar *buffer, gint len)
 695{
 696    lm_verbose ("OUTPUT BUFFER ENABLED\n");
 697
 698    socket->out_buf = g_string_new_len (buffer, len);
 699
 700    socket->watch_out =
 701        lm_misc_add_io_watch (socket->context,
 702                              socket->io_channel,
 703                              G_IO_OUT,
 704                              (GIOFunc) socket_buffered_write_cb,
 705                              socket);
 706}
 707
 708static gboolean
 709socket_buffered_write_cb (GIOChannel   *source,
 710                          GIOCondition  condition,
 711                          LmOldSocket     *socket)
 712{
 713    gint     b_written;
 714    GString *out_buf;
 715
 716    out_buf = socket->out_buf;
 717    if (!out_buf) {
 718        /* Should not be possible */
 719        return FALSE;
 720    }
 721
 722    b_written = old_socket_do_write (socket, out_buf->str, out_buf->len);
 723
 724    if (b_written < 0) {
 725        (socket->closed_func) (socket, LM_DISCONNECT_REASON_ERROR,
 726                               socket->user_data);
 727        return FALSE;
 728    }
 729
 730    g_string_erase (out_buf, 0, (gsize) b_written);
 731    if (out_buf->len == 0) {
 732        lm_verbose ("Output buffer is empty, going back to normal output\n");
 733
 734        if (socket->watch_out) {
 735            g_source_destroy (socket->watch_out);
 736            socket->watch_out = NULL;
 737        }
 738
 739        g_string_free (out_buf, TRUE);
 740        socket->out_buf = NULL;
 741        return FALSE;
 742    }
 743
 744    return TRUE;
 745}
 746
 747static void
 748socket_close_io_channel (GIOChannel *io_channel)
 749{
 750    gint fd;
 751
 752    g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
 753           "Freeing up IOChannel and file descriptor\n");
 754
 755    fd = g_io_channel_unix_get_fd (io_channel);
 756
 757    g_io_channel_unref (io_channel);
 758
 759    _lm_sock_close (fd);
 760}
 761
 762static void
 763old_socket_resolver_host_cb (LmResolver       *resolver,
 764                             LmResolverResult  result,
 765                             gpointer          user_data)
 766{
 767    LmOldSocket *socket = (LmOldSocket *) user_data;
 768    char dispbuf[128];
 769    struct sockaddr_in *addr; /* FIXME:IPv6 */
 770    const char *converr;
 771
 772    lm_verbose ("LmOldSocket::host_cb (result=%d)\n", result);
 773
 774    if (result != LM_RESOLVER_RESULT_OK) {
 775        lm_verbose ("error while resolving, bailing out\n");
 776        if (socket->connect_func) {
 777            (socket->connect_func) (socket, FALSE, socket->user_data);
 778        }
 779        /*FIXME: Leaking Resolvers Until Clean Up Can Be Properly Handled
 780        g_object_unref (socket->resolver);
 781        socket->resolver = NULL;*/
 782        g_free (socket->connect_data);
 783        socket->connect_data = NULL;
 784
 785        return;
 786    }
 787
 788    socket->connect_data->current_addr =
 789        lm_resolver_results_get_next (resolver);
 790
 791    if (socket->connect_data->current_addr) { /* FIXME:IPv6 */
 792        addr = (struct sockaddr_in *) (socket->connect_data->current_addr->ai_addr);
 793        converr = inet_ntop(AF_INET,&(addr->sin_addr),dispbuf,sizeof(dispbuf));
 794        if (converr) {
 795            g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE,
 796                   "Attempting Connection to %s\n",dispbuf);
 797        } else {
 798            g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE,
 799                   "Attempting Connection (unable to convert address to presentable format)\n");
 800        };
 801        socket_do_connect (socket->connect_data);
 802    } else { /* FIXME: IPv6 Support? */
 803        g_log (LM_LOG_DOMAIN,G_LOG_LEVEL_ERROR,
 804               "Unable to locate server available over IPv4.\n");
 805    };
 806
 807    /* FIXME: What do we do here?  How to make the mainloop exit with an 
 808       error, while having no ref to said mainloop */
 809}
 810
 811/* FIXME: Need to have a way to only get srv reply and then decide if the
 812 *        resolver should continue to look the host up.
 813 *
 814 *        This is needed for the case when we do a SRV lookup to lookup the
 815 *        real host of the service and then connect to it through a proxy.
 816 */
 817static void
 818old_socket_resolver_srv_cb (LmResolver       *resolver,
 819                            LmResolverResult  result,
 820                            gpointer          user_data)
 821{
 822    LmOldSocket *socket = (LmOldSocket *) user_data;
 823    const gchar *remote_addr;
 824
 825    lm_verbose ("LmOldSocket::srv_cb (result=%d)\n", result);
 826
 827    if (result != LM_RESOLVER_RESULT_OK) {
 828        lm_verbose ("SRV lookup failed, trying jid domain\n");
 829        socket->server = g_strdup (socket->domain);
 830    } else {
 831        g_object_get (resolver, "host", &socket->server, NULL);
 832        g_object_get (resolver, "port", &socket->port, NULL);
 833    }
 834
 835    if (socket->proxy) {
 836        remote_addr = lm_proxy_get_server (socket->proxy);
 837    } else if (socket->server) {
 838        remote_addr = socket->server;
 839    }
 840    else {
 841        remote_addr = socket->domain;
 842    }
 843
 844    g_object_unref (socket->resolver);
 845
 846    socket->resolver =
 847            lm_resolver_new_for_host (remote_addr,
 848                                      old_socket_resolver_host_cb,
 849                                      socket);
 850
 851    lm_resolver_lookup (socket->resolver);
 852}
 853
 854LmOldSocket *
 855lm_old_socket_create (GMainContext      *context,
 856                      IncomingDataFunc   data_func,
 857                      SocketClosedFunc   closed_func,
 858                      ConnectResultFunc  connect_func,
 859                      gpointer           user_data,
 860                      LmConnection      *connection,
 861                      const gchar       *server,
 862                      const gchar       *domain,
 863                      guint              port,
 864                      LmSSL             *ssl,
 865                      LmProxy           *proxy,
 866                      GError           **error)
 867{
 868    LmOldSocket   *socket;
 869    LmConnectData *data;
 870
 871    g_return_val_if_fail (domain != NULL, NULL);
 872    g_return_val_if_fail ((port >= LM_MIN_PORT && port <= LM_MAX_PORT), NULL);
 873    g_return_val_if_fail (data_func != NULL, NULL);
 874    g_return_val_if_fail (closed_func != NULL, NULL);
 875    g_return_val_if_fail (connect_func != NULL, NULL);
 876
 877    socket = g_new0 (LmOldSocket, 1);
 878
 879    socket->ref_count = 1;
 880
 881    socket->connection = connection;
 882    socket->domain = g_strdup (domain);
 883    socket->server = g_strdup (server);
 884    socket->port = port;
 885    socket->cancel_open = FALSE;
 886    socket->ssl = ssl;
 887    socket->ssl_started = FALSE;
 888    socket->proxy = NULL;
 889
 890    if (context) {
 891        socket->context = g_main_context_ref (context);
 892    }
 893
 894    if (proxy) {
 895        socket->proxy = lm_proxy_ref (proxy);
 896    }
 897
 898    data = g_new0 (LmConnectData, 1);
 899    data->socket = socket;
 900    data->connection = socket->connection;
 901    data->fd = -1;
 902    socket->connect_data = data;
 903
 904    if (!server) {
 905        socket->resolver = lm_resolver_new_for_service (socket->domain,
 906                                                        "xmpp-client",
 907                                                        "tcp",
 908                                                        old_socket_resolver_srv_cb,
 909                                                        socket);
 910    } else {
 911        socket->resolver =
 912            lm_resolver_new_for_host (socket->server ? socket->server : socket->domain,
 913                                      old_socket_resolver_host_cb,
 914                                      socket);
 915    }
 916
 917    if (socket->context) {
 918        g_object_set (socket->resolver, "context", context, NULL);
 919    }
 920
 921    socket->data_func = data_func;
 922    socket->closed_func = closed_func;
 923    socket->connect_func = connect_func;
 924    socket->user_data = user_data;
 925
 926    lm_resolver_lookup (socket->resolver);
 927
 928    return socket;
 929}
 930
 931void
 932lm_old_socket_flush (LmOldSocket *socket)
 933{
 934    g_return_if_fail (socket != NULL);
 935    g_return_if_fail (socket->io_channel != NULL);
 936
 937    g_io_channel_flush (socket->io_channel, NULL);
 938}
 939
 940void
 941lm_old_socket_close (LmOldSocket *socket)
 942{
 943    LmConnectData *data;
 944
 945    g_return_if_fail (socket != NULL);
 946
 947    if (socket->watch_connect) {
 948        g_source_destroy (socket->watch_connect);
 949        socket->watch_connect = NULL;
 950    }
 951
 952    data = socket->connect_data;
 953    if (data) {
 954        socket->connect_data = NULL;
 955        g_free (data);
 956    }
 957
 958    /* FIXME: Leaking Resolvers Until Clean Up Can Be Corrected
 959    if (socket->resolver) {
 960        g_object_unref (socket->resolver);
 961        socket->resolver = NULL;
 962    } */
 963
 964    if (socket->io_channel) {
 965        if (socket->watch_in) {
 966            g_source_destroy (socket->watch_in);
 967            socket->watch_in = NULL;
 968        }
 969
 970        if (socket->watch_err) {
 971            g_source_destroy (socket->watch_err);
 972            socket->watch_err = NULL;
 973        }
 974
 975        if (socket->watch_hup) {
 976            g_source_destroy (socket->watch_hup);
 977            socket->watch_hup = NULL;
 978        }
 979
 980        if (socket->watch_out) {
 981            g_source_destroy (socket->watch_out);
 982            socket->watch_out = NULL;
 983        }
 984
 985        socket_close_io_channel (socket->io_channel);
 986
 987        socket->io_channel = NULL;
 988        socket->fd = -1;
 989    }
 990
 991    if (socket->ssl) {
 992        _lm_ssl_close (socket->ssl);
 993    }
 994}
 995
 996gchar *
 997lm_old_socket_get_local_host (LmOldSocket *socket)
 998{
 999    return _lm_sock_get_local_host (socket->fd);
1000}
1001
1002LmOldSocket *
1003lm_old_socket_ref (LmOldSocket *socket)
1004{
1005    g_return_val_if_fail (socket != NULL, NULL);
1006
1007    socket->ref_count++;
1008
1009    return socket;
1010}
1011
1012void
1013lm_old_socket_unref (LmOldSocket *socket)
1014{
1015    g_return_if_fail (socket != NULL);
1016
1017    socket->ref_count--;
1018
1019    if (socket->ref_count <= 0) {
1020        socket_free (socket);
1021    }
1022}
1023
1024gboolean
1025lm_old_socket_set_keepalive (LmOldSocket *socket, int delay)
1026{
1027#ifdef USE_TCP_KEEPALIVES
1028    return _lm_sock_set_keepalive (socket->fd, delay);
1029#else
1030    return FALSE;
1031#endif /* USE_TCP_KEEPALIVES */
1032}
1033
1034void
1035lm_old_socket_asyncns_cancel (LmOldSocket *socket)
1036{
1037    if (!socket->resolver) {
1038        return;
1039    }
1040
1041    lm_resolver_cancel (socket->resolver);
1042}
1043
1044gboolean
1045lm_old_socket_get_use_starttls (LmOldSocket *socket)
1046{
1047    if (!socket->ssl) {
1048        return FALSE;
1049    }
1050
1051    return lm_ssl_get_use_starttls (socket->ssl);
1052}
1053
1054gboolean
1055lm_old_socket_get_require_starttls (LmOldSocket *socket)
1056{
1057    if (!socket->ssl) {
1058        return FALSE;
1059    }
1060
1061    return lm_ssl_get_require_starttls (socket->ssl);
1062}