예제 #1
0
static void request_config(cccp_provider *cccp)
{
    protocol_binary_request_set_cluster_config req;
    lcb_connection_t conn = &cccp->connection;
    ringbuffer_t *buf = conn->output;

    memset(&req, 0, sizeof(req));
    req.message.header.request.magic = PROTOCOL_BINARY_REQ;
    req.message.header.request.opcode = CMD_GET_CLUSTER_CONFIG;
    req.message.header.request.opaque = 0xF00D;

    if (!buf) {
        if ((buf = calloc(1, sizeof(*buf))) == NULL) {
            mcio_error(cccp, LCB_CLIENT_ENOMEM);
            return;
        }
        conn->output = buf;
    }

    if (!ringbuffer_ensure_capacity(buf, sizeof(req.bytes))) {
        mcio_error(cccp, LCB_CLIENT_ENOMEM);
    }

    ringbuffer_write(buf, req.bytes, sizeof(req.bytes));
    lcb_sockrw_set_want(conn, LCB_WRITE_EVENT, 1);
    lcb_sockrw_apply_want(conn);
    lcb_timer_rearm(cccp->timer, PROVIDER_SETTING(&cccp->base,
                                                  config_node_timeout));
}
예제 #2
0
static void connect_done_handler(lcb_connection_t conn, lcb_error_t err)
{
    http_provider *http = (http_provider *)conn->data;
    const lcb_host_t *host = lcb_connection_get_host(conn);

    if (err != LCB_SUCCESS) {
        lcb_log(LOGARGS(http, ERR),
                "Connection to REST API @%s:%s failed with code=0x%x",
                host->host, host->port, err);

        io_error(http, err);
        return;
    }

    lcb_log(LOGARGS(http, DEBUG),
            "Successfuly connected to REST API %s:%s",
            host->host, host->port);

    lcb_connection_reset_buffers(conn);
    ringbuffer_strcat(conn->output, http->request_buf);
    lcb_assert(conn->output->nbytes > 0);

    lcb_sockrw_set_want(conn, LCB_RW_EVENT, 0);
    lcb_sockrw_apply_want(conn);
    lcb_timer_rearm(http->io_timer,
                    PROVIDER_SETTING(&http->base, config_node_timeout));
}
예제 #3
0
static void event_complete_common(lcb_server_t *c, lcb_error_t rc)
{
    lcb_t instance = c->instance;

    if (rc != LCB_SUCCESS) {
        lcb_failout_server(c, rc);
    } else {
        if (instance->bootstrap.type == LCB_CONFIG_TRANSPORT_HTTP && c->is_config_node) {
            c->instance->bootstrap.via.http.weird_things = 0;
        }
        lcb_sockrw_apply_want(&c->connection);
        c->inside_handler = 0;
    }

    if (instance->compat.type == LCB_CACHED_CONFIG &&
            instance->compat.value.cached.needs_update) {
        lcb_refresh_config_cache(instance);

    } else if (instance->bootstrap.type == LCB_CONFIG_TRANSPORT_CCCP &&
            instance->bootstrap.via.cccp.next_config) {
        lcb_update_vbconfig(instance, instance->bootstrap.via.cccp.next_config);
        instance->bootstrap.via.cccp.next_config = NULL;
    }

    lcb_maybe_breakout(instance);
    lcb_error_handler(instance, rc, NULL);
}
예제 #4
0
/**
 * Common function to handle parsing the HTTP stream for both v0 and v1 io
 * implementations.
 */
