<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2014 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "connections.h"

#include <cJSON.h>

/*
 * Free list management for connections.
 */
struct connections {
    conn sentinal; /* Sentinal conn object used as the base of the linked-list
                      of connections. */
    cb_mutex_t mutex;
} connections;

/** Types ********************************************************************/

/** Result of a buffer loan attempt */
enum loan_res {
    loan_existing,
    loan_loaned,
    loan_allocated,
};

/** Function prototypes ******************************************************/

static void conn_loan_buffers(conn *c);
static void conn_return_buffers(conn *c);
static bool conn_reset_buffersize(conn *c);
static enum loan_res conn_loan_single_buffer(conn *c, struct net_buf *thread_buf,
                                             struct net_buf *conn_buf);
static void conn_return_single_buffer(conn *c, struct net_buf *thread_buf,
                                      struct net_buf *conn_buf);
static int conn_constructor(conn *c);
static void conn_destructor(conn *c);
static conn *allocate_connection(void);
static void release_connection(conn *c);

static cJSON* get_connection_stats(const conn *c);


/** External functions *******************************************************/

void initialize_connections(void)
{
    cb_mutex_initialize(&connections.mutex);
    connections.sentinal.all_next = &connections.sentinal;
    connections.sentinal.all_prev = &connections.sentinal;
}

void destroy_connections(void)
{
    /* traverse the list of connections. */
    conn *c = connections.sentinal.all_next;
    while (c != &connections.sentinal) {
        conn *next = c->all_next;
        conn_destructor(c);
        c = next;
    }
    connections.sentinal.all_next = &connections.sentinal;
    connections.sentinal.all_prev = &connections.sentinal;
}

void run_event_loop(conn* c) {

    if (!is_listen_thread()) {
        conn_loan_buffers(c);
    }

    do {
        if (settings.verbose) {
            settings.extensions.logger->log(EXTENSION_LOG_DEBUG, c,
                    "%d - Running task: (%s)\n", c->sfd, state_text(c->state));
        }
    } while (c->state(c));

    if (!is_listen_thread()) {
        conn_return_buffers(c);
    }

    if (c->state == conn_destroyed) {
        /* Actually free the memory from this connection. Unsafe to dereference
         * c after this point.
         */
        release_connection(c);
        c = NULL;
    }
}

