/*
 * Copyright (c) 2009-2012 Zmanda, Inc.  All Rights Reserved.
 * Copyright (c) 2013-2016 Carbonite, Inc.  All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 * Contact information: Zmanda Inc., 465 N Mathlida Ave, Suite 300
 * Sunnyvale, CA 94085, or: http://www.zmanda.com
 */

#include "amanda.h"
#include "directtcp-connection.h"
#include <glib-object.h>

/*
 * DirectTCPConnection class implementation
 */

static GObjectClass *parent_class = NULL;

static void
directtcp_connection_finalize(GObject *goself)
{
    DirectTCPConnection *self = DIRECTTCP_CONNECTION(goself);

    /* close this socket if necessary, failing fatally if that doesn't work */
    if (!self->closed) {
        char *errmsg;

        g_warning("connection freed without being closed first; any error will be fatal");
        errmsg = directtcp_connection_close(self);
        if (errmsg)
            error("while closing directtcp connection: %s", errmsg);
    }

    G_OBJECT_CLASS(parent_class)->finalize(goself);
}

static void
directtcp_connection_class_init(
        DirectTCPConnectionClass * c)
{
    GObjectClass *goc = (GObjectClass *)c;

    goc->finalize =  directtcp_connection_finalize;

    parent_class = g_type_class_peek_parent(c);
}

GType
directtcp_connection_get_type(void)
{
    static GType type = 0;
    if (G_UNLIKELY(type == 0)) {
        static const GTypeInfo info = {
            sizeof (DirectTCPConnectionClass),
            (GBaseInitFunc) NULL,
            (GBaseFinalizeFunc) NULL,
            (GClassInitFunc) directtcp_connection_class_init,
            (GClassFinalizeFunc) NULL,
            NULL /* class_data */,
            sizeof (DirectTCPConnection),
            0 /* n_preallocs */,
            (GInstanceInitFunc) NULL,
            NULL
        };

        type = g_type_register_static (G_TYPE_OBJECT, "DirectTCPConnection", &info,
                                       (GTypeFlags)G_TYPE_FLAG_ABSTRACT);
    }
    return type;
}

char *
directtcp_connection_close(
    DirectTCPConnection *self)
{
    DirectTCPConnectionClass *klass = DIRECTTCP_CONNECTION_GET_CLASS(self);
    char *rv;

    /* Note that this also tracks the 'closed' value, which is used by finalize
     * to ensure that the connection has been closed */

    g_assert(!self->closed);

    g_assert(klass->close);
    rv = klass->close(self);
    self->closed = TRUE;
    return rv;
}

/*
 * DirectTCPConnSocket class implementation
 */

DirectTCPConnectionSocket *
directtcp_connection_socket_new(
    int socket)
{
    DirectTCPConnectionSocket *conn = DIRECTTCP_CONNECTION_SOCKET(g_object_new(TYPE_DIRECTTCP_CONNECTION_SOCKET, NULL));
    conn->socket = socket;
    return conn;
}

static char *
directtcp_connection_socket_close(DirectTCPConnection *dself)
{
    DirectTCPConnectionSocket *self = DIRECTTCP_CONNECTION_SOCKET(dself);
    if (self->socket >= 0 && close(self->socket)) {
        return g_strdup_printf("while closing socket: %s", strerror(errno));
    }
    self->socket = -1;

    return NULL;
}

static void
directtcp_connection_socket_init(DirectTCPConnectionSocket *self)
{
    self->socket = -1;
}

static void
directtcp_connection_socket_class_init(DirectTCPConnectionSocketClass * c)
{
    DirectTCPConnectionClass *connc = (DirectTCPConnectionClass *)c;

    connc->close = directtcp_connection_socket_close;
}

GType
directtcp_connection_socket_get_type (void)
{
    static GType type = 0;

    if (G_UNLIKELY(type == 0)) {
        static const GTypeInfo info = {
            sizeof (DirectTCPConnectionSocketClass),
            (GBaseInitFunc) NULL,
            (GBaseFinalizeFunc) NULL,
            (GClassInitFunc) directtcp_connection_socket_class_init,
            (GClassFinalizeFunc) NULL,
            NULL /* class_data */,
            sizeof (DirectTCPConnectionSocket),
            0 /* n_preallocs */,
            (GInstanceInitFunc) directtcp_connection_socket_init,
            NULL
        };

        type = g_type_register_static(TYPE_DIRECTTCP_CONNECTION,
                                "DirectTCPConnectionSocket", &info, (GTypeFlags)0);
    }

    return type;
}