static void read_common(http_provider *http)
{
    lcb_error_t err;
    lcb_connection_t conn = &http->connection;
    int old_generation = http->stream.generation;

    lcb_log(LOGARGS(http, TRACE),
            "Received %d bytes on HTTP stream", conn->input->nbytes);

    lcb_timer_rearm(http->io_timer,
                    PROVIDER_SETTING(&http->base, config_node_timeout));

    lcb_string_rbappend(&http->stream.chunk, conn->input, 1);

    err = htvb_parse(&http->stream, http->base.parent->settings->conntype);

    if (http->stream.generation != old_generation) {
        lcb_log(LOGARGS(http, DEBUG),
                "Generation %d -> %d", old_generation, http->stream.generation);

        set_new_config(http);
    } else {
        lcb_log(LOGARGS(http, TRACE), "HTTP not yet done. Err=0x%x", err);
    }

    if (err != LCB_BUSY && err != LCB_SUCCESS) {
        io_error(http, err);
        return;
    }

    lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1);
    lcb_sockrw_apply_want(conn);
}
예제 #5
0
static void v0_generic_handler(lcb_socket_t sock, short which, void *arg)
{
    lcb_connection_t conn = arg;
    lcb_sockrw_status_t status;
    lcb_size_t oldnr, newnr;

    lcb_assert(sock != INVALID_SOCKET);

    if (which & LCB_WRITE_EVENT) {
        status = lcb_sockrw_v0_write(conn, conn->output);
        if (status == LCB_SOCKRW_WROTE) {
            if ((which & LCB_READ_EVENT) == 0) {
                lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1);
                lcb_sockrw_apply_want(conn);
            }

        } else if (status == LCB_SOCKRW_WOULDBLOCK) {
            lcb_sockrw_set_want(conn, LCB_WRITE_EVENT, 0);
            lcb_sockrw_apply_want(conn);

        } else {
            conn->easy.error(conn);
            return;
        }
    }

    if ( (which & LCB_READ_EVENT) == 0) {
        return;
    }

    oldnr = conn->input->nbytes;
    status = lcb_sockrw_v0_slurp(conn, conn->input);
    newnr = conn->input->nbytes;

    if (status != LCB_SOCKRW_READ &&
            status != LCB_SOCKRW_WOULDBLOCK && oldnr == newnr) {

        conn->easy.error(conn);
    } else {
        conn->easy.read(conn);
    }
}
예제 #6
0
void lcb_server_connect_handler(lcb_connection_t conn, lcb_error_t err)
{
    lcb_server_t *server = (lcb_server_t *)conn->data;
    struct nameinfo_common nistrs;
    int sasl_in_progress;
    int should_do_sasl = 0;

    if (err != LCB_SUCCESS) {
        connection_error(server, err);
        return;
    }


    server->inside_handler = 1;

    sasl_in_progress = (server->sasl_conn != NULL);
    if (!get_nameinfo(conn, &nistrs)) {
        /** This normally shouldn't happen! */
        connection_error(server, LCB_NETWORK_ERROR);
    }

    if (!sasl_in_progress) {
        int sasl_ok = cbsasl_client_new("couchbase", conn->host,
                                         nistrs.local, nistrs.remote,
                                         server->instance->sasl.callbacks, 0,
                                         &server->sasl_conn);
        lcb_assert(sasl_ok == SASL_OK);
    }

    if (server->index == -1) {
        should_do_sasl = 1;
    } else if (vbucket_config_get_user(server->instance->config.handle) != NULL) {
        should_do_sasl = 1;
    }

    if (should_do_sasl) {
        if (!sasl_in_progress) {
            start_sasl_auth_server(server);
        }
    } else {
        /* No SASL AUTH needed */
        lcb_server_connected(server);
    }

    lcb_connection_cancel_timer(conn);
    lcb_sockrw_apply_want(conn);
    server->inside_handler = 0;
}
예제 #7
0
void lcb_server_send_packets(lcb_server_t *server)
{
    if (server->pending.nbytes > 0 || server->connection.output->nbytes > 0) {
        if (server->connection_ready) {
            lcb_sockrw_set_want(&server->connection, LCB_WRITE_EVENT, 0);
            if (!server->inside_handler) {
                lcb_sockrw_apply_want(&server->connection);
                if (!lcb_timer_armed(server->io_timer)) {
                    lcb_timer_rearm(server->io_timer, MCSERVER_TIMEOUT(server));
                }
            }

        } else if (server->connection.state == LCB_CONNSTATE_UNINIT) {
            lcb_server_connect(server);
        }
    }
}
예제 #8
0
static void config_v1_write_handler(lcb_sockdata_t *sockptr,
                                    lcb_io_writebuf_t *wbuf,
                                    int status)
{
    lcb_t instance;
    lcb_connection_t conn = sockptr->lcbconn;

    if (!lcb_sockrw_v1_cb_common(sockptr, wbuf, (void **)&instance)) {
        return;
    }
    lcb_sockrw_v1_onwrite_common(sockptr, wbuf, &conn->output);
    if (status) {
        v1_error_common(instance);
    }

    lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1);
    lcb_sockrw_apply_want(conn);
}
예제 #9
0
static void event_complete_common(lcb_server_t *c, lcb_error_t rc)
{
    lcb_t instance = c->instance;

    if (rc != LCB_SUCCESS) {
        lcb_failout_server(c, rc);
    } else {
        if (c->is_config_node) {
            c->instance->weird_things = 0;
        }
        lcb_sockrw_apply_want(&c->connection);
        c->inside_handler = 0;
    }
    if (instance->compat.type == LCB_CACHED_CONFIG &&
            instance->compat.value.cached.needs_update) {
        lcb_refresh_config_cache(instance);
    }
    lcb_maybe_breakout(instance);
    lcb_error_handler(instance, rc, NULL);
}
예제 #10
0
static void v1_generic_write_handler(lcb_sockdata_t *sd,
                                     lcb_io_writebuf_t *wbuf,
                                     int status)
{
    lcb_t instance;
    lcb_connection_t conn = sd->lcbconn;

    if (!lcb_sockrw_v1_cb_common(sd, wbuf, (void **)&instance)) {
        return;
    }

    lcb_sockrw_v1_onwrite_common(sd, wbuf, &sd->lcbconn->output);

    if (status) {
        conn->easy.error(conn);
    } else {
        lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1);
        lcb_sockrw_apply_want(conn);
    }
}
예제 #11
0
static void connect_done_handler(lcb_connection_t conn, lcb_error_t err)
{
    lcb_t instance = conn->instance;

    if (err == LCB_SUCCESS) {
        /**
         * Print the URI to the ringbuffer
         */
        ringbuffer_strcat(conn->output, instance->bootstrap.via.http.uri);
        lcb_assert(conn->output->nbytes > 0);

        lcb_sockrw_set_want(conn, LCB_RW_EVENT, 0);
        lcb_sockrw_apply_want(conn);
        lcb_connection_activate_timer(conn);
        return;
    }

    if (err == LCB_ETIMEDOUT) {
        timeout_handler(conn, err);
    } else {
        lcb_bootstrap_error(instance, err, "Couldn't connect", 0);
    }
}
예제 #12
0
static void io_read_handler(lcb_connection_t conn)
{
    packet_info pi;
    cccp_provider *cccp = conn->data;
    lcb_string jsonstr;
    lcb_error_t err;
    int rv;
    lcb_host_t curhost;

    memset(&pi, 0, sizeof(pi));

    rv = lcb_packet_read_ringbuffer(&pi, conn->input);

    if (rv < 0) {
        LOG(cccp, ERR, "Couldn't parse packet!?");
        mcio_error(cccp, LCB_EINTERNAL);
        return;

    } else if (rv == 0) {
        lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1);
        lcb_sockrw_apply_want(conn);
        return;
    }

    if (PACKET_STATUS(&pi) != PROTOCOL_BINARY_RESPONSE_SUCCESS) {
        lcb_log(LOGARGS(cccp, ERR),
                "CCCP Packet responded with 0x%x; nkey=%d, nbytes=%lu, cmd=0x%x, seq=0x%x",
                PACKET_STATUS(&pi),
                PACKET_NKEY(&pi),
                PACKET_NBODY(&pi),
                PACKET_OPCODE(&pi),
                PACKET_OPAQUE(&pi));

        switch (PACKET_STATUS(&pi)) {
        case PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED:
        case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
            mcio_error(cccp, LCB_NOT_SUPPORTED);
            break;
        default:
            mcio_error(cccp, LCB_PROTOCOL_ERROR);
            break;
        }

        return;
    }

    if (!PACKET_NBODY(&pi)) {
        mcio_error(cccp, LCB_PROTOCOL_ERROR);
        return;
    }

    if (lcb_string_init(&jsonstr)) {
        mcio_error(cccp, LCB_CLIENT_ENOMEM);
        return;
    }

    if (lcb_string_append(&jsonstr, PACKET_BODY(&pi), PACKET_NBODY(&pi))) {
        mcio_error(cccp, LCB_CLIENT_ENOMEM);
        return;
    }

    curhost = *lcb_connection_get_host(&cccp->connection);
    lcb_packet_release_ringbuffer(&pi, conn->input);
    release_socket(cccp, 1);

    err = lcb_cccp_update(&cccp->base, curhost.host, &jsonstr);
    lcb_string_release(&jsonstr);
    if (err == LCB_SUCCESS) {
        lcb_timer_disarm(cccp->timer);
        cccp->server_active = 0;
    } else {
        schedule_next_request(cccp, LCB_PROTOCOL_ERROR, 0);
    }
}
예제 #13
0
/**
 * Common function to handle parsing the event loop for both v0 and v1 io
 * implementations.
 */
