Ejemplo n.º 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));
}
Ejemplo n.º 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));
}
Ejemplo n.º 3
0
void lcb_server_v1_read_handler(lcb_sockdata_t *sockptr, lcb_ssize_t nr)
{
    lcb_server_t *c;
    int rv;
    hrtime_t stop;

    if (!lcb_sockrw_v1_cb_common(sockptr, NULL, (void **)&c)) {
        return;
    }

    lcb_sockrw_v1_onread_common(sockptr, &c->connection.input, nr);

    c->inside_handler = 1;

    if (nr < 1) {
        event_complete_common(c, LCB_NETWORK_ERROR);
        return;
    }

    lcb_connection_delay_timer(&c->connection);

    stop = gethrtime();

    while ((rv = lcb_proto_parse_single(c, stop)) > 0) {
        /* do nothing */
    }

    if (rv >= 0) {
        /* Schedule the read request again */
        lcb_sockrw_set_want(&c->connection, LCB_READ_EVENT, 0);
    }
    event_complete_common(c, LCB_SUCCESS);
}
Ejemplo n.º 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);
}
Ejemplo n.º 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);
    }
}
Ejemplo n.º 6
0
static void sasl_auth_response_handler(lcb_server_t *server,
                                       struct lcb_command_data_st *command_data,
                                       protocol_binary_response_header *res)
{
    lcb_uint16_t ret = ntohs(res->response.status);

    if (ret == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
        if (server->sasl_conn) {
            cbsasl_dispose(&server->sasl_conn);
        }
        server->sasl_conn = NULL;
        lcb_server_connected(server);
    } else if (ret == PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE) {
        protocol_binary_request_no_extras req;
        lcb_connection_t conn = &server->connection;
        const char *out, *bytes = (const char *)res + sizeof(res->bytes);
        unsigned int nout, nbytes = ntohl(res->response.bodylen);

        if (cbsasl_client_step(server->sasl_conn, bytes, nbytes,
                               NULL, &out, &nout) != SASL_CONTINUE) {
            lcb_error_handler(server->instance, LCB_AUTH_ERROR,
                              "Unable to perform SASL STEP");
            return;
        }
        memset(&req, 0, sizeof(req));
        req.message.header.request.magic = PROTOCOL_BINARY_REQ;
        req.message.header.request.opcode = PROTOCOL_BINARY_CMD_SASL_STEP;
        req.message.header.request.keylen = ntohs((lcb_uint16_t)server->sasl_nmech);
        req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
        req.message.header.request.bodylen = ntohl((lcb_uint32_t)(server->sasl_nmech + nout));
        lcb_server_buffer_start_packet(server, command_data->cookie, conn->output,
                                       &server->output_cookies,
                                       req.bytes, sizeof(req.bytes));
        lcb_server_buffer_write_packet(server, conn->output,
                                       server->sasl_mech, server->sasl_nmech);
        lcb_server_buffer_write_packet(server, conn->output, out, nout);
        lcb_server_buffer_end_packet(server, conn->output);
        lcb_sockrw_set_want(conn, LCB_WRITE_EVENT, 0);
    } else {
        lcb_error_handler(server->instance, LCB_AUTH_ERROR,
                          "SASL authentication failed");
    }

    /* Make it known that this was a success. */
    lcb_error_handler(server->instance, LCB_SUCCESS, NULL);
    (void)command_data;
}
Ejemplo n.º 7
0
static void start_sasl_auth_server(lcb_server_t *server)
{
    protocol_binary_request_no_extras req;
    lcb_connection_t conn = &server->connection;

    memset(&req, 0, sizeof(req));
    req.message.header.request.magic = PROTOCOL_BINARY_REQ;
    req.message.header.request.opcode = PROTOCOL_BINARY_CMD_SASL_LIST_MECHS;
    req.message.header.request.keylen = 0;
    req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
    req.message.header.request.bodylen = 0;

    lcb_server_buffer_complete_packet(server, NULL, conn->output,
                                      &server->output_cookies,
                                      req.bytes, sizeof(req.bytes));
    lcb_sockrw_set_want(conn, LCB_WRITE_EVENT, 0);
}
Ejemplo n.º 8
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);
        }
    }
}
Ejemplo n.º 9
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);
}
Ejemplo n.º 10
0
static void config_v1_read_handler(lcb_sockdata_t *sockptr, lcb_ssize_t nr)
{
    lcb_t instance;
    lcb_connection_t conn = sockptr->lcbconn;

    if (!lcb_sockrw_v1_cb_common(sockptr, NULL, (void **)&instance)) {
        return;
    }
    lcb_sockrw_v1_onread_common(sockptr, &conn->input, nr);
    if (nr < 1) {
        v1_error_common(instance);
        return;
    }

    lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1);
    /* automatically does apply_want */
    handle_vbstream_read(instance);
}
Ejemplo n.º 11
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);
    }
}
Ejemplo n.º 12
0
void lcb_server_v1_write_handler(lcb_sockdata_t *sockptr,
                                 lcb_io_writebuf_t *wbuf,
                                 int status)
{
    lcb_server_t *c;
    if (!lcb_sockrw_v1_cb_common(sockptr, wbuf, (void **)&c)) {
        return;
    }

    lcb_sockrw_v1_onwrite_common(sockptr, wbuf, &c->connection.output);

    c->inside_handler = 1;

    if (status) {
        event_complete_common(c, LCB_NETWORK_ERROR);
    } else {
        lcb_sockrw_set_want(&c->connection, LCB_READ_EVENT, 0);
        event_complete_common(c, LCB_SUCCESS);
    }
}
Ejemplo n.º 13
0
void lcb_server_v0_event_handler(lcb_socket_t sock, short which, void *arg)
{
    lcb_server_t *c = arg;
    lcb_connection_t conn = &c->connection;
    (void)sock;

    if (which & LCB_WRITE_EVENT) {
        lcb_sockrw_status_t status;

        status = lcb_sockrw_v0_write(conn, conn->output);
        if (status != LCB_SOCKRW_WROTE && status != LCB_SOCKRW_WOULDBLOCK) {
            event_complete_common(c, LCB_NETWORK_ERROR);
            return;
        }
    }

    if (which & LCB_READ_EVENT || conn->input->nbytes) {
        if (do_read_data(c, which & LCB_READ_EVENT) != 0) {
            /* TODO stash error message somewhere
             * "Failed to read from connection to \"%s:%s\"", c->hostname, c->port */
            event_complete_common(c, LCB_NETWORK_ERROR);
            return;
        }
    }

    /**
     * Because of the operations-per-call limit, we might still need to read
     * a bit more once the event loop calls us again. We can't assume a
     * non-blocking read if we don't expect any data, but we can usually rely
     * on a non-blocking write.
     */
    if (conn->output->nbytes || conn->input->nbytes) {
        which = LCB_RW_EVENT;
    } else {
        which = LCB_READ_EVENT;
    }

    lcb_sockrw_set_want(conn, which, 1);
    event_complete_common(c, LCB_SUCCESS);
}
Ejemplo n.º 14
0
/**
 * Callback from libevent when we read from the REST socket
 * @param sock the readable socket
 * @param which what kind of events we may do
 * @param arg pointer to the libcouchbase instance
 */