conn *conn_new(const SOCKET sfd, in_port_t parent_port,
               STATE_FUNC init_state, int event_flags,
               unsigned int read_buffer_size, struct event_base *base,
               struct timeval *timeout) {
    conn *c = allocate_connection();
    if (c == NULL) {
        return NULL;
    }

    c->admin = false;
    cb_assert(c->thread == NULL);

    memset(&c->ssl, 0, sizeof(c->ssl));
    if (init_state != conn_listening) {
        int ii;
        for (ii = 0; ii < settings.num_interfaces; ++ii) {
            if (parent_port == settings.interfaces[ii].port) {
                if (settings.interfaces[ii].ssl.cert != NULL) {
                    const char *cert = settings.interfaces[ii].ssl.cert;
                    const char *pkey = settings.interfaces[ii].ssl.key;

                    c->ssl.ctx = SSL_CTX_new(SSLv23_server_method());

                    /* @todo don't read files, but use in-memory-copies */
                    if (!SSL_CTX_use_certificate_chain_file(c->ssl.ctx, cert) ||
                        !SSL_CTX_use_PrivateKey_file(c->ssl.ctx, pkey, SSL_FILETYPE_PEM)) {
                        release_connection(c);
                        return NULL;
                    }

                    c->ssl.enabled = true;
                    c->ssl.error = false;<commit_msg>MB-12359: Disable SSLv2 & SSLv3 due to the POODLE exploit<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2014 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "connections.h"

#include <cJSON.h>

/*
 * Free list management for connections.
 */
struct connections {
    conn sentinal; /* Sentinal conn object used as the base of the linked-list
                      of connections. */
    cb_mutex_t mutex;
} connections;

/** Types ********************************************************************/

/** Result of a buffer loan attempt */
enum loan_res {
    loan_existing,
    loan_loaned,
    loan_allocated,
};

/** Function prototypes ******************************************************/

static void conn_loan_buffers(conn *c);
static void conn_return_buffers(conn *c);
static bool conn_reset_buffersize(conn *c);
static enum loan_res conn_loan_single_buffer(conn *c, struct net_buf *thread_buf,
                                             struct net_buf *conn_buf);
static void conn_return_single_buffer(conn *c, struct net_buf *thread_buf,
                                      struct net_buf *conn_buf);
static int conn_constructor(conn *c);
static void conn_destructor(conn *c);
static conn *allocate_connection(void);
static void release_connection(conn *c);

static cJSON* get_connection_stats(const conn *c);


/** External functions *******************************************************/

void initialize_connections(void)
{
    cb_mutex_initialize(&connections.mutex);
    connections.sentinal.all_next = &connections.sentinal;
    connections.sentinal.all_prev = &connections.sentinal;
}

void destroy_connections(void)
{
    /* traverse the list of connections. */
    conn *c = connections.sentinal.all_next;
    while (c != &connections.sentinal) {
        conn *next = c->all_next;
        conn_destructor(c);
        c = next;
    }
    connections.sentinal.all_next = &connections.sentinal;
    connections.sentinal.all_prev = &connections.sentinal;
}

void run_event_loop(conn* c) {

    if (!is_listen_thread()) {
        conn_loan_buffers(c);
    }

    do {
        if (settings.verbose) {
            settings.extensions.logger->log(EXTENSION_LOG_DEBUG, c,
                    "%d - Running task: (%s)\n", c->sfd, state_text(c->state));
        }
    } while (c->state(c));

    if (!is_listen_thread()) {
        conn_return_buffers(c);
    }

    if (c->state == conn_destroyed) {
        /* Actually free the memory from this connection. Unsafe to dereference
         * c after this point.
         */
        release_connection(c);
        c = NULL;
    }
}

conn *conn_new(const SOCKET sfd, in_port_t parent_port,
               STATE_FUNC init_state, int event_flags,
               unsigned int read_buffer_size, struct event_base *base,
               struct timeval *timeout) {
    conn *c = allocate_connection();
    if (c == NULL) {
        return NULL;
    }

    c->admin = false;
    cb_assert(c->thread == NULL);

    memset(&c->ssl, 0, sizeof(c->ssl));
    if (init_state != conn_listening) {
        int ii;
        for (ii = 0; ii < settings.num_interfaces; ++ii) {
            if (parent_port == settings.interfaces[ii].port) {
                if (settings.interfaces[ii].ssl.cert != NULL) {
                    const char *cert = settings.interfaces[ii].ssl.cert;
                    const char *pkey = settings.interfaces[ii].ssl.key;

                    c->ssl.ctx = SSL_CTX_new(SSLv23_server_method());

                    /* MB-12359 - Disable SSLv2 & SSLv3 due to POODLE */
                    SSL_CTX_set_options(c->ssl.ctx,
                                        SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);

                    /* @todo don't read files, but use in-memory-copies */
                    if (!SSL_CTX_use_certificate_chain_file(c->ssl.ctx, cert) ||
                        !SSL_CTX_use_PrivateKey_file(c->ssl.ctx, pkey, SSL_FILETYPE_PEM)) {
                        release_connection(c);
                        return NULL;
                    }

                    c->ssl.enabled = true;
                    c->ssl.error = false;
{'fraction_non_alphanumeric': 0.14177160225792446, 'fraction_numerical': 0.004776378636561007, 'mean_word_length': 2.4312849162011174, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 36, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 7, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7420083', 'n_tokens_mistral': 2727, 'n_tokens_neox': 2605, 'n_words': 699}