#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <gnutls/gnutls.h>

#include "error.h"
#include "log.h"
#include "mssl_gnutls.h"

int https_resume = 0;
gnutls_certificate_credentials_t gnutls_xcred;
gnutls_datum_t gnutls_session_data;

int READ_SSL(gnutls_session_t ssl_h, char *whereto, int len) {
    int cnt = len;

    while (len > 0) {
        int rc;

        rc = gnutls_record_recv(ssl_h, whereto, len);
        if (rc < 0 && gnutls_error_is_fatal(rc) != 0) {
            dolog(LOG_ERR, "READ_SSL: io-error: %s", gnutls_strerror(rc));
            return -1;
        } else if (rc == 0) {
            return cnt - len;
        } else {
            whereto += rc;
            len -= rc;
        }
    }

    return cnt;
}

int WRITE_SSL(gnutls_session_t ssl_h, char *whereto, int len) {
    int cnt = len;

    while (len > 0) {
        int rc;

        rc = gnutls_record_send(ssl_h, whereto, len);
        if (rc < 0 && gnutls_error_is_fatal(rc) != 0) {
            dolog(LOG_ERR, "WRITE_SSL: io-error: %s", gnutls_strerror(rc));
            return -1;
        } else if (rc == 0) {
            return cnt - len;
        } else {
            whereto += rc;
            len -= rc;
        }
    }

    return cnt;
}

int connect_ssl(int socket_h, gnutls_session_t session, char *hostname) {
    int ret = 0;

    CHECK(gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname, strlen(hostname)));
    gnutls_session_set_verify_cert(session, hostname, 0);

    CHECK(gnutls_set_default_priority(session));

    gnutls_transport_set_int(session, socket_h);
    gnutls_handshake_set_timeout(session,
            GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);

    gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
            gnutls_xcred);

/* if this is not the first time we connect */
    /*
    if (https_resume) {

        CHECK(gnutls_session_set_data(session, gnutls_session_data.data,
                gnutls_session_data.size));
        gnutls_free(gnutls_session_data.data);
    }
*/

    /* Perform the TLS handshake */
    do {
        ret = gnutls_handshake(session);
    } while (ret < 0 && gnutls_error_is_fatal(ret) == 0);

    if (ret < 0) {
        dolog(LOG_ERR, "problem starting SSL connection: %s", gnutls_strerror(ret));
        return -1;
    }

     /* the first time we connect */
/*
    if (!https_resume) {
        CHECK(gnutls_session_get_data2(session, &gnutls_session_data));
        https_resume = 1;
    }
*/
    return 0;
}

void initialize_ctx(void) {
#if GNUTLS_VERSION_NUMBER < 0x030300
    CHECK(gnutls_global_init());
#endif
    CHECK(gnutls_certificate_allocate_credentials(&gnutls_xcred));
    CHECK(gnutls_certificate_set_x509_system_trust(gnutls_xcred));
}