static void config_v0_handler(lcb_socket_t sock, short which, void *arg)
{
    lcb_t instance = arg;
    lcb_connection_t conn = &instance->bootstrap.via.http.connection;
    lcb_sockrw_status_t status;

    lcb_assert(sock != INVALID_SOCKET);
    if ((which & LCB_WRITE_EVENT) == LCB_WRITE_EVENT) {

        status = lcb_sockrw_v0_write(conn, conn->output);
        if (status != LCB_SOCKRW_WROTE && status != LCB_SOCKRW_WOULDBLOCK) {
            lcb_bootstrap_error(instance, LCB_NETWORK_ERROR,
                                "Problem with sending data. "
                                "Failed to send data to REST server", 0);
            return;
        }

        if (lcb_sockrw_flushed(conn)) {
            lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1);
        }

    }

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

    status = lcb_sockrw_v0_slurp(conn, conn->input);
    if (status != LCB_SOCKRW_READ && status != LCB_SOCKRW_WOULDBLOCK) {
        lcb_bootstrap_error(instance, LCB_NETWORK_ERROR,
                            "Problem with reading data. "
                            "Failed to send read data from REST server", 0);
        return;
    }

    handle_vbstream_read(instance);
    (void)sock;
}
Ejemplo n.º 15
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);
    }
}
Ejemplo n.º 16
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;
}
Ejemplo n.º 17
0
static void sasl_list_mech_response_handler(lcb_server_t *server,
                                            struct lcb_command_data_st *command_data,
                                            protocol_binary_response_header *res)
{
    const char *chosenmech;
    char *mechlist;
    const char *data;
    unsigned int ndata;
    protocol_binary_request_no_extras req;
    lcb_size_t bodysize;
    lcb_uint16_t ret = ntohs(res->response.status);
    lcb_connection_t conn = &server->connection;

    if (ret != PROTOCOL_BINARY_RESPONSE_SUCCESS) {
        lcb_error_handler(server->instance, LCB_AUTH_ERROR,
                          "SASL authentication failed: "
                          "bad SASL_LIST_MECH status code");
        return;
    }

    bodysize = ntohl(res->response.bodylen);
    mechlist = calloc(bodysize + 1, sizeof(char));
    if (mechlist == NULL) {
        lcb_error_handler(server->instance, LCB_CLIENT_ENOMEM, NULL);
        return;
    }
    memcpy(mechlist, (const char *)(res + 1), bodysize);

    if (server->instance->sasl_mech_force) {
        if (!strstr(mechlist, server->instance->sasl_mech_force)) {
            lcb_error_handler(server->instance, LCB_SASLMECH_UNAVAILABLE,
                              mechlist);
            free(mechlist);
            return;
        }

        /** strstr already ensures we have enough space */
        strcpy(mechlist, server->instance->sasl_mech_force);
    }

    if (cbsasl_client_start(server->sasl_conn, mechlist,
                          NULL, &data, &ndata, &chosenmech) != SASL_OK) {
        free(mechlist);
        lcb_error_handler(server->instance, LCB_AUTH_ERROR,
                          "Unable to start sasl client");
        return;
    }
    free(mechlist);

    server->sasl_nmech = strlen(chosenmech);
    server->sasl_mech = strdup(chosenmech);
    if (server->sasl_mech == NULL) {
        lcb_error_handler(server->instance, LCB_CLIENT_ENOMEM, NULL);
        return;
    }

    memset(&req, 0, sizeof(req));
    req.message.header.request.magic = PROTOCOL_BINARY_REQ;
    req.message.header.request.opcode = PROTOCOL_BINARY_CMD_SASL_AUTH;
    req.message.header.request.keylen = ntohs((lcb_uint16_t)server->sasl_nmech);
    req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
    req.message.header.request.bodylen = ntohl((lcb_uint32_t)(server->sasl_nmech + ndata));

    lcb_server_buffer_start_packet(server, command_data->cookie, conn->output,
                                   &server->output_cookies,
                                   req.bytes, sizeof(req.bytes));
    lcb_server_buffer_write_packet(server, conn->output,
                                   server->sasl_mech, server->sasl_nmech);
    lcb_server_buffer_write_packet(server, conn->output, data, ndata);
    lcb_server_buffer_end_packet(server, conn->output);
    lcb_sockrw_set_want(conn, LCB_WRITE_EVENT, 0);
}
Ejemplo n.º 18
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);
    }
}