static lcb_error_t handle_vbstream_read(lcb_t instance)
{
    lcb_error_t err;
    int can_retry = 0;
    int old_gen = instance->config.generation;
    struct lcb_http_bootstrap_st *http = &instance->bootstrap.via.http;
    lcb_connection_t conn = &instance->bootstrap.via.http.connection;

    err = lcb_parse_vbucket_stream(instance);
    if (err == LCB_SUCCESS) {
        if (instance->type == LCB_TYPE_BUCKET) {
            lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1);
            lcb_sockrw_apply_want(conn);
        }
        if (old_gen != instance->config.generation || instance->type == LCB_TYPE_CLUSTER) {
            lcb_connection_cancel_timer(conn);
            conn->timeout.usec = 0;
            lcb_maybe_breakout(instance);
        }
        return LCB_SUCCESS;

    } else if (err != LCB_BUSY) {
        /**
         * XXX: We only want to retry on some errors. Things which signify an
         * obvious user error should be left out here; we only care about
         * actual "network" errors
         */

        switch (err) {
        case LCB_ENOMEM:
        case LCB_AUTH_ERROR:
        case LCB_PROTOCOL_ERROR:
        case LCB_BUCKET_ENOENT:
            can_retry = 0;
            break;
        default:
            can_retry = 1;
        }

        if (http->bummer && (err == LCB_BUCKET_ENOENT || err == LCB_AUTH_ERROR)) {
            can_retry = 1;
        }

        if (can_retry) {
            const char *msg = "Failed to get configuration";
            lcb_bootstrap_error(instance, err, msg, LCB_CONFERR_NO_BREAKOUT);
            return err;
        } else {
            lcb_maybe_breakout(instance);
            return lcb_error_handler(instance, err, "");
        }
    }

    lcb_assert(err == LCB_BUSY);
    lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1);
    lcb_sockrw_apply_want(conn);

    if (old_gen != instance->config.generation) {
        lcb_connection_cancel_timer(conn);
        conn->timeout.usec = 0;
        lcb_maybe_breakout(instance);
    }

    return LCB_BUSY;
}