示例#1
0
static void config_callback(lcb_server_t *server, lcb_error_t error, const char *json)
{
    VBUCKET_CONFIG_HANDLE config;
    lcb_t instance = server->instance;

    server->connection.timeout.usec = 0;
    lcb_connection_cancel_timer(&server->connection);

    if (error != LCB_SUCCESS) {
        lcb_error_handler(instance, error, "Failed to receive configration");
        return;
    }

    config = vbucket_config_create();

    if (config == NULL) {
        lcb_error_handler(instance, LCB_CLIENT_ENOMEM,
                          "Failed to allocate memory for configuration");
        return;
    }

    if (vbucket_config_parse2(config, LIBVBUCKET_SOURCE_MEMORY, json, server->connection.host)) {
        vbucket_config_destroy(config);
        lcb_error_handler(instance, LCB_PROTOCOL_ERROR,
                          vbucket_get_error_message(config));
        return;
    }

    lcb_update_vbconfig(instance, config);
}
示例#2
0
static void store_response_handler(lcb_server_t *server, packet_info *info)
{
    lcb_t root = server->instance;
    lcb_storage_t op;

    char *packet;
    lcb_uint16_t nkey;
    lcb_error_t rc;
    lcb_uint16_t status = PACKET_STATUS(info);

    const char *key = get_key(server, &nkey, &packet);
    if (PACKET_STATUS(info) == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
        rc = LCB_SUCCESS;
    } else {
        rc = map_error(root, status);
    }

    switch (PACKET_OPCODE(info)) {
    case PROTOCOL_BINARY_CMD_ADD:
        op = LCB_ADD;
        break;
    case PROTOCOL_BINARY_CMD_REPLACE:
        op = LCB_REPLACE;
        break;
    case PROTOCOL_BINARY_CMD_SET:
        op = LCB_SET;
        break;
    case PROTOCOL_BINARY_CMD_APPEND:
        op = LCB_APPEND;
        break;
    case PROTOCOL_BINARY_CMD_PREPEND:
        op = LCB_PREPEND;
        break;
    default:
        /*
        ** It is impossible to get here (since we're called from our
        ** lookup table... If we _DO_ get here, it must be a development
        ** version where the developer isn't done yet (and should be
        ** forced to think about what to do...)
        */
        lcb_error_handler(root, LCB_EINTERNAL,
                          "Internal error. Received an illegal command opcode");
        abort();
    }

    if (key == NULL) {
        lcb_error_handler(server->instance, LCB_EINTERNAL,
                          NULL);
    } else {
        lcb_store_resp_t resp;
        setup_lcb_store_resp_t(&resp, key, nkey, PACKET_CAS(info));
        PACKET_TRACE(TRACE_STORE_END, info, rc, &resp);
        root->callbacks.store(root, info->ct.cookie, op, rc, &resp);
        release_key(server, packet);
    }
}
示例#3
0
static void store_response_handler(lcb_server_t *server,
                                   struct lcb_command_data_st *command_data,
                                   protocol_binary_response_header *res)
{
    lcb_t root = server->instance;
    lcb_storage_t op;

    char *packet;
    lcb_uint16_t nkey;
    const char *key = get_key(server, &nkey, &packet);

    lcb_uint16_t status = ntohs(res->response.status);
    lcb_error_t rc = map_error(root, status);

    switch (res->response.opcode) {
    case PROTOCOL_BINARY_CMD_ADD:
        op = LCB_ADD;
        break;
    case PROTOCOL_BINARY_CMD_REPLACE:
        op = LCB_REPLACE;
        break;
    case PROTOCOL_BINARY_CMD_SET:
        op = LCB_SET;
        break;
    case PROTOCOL_BINARY_CMD_APPEND:
        op = LCB_APPEND;
        break;
    case PROTOCOL_BINARY_CMD_PREPEND:
        op = LCB_PREPEND;
        break;
    default:
        /*
        ** It is impossible to get here (since we're called from our
        ** lookup table... If we _DO_ get here, it must be a development
        ** version where the developer isn't done yet (and should be
        ** forced to think about what to do...)
        */
        lcb_error_handler(root, LCB_EINTERNAL,
                          "Internal error. Received an illegal command opcode");
        abort();
    }

    if (key == NULL) {
        lcb_error_handler(server->instance, LCB_EINTERNAL,
                          NULL);
    } else {
        lcb_store_resp_t resp;
        setup_lcb_store_resp_t(&resp, key, nkey, res->response.cas);
        TRACE_STORE_END(res->response.opaque, command_data->vbucket,
                        res->response.opcode, rc, &resp);
        root->callbacks.store(root, command_data->cookie, op, rc, &resp);
        release_key(server, packet);
    }
}
示例#4
0
lcb_error_t lcb_apply_vbucket_config(lcb_t instance, VBUCKET_CONFIG_HANDLE config)
{
    lcb_uint16_t ii, max, buii;
    lcb_size_t num;
    lcb_error_t err;

    instance->vbucket_config = config;
    instance->weird_things = 0;
    num = (lcb_size_t)vbucket_config_get_num_servers(config);

    /* servers array should be freed in the caller */
    instance->servers = calloc(num, sizeof(lcb_server_t));
    if (instance->servers == NULL) {
        return lcb_error_handler(instance,
                                 LCB_CLIENT_ENOMEM, "Failed to allocate memory");
    }
    instance->nservers = num;
    lcb_free_backup_nodes(instance);
    instance->backup_nodes = calloc(num + 1, sizeof(char *));

    if (instance->backup_nodes == NULL) {
        return lcb_error_handler(instance,
                                 LCB_CLIENT_ENOMEM, "Failed to allocate memory");
    }

    err = setup_sasl_params(instance);
    if (err != LCB_SUCCESS) {
        return lcb_error_handler(instance, err, "sasl setup");
    }

    for (buii = 0, ii = 0; ii < num; ++ii) {
        instance->servers[ii].instance = instance;
        err = lcb_server_initialize(instance->servers + ii, (int)ii);
        if (err != LCB_SUCCESS) {
            return lcb_error_handler(instance, err, "Failed to initialize server");
        }
        instance->backup_nodes[buii] = instance->servers[ii].rest_api_server;
        if (instance->randomize_bootstrap_nodes) {
            /* swap with random position < ii */
            if (buii > 0) {
                lcb_size_t nn = (lcb_size_t)(gethrtime() >> 10) % buii;
                char *pp = instance->backup_nodes[buii];
                instance->backup_nodes[ii] = instance->backup_nodes[nn];
                instance->backup_nodes[nn] = pp;
            }
        }
        buii++;
    }
示例#5
0
void lcb_server_connected(lcb_server_t *server)
{
    lcb_connection_t conn = &server->connection;
    server->connection_ready = 1;

    if (server->pending.nbytes > 0) {
        /*
        ** @todo we might want to do this a bit more optimal later on..
        **       We're only using the pending ringbuffer while we're
        **       doing the SASL auth, so it shouldn't contain that
        **       much data..
        */
        ringbuffer_t copy = server->pending;
        ringbuffer_reset(&server->cmd_log);
        ringbuffer_reset(&server->output_cookies);
        ringbuffer_reset(conn->output);
        if (!ringbuffer_append(&server->pending, conn->output) ||
                !ringbuffer_append(&server->pending_cookies, &server->output_cookies) ||
                !ringbuffer_append(&copy, &server->cmd_log)) {
            ringbuffer_reset(&server->cmd_log);
            ringbuffer_reset(&server->output_cookies);
            lcb_server_release_connection(server, LCB_CLIENT_ENOMEM);
            lcb_connection_cleanup(conn);
            lcb_error_handler(server->instance, LCB_CLIENT_ENOMEM, NULL);
            return;
        }

        ringbuffer_reset(&server->pending);
        ringbuffer_reset(&server->pending_cookies);
        lcb_assert(conn->output->nbytes);
        lcb_server_send_packets(server);
    }
}
示例#6
0
static void getq_response_handler(lcb_server_t *server, packet_info *info)
{
    lcb_t root = server->instance;
    char *packet;
    lcb_uint16_t nkey;
    const char *key = get_key(server, &nkey, &packet);
    lcb_error_t rc;
    lcb_get_resp_t resp;

    fprintf(stderr, "\n The datatype is ...%d", PACKET_DATATYPE(info));

    if (key == NULL) {
        lcb_error_handler(server->instance, LCB_EINTERNAL, NULL);
        return;

    } else if (PACKET_STATUS(info) == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
        const protocol_binary_response_getq *getq = PACKET_EPHEMERAL_START(info);
        rc = LCB_SUCCESS;
        setup_lcb_get_resp_t(&resp, key, nkey,
                             PACKET_VALUE(info), PACKET_NVALUE(info),
                             ntohl(getq->message.body.flags),
                             PACKET_CAS(info),
                             PACKET_DATATYPE(info));

    } else {
        rc = map_error(root, PACKET_STATUS(info));
        setup_lcb_get_resp_t(&resp, key, nkey, NULL, 0, 0, 0, 0);
    }

    root->callbacks.get(root, info->ct.cookie, rc, &resp);
    release_key(server, packet);
}
示例#7
0
static void arithmetic_response_handler(lcb_server_t *server,
                                        struct lcb_command_data_st *command_data,
                                        protocol_binary_response_header *res)
{
    lcb_t root = server->instance;
    lcb_uint16_t status = ntohs(res->response.status);
    lcb_error_t rc = map_error(root, status);
    char *packet;
    lcb_uint16_t nkey;
    const char *key = get_key(server, &nkey, &packet);
    lcb_arithmetic_resp_t resp;
    lcb_uint64_t value = 0;

    if (key == NULL) {
        lcb_error_handler(server->instance, LCB_EINTERNAL,
                          NULL);
        return ;
    }

    if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
        memcpy(&value, res + 1, sizeof(value));
        value = ntohll(value);
    }

    setup_lcb_arithmetic_resp_t(&resp, key, nkey, value, res->response.cas);
    TRACE_ARITHMETIC_END(res->response.opaque, command_data->vbucket,
                         res->response.opcode, rc, &resp);
    root->callbacks.arithmetic(root, command_data->cookie, rc, &resp);
    release_key(server, packet);
}
示例#8
0
static void arithmetic_response_handler(lcb_server_t *server,
                                        packet_info *info)
{
    lcb_t root = server->instance;
    lcb_uint16_t status = PACKET_STATUS(info);
    lcb_error_t rc = map_error(root, status);
    char *packet;
    lcb_uint16_t nkey;
    const char *key = get_key(server, &nkey, &packet);
    lcb_arithmetic_resp_t resp;
    lcb_uint64_t value = 0;
    struct lcb_command_data_st *command_data = &info->ct;

    if (key == NULL) {
        lcb_error_handler(server->instance, LCB_EINTERNAL,
                          NULL);
        return ;
    }

    if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
        memcpy(&value, info->payload, sizeof(value));
        value = ntohll(value);
    }

    setup_lcb_arithmetic_resp_t(&resp, key, nkey, value, PACKET_CAS(info));
    PACKET_TRACE(TRACE_ARITHMETIC_END, info, rc, &resp);
    root->callbacks.arithmetic(root, command_data->cookie, rc, &resp);
    release_key(server, packet);
}
示例#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 (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);
}
示例#10
0
LIBCOUCHBASE_API
lcb_error_t lcb_compact(lcb_t instance,
                      const void *command_cookie, uint16_t vb, uint64_t purge_before_ts, uint64_t purge_before_seq, uint8_t drop_deletes)
{
    
    fprintf(stderr,"inside compact method..\n");
    lcb_server_t *server;
    protocol_binary_request_hello req;
    lcb_size_t headersize;
    
    server = instance->servers;
    uint16_t keylen = 0; 
    uint32_t bodylen = 0; 
    
    //const void *key = useragent;
    fprintf(stderr,"setting the useragent..\n");
    memset(&req, 0, sizeof(req));
    req.message.header.request.magic = PROTOCOL_BINARY_REQ;
    req.message.header.request.opcode = PROTOCOL_BINARY_CMD_COMPACTDB;
    req.message.header.request.keylen = ntohs(keylen);
    req.message.header.request.extlen = 24;
    req.message.header.request.vbucket = ntohs((lcb_uint16_t)vb);
    req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
    req.message.header.request.opaque = ++instance->seqno;
        
    struct compact_st {
 
       uint64_t pbs;
       uint64_t pbseq;
       uint8_t  dds;
       uint8_t bytes[7];

    };
    struct compact_st* compact_t;
    compact_t = malloc(sizeof(struct compact_st));
    compact_t->pbs = htonll(purge_before_ts);
    compact_t->pbseq = htonll(purge_before_seq);
    compact_t->dds = drop_deletes;
    
    //uint8_t bytes[24];
    
    // Make it known that this was a success. 
    lcb_error_handler(instance, LCB_SUCCESS, NULL);
    
    req.message.header.request.bodylen = htonl(bodylen);
    //fprintf(stderr,"after setting bodylen..");
     
    lcb_server_start_packet(server, NULL, &req, sizeof(req.message.header));
    //fprintf(stderr,"after starting packet.."); 
    lcb_server_write_packet(server, compact_t, (lcb_size_t)sizeof(struct compact_st));
    //fprintf(stderr,"after writing key.."); 
    // lcb_server_write_packet(server, compact_t, (lcb_size_t)sizeof(bytes));
    //fprintf(stderr,"after writing feature.."); 
    lcb_server_end_packet(server);
    //fprintf(stderr,"after end packet.."); 
    lcb_server_send_packets(server);
    //fprintf(stderr,"after sending packet.."); 
    
    return lcb_synchandler_return(instance, LCB_SUCCESS);
}
示例#11
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;
}
示例#12
0
/**
 * Get a pointer to the key. If the buffer isn't continous we need to
 * allocate a temporary chunk of memory and copy the packet over there.
 * packet will return the pointer to the newly allocated packet or
 * NULL if we didn't have to allocate anything.
 *
 * @param server the server owning the key
 * @param nkey the number of bytes in the key
 * @param packet where to store the result
 * @return pointer to the key
 */
static const char *get_key(lcb_server_t *server, lcb_uint16_t *nkey,
                           char **packet)
{
    protocol_binary_request_header req;
    lcb_size_t nr = ringbuffer_peek(&server->cmd_log,
                                    req.bytes, sizeof(req));
    lcb_size_t packetsize = ntohl(req.request.bodylen) + (lcb_uint32_t)sizeof(req);
    char *keyptr;
    *packet = server->cmd_log.read_head;
    lcb_assert(nr == sizeof(req));

    *nkey = ntohs(req.request.keylen);
    keyptr = *packet + sizeof(req) + req.request.extlen;
    *packet = NULL;

    if (!ringbuffer_is_continous(&server->cmd_log,
                                 RINGBUFFER_READ,
                                 packetsize)) {
        *packet = malloc(packetsize);
        if (*packet == NULL) {
            lcb_error_handler(server->instance, LCB_CLIENT_ENOMEM,
                              NULL);
            return NULL;
        }

        nr = ringbuffer_peek(&server->cmd_log, *packet, packetsize);
        if (nr != packetsize) {
            lcb_error_handler(server->instance, LCB_EINTERNAL,
                              NULL);
            free(*packet);
            return NULL;
        }
        keyptr = *packet + sizeof(req) + req.request.extlen;
    }

    return keyptr;
}
示例#13
0
/**
 * Schedule a connection to the server
 */
void lcb_server_connect(lcb_server_t *server)
{
    lcb_connection_t conn = &server->connection;
    conn->on_connect_complete = lcb_server_connect_handler;
    conn->on_timeout = server_timeout_handler;
    conn->evinfo.handler = lcb_server_v0_event_handler;
    conn->completion.read = lcb_server_v1_read_handler;
    conn->completion.write = lcb_server_v1_write_handler;
    conn->completion.error = lcb_server_v1_error_handler;
    conn->timeout.usec = server->instance->config.operation_timeout;

    if (lcb_connection_reset_buffers(&server->connection) != LCB_SUCCESS) {
        lcb_error_handler(server->instance, LCB_CLIENT_ENOMEM, NULL);
    }

    lcb_connection_start(conn, LCB_CONNSTART_NOCB | LCB_CONNSTART_ASYNCERR);
}
示例#14
0
static void delete_response_handler(lcb_server_t *server, packet_info *info)
{
    lcb_t root = server->instance;
    lcb_error_t rc = map_error(root, PACKET_STATUS(info));
    char *packet;
    lcb_uint16_t nkey;
    const char *key = get_key(server, &nkey, &packet);

    if (key == NULL) {
        lcb_error_handler(server->instance, LCB_EINTERNAL, NULL);
    } else {
        lcb_remove_resp_t resp;
        setup_lcb_remove_resp_t(&resp, key, nkey, PACKET_CAS(info));
        root->callbacks.remove(root, info->ct.cookie, rc, &resp);
        release_key(server, packet);
    }
}
示例#15
0
static lcb_error_t start_connection(lcb_t instance)
{
    lcb_error_t rc;
    char *ptr;
    lcb_connection_result_t connres;
    lcb_connection_t conn = &instance->bootstrap.via.http.connection;

    /**
     * First, close the connection, if there's an open socket from a previous
     * one.
     */
    lcb_connection_close(conn);
    reset_stream_state(instance);

    conn->on_connect_complete = connect_done_handler;
    conn->evinfo.handler = config_v0_handler;
    conn->completion.read = config_v1_read_handler;
    conn->completion.write = config_v1_write_handler;
    conn->completion.error = config_v1_error_handler;
    conn->on_timeout = lcb_bootstrap_timeout_handler;
    conn->timeout.usec = instance->config.bootstrap_timeout;
    rc = lcb_init_next_host(instance, 8091);
    if (rc != LCB_SUCCESS) {
        return rc;
    }
    instance->last_error = LCB_SUCCESS;

    /* We need to fix the host part... */
    ptr = strstr(instance->bootstrap.via.http.uri, LCB_LAST_HTTP_HEADER);
    lcb_assert(ptr);
    ptr += strlen(LCB_LAST_HTTP_HEADER);
    sprintf(ptr, "Host: %s:%s\r\n\r\n", conn->host, conn->port);
    connres = lcb_connection_start(conn, 1);
    if (connres == LCB_CONN_ERROR) {
        lcb_connection_close(conn);
        return lcb_error_handler(instance, LCB_CONNECT_ERROR,
                                 "Couldn't schedule connection");
    }

    if (instance->config.syncmode == LCB_SYNCHRONOUS) {
        lcb_wait(instance);
    }

    return instance->last_error;
}
示例#16
0
static void sasl_step_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 {
        lcb_error_handler(server->instance, LCB_AUTH_ERROR,
                          "SASL authentication failed");
    }
    (void)command_data;
}
示例#17
0
LIBCOUCHBASE_API
lcb_error_t lcb_hello(lcb_t instance,
                      const void *command_cookie)
{

        fprintf(stderr,"inside hello method..\n");
        lcb_server_t *server;
        protocol_binary_request_hello req;
        lcb_size_t headersize;
        lcb_size_t bodylen;

        server = instance->servers; 
        const char *useragent = "my prototype";
        uint16_t feature = htons(PROTOCOL_BINARY_FEATURE_DATATYPE);

        /*const void *key = useragent;*/
        fprintf(stderr,"setting the useragent..\n"); 
        memset(&req, 0, sizeof(req));
        req.message.header.request.magic = PROTOCOL_BINARY_REQ;
        req.message.header.request.opcode = PROTOCOL_BINARY_CMD_HELLO;
        req.message.header.request.keylen = ntohs(strlen(useragent));
        req.message.header.request.extlen = 0;
        req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
        req.message.header.request.opaque = ++instance->seqno;

        /* Make it known that this was a success. */
        lcb_error_handler(instance, LCB_SUCCESS, NULL);

        req.message.header.request.bodylen = htonl((uint32_t)(strlen(useragent) + sizeof(feature)));
        /*fprintf(stderr,"after setting bodylen..");*/ 

        lcb_server_start_packet(server, NULL, &req, sizeof(req.message.header));
        /*fprintf(stderr,"after starting packet..");*/ 
        lcb_server_write_packet(server, useragent, (lcb_size_t)strlen(useragent));
        /*fprintf(stderr,"after writing key.."); */
        lcb_server_write_packet(server, &feature, (lcb_size_t)sizeof(feature));
        /*fprintf(stderr,"after writing feature.."); */
        lcb_server_end_packet(server);
        /*fprintf(stderr,"after end packet.."); */
        lcb_server_send_packets(server);
        /*fprintf(stderr,"after sending packet.."); */

    return lcb_synchandler_return(instance, LCB_SUCCESS);
}
示例#18
0
static lcb_error_t setup_sasl_params(lcb_t instance)
{
    const char *passwd;
    sasl_callback_t sasl_callbacks[4];

    sasl_callbacks[0].id = SASL_CB_USER;
    sasl_callbacks[0].proc = (int( *)(void)) &sasl_get_username;
    sasl_callbacks[0].context = instance;
    sasl_callbacks[1].id = SASL_CB_AUTHNAME;
    sasl_callbacks[1].proc = (int( *)(void)) &sasl_get_username;
    sasl_callbacks[1].context = instance;
    sasl_callbacks[2].id = SASL_CB_PASS;
    sasl_callbacks[2].proc = (int( *)(void)) &sasl_get_password;
    sasl_callbacks[2].context = instance;
    sasl_callbacks[3].id = SASL_CB_LIST_END;
    sasl_callbacks[3].proc = NULL;
    sasl_callbacks[3].context = NULL;

    instance->sasl.name = instance->username;
    memset(instance->sasl.password.buffer, 0,
           sizeof(instance->sasl.password.buffer));
    passwd = instance->password;

    if (passwd) {
        unsigned long pwlen;
        lcb_size_t maxlen;

        pwlen = (unsigned long)strlen(passwd);
        maxlen = sizeof(instance->sasl.password.buffer) -
                 offsetof(sasl_secret_t, data);

        instance->sasl.password.secret.len = pwlen;

        if (pwlen < maxlen) {
            memcpy(instance->sasl.password.secret.data, passwd, pwlen);
        } else {
            return lcb_error_handler(instance, LCB_EINVAL, "Password too long");
        }
    }

    memcpy(instance->sasl.callbacks, sasl_callbacks, sizeof(sasl_callbacks));
    return LCB_SUCCESS;
}
示例#19
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);
}
示例#20
0
static void unlock_response_handler(lcb_server_t *server,
                                    packet_info *info)
{
    lcb_t root = server->instance;
    lcb_uint16_t status = PACKET_STATUS(info);
    char *packet;
    lcb_uint16_t nkey;
    struct lcb_command_data_st *command_data = &info->ct;
    const char *key = get_key(server, &nkey, &packet);
    lcb_error_t rc = map_error(root, status);

    if (key == NULL) {
        lcb_error_handler(server->instance, LCB_EINTERNAL, NULL);
    } else {
        lcb_unlock_resp_t resp;
        setup_lcb_unlock_resp_t(&resp, key, nkey);
        root->callbacks.unlock(root, command_data->cookie, rc, &resp);
        release_key(server, packet);
    }
}
示例#21
0
static void timeout_handler(lcb_connection_t conn, lcb_error_t err)
{
    lcb_t instance = (lcb_t)conn->data;
    const char *msg = "Configuration update timed out";
    lcb_assert(instance->config.state != LCB_CONFSTATE_CONFIGURED);

    if (instance->config.state == LCB_CONFSTATE_UNINIT) {
        /**
         * If lcb_connect was called explicitly then it means there are no
         * pending operations and we should just break out because we have
         * no valid configuration.
         */
        lcb_error_handler(instance, LCB_CONNECT_ERROR,
                          "Could not connect to server within allotted time");
        lcb_maybe_breakout(instance);
        return;
    }

    lcb_bootstrap_error(instance, err, msg, 0);
}
示例#22
0
static void touch_response_handler(lcb_server_t *server,
                                   packet_info *info)
{
    lcb_t root = server->instance;
    char *packet;
    lcb_uint16_t nkey;
    const char *key = get_key(server, &nkey, &packet);
    lcb_uint16_t status = PACKET_STATUS(info);
    lcb_error_t rc = map_error(root, status);

    if (key == NULL) {
        lcb_error_handler(server->instance, LCB_EINTERNAL,
                          NULL);
    } else {
        lcb_touch_resp_t resp;
        setup_lcb_touch_resp_t(&resp, key, nkey, PACKET_CAS(info));
        PACKET_TRACE(TRACE_TOUCH_END, info, rc, &resp);
        root->callbacks.touch(root, info->ct.cookie, rc, &resp);
        release_key(server, packet);
    }
}
示例#23
0
static void initial_bootstrap_error(lcb_t instance,
                                    lcb_error_t err,
                                    const char *errinfo)
{
    instance->last_error = lcb_confmon_last_error(instance->confmon);
    if (instance->last_error == LCB_SUCCESS) {
        instance->last_error = err;
    }

    instance->bootstrap->active = 0 ;
    lcb_error_handler(instance, instance->last_error, errinfo);
    lcb_log(LOGARGS(instance, ERR),
            "Failed to bootstrap client=%p. Code=0x%x, Message=%s",
            (void *)instance, err, errinfo);
    if (instance->bootstrap->timer) {
        lcb_timer_destroy(instance, instance->bootstrap->timer);
        instance->bootstrap->timer = NULL;
    }

    lcb_maybe_breakout(instance);
}
示例#24
0
static void unlock_response_handler(lcb_server_t *server,
                                    struct lcb_command_data_st *command_data,
                                    protocol_binary_response_header *res)
{
    lcb_t root = server->instance;
    lcb_uint16_t status = ntohs(res->response.status);
    char *packet;
    lcb_uint16_t nkey;
    const char *key = get_key(server, &nkey, &packet);
    lcb_error_t rc = map_error(root, status);

    if (key == NULL) {
        lcb_error_handler(server->instance, LCB_EINTERNAL,
                          NULL);
    } else {
        lcb_unlock_resp_t resp;
        setup_lcb_unlock_resp_t(&resp, key, nkey);
        TRACE_UNLOCK_END(res->response.opaque, command_data->vbucket, rc, &resp);
        root->callbacks.unlock(root, command_data->cookie, rc, &resp);
        release_key(server, packet);
    }
}
示例#25
0
static void getq_response_handler(lcb_server_t *server,
                                  struct lcb_command_data_st *command_data,
                                  protocol_binary_response_header *res)
{
    lcb_t root = server->instance;
    protocol_binary_response_getq *getq = (void *)res;
    lcb_uint16_t status = ntohs(res->response.status);
    lcb_size_t nbytes = ntohl(res->response.bodylen);
    char *packet;
    lcb_uint16_t nkey;
    const char *key = get_key(server, &nkey, &packet);
    lcb_error_t rc = map_error(root, status);

    nbytes -= res->response.extlen;
    if (key == NULL) {
        lcb_error_handler(server->instance, LCB_EINTERNAL, NULL);
        return;
    } else if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
        const char *bytes = (const char *)res;
        lcb_get_resp_t resp;
        bytes += sizeof(getq->bytes);
        setup_lcb_get_resp_t(&resp, key, nkey, bytes, nbytes,
                             ntohl(getq->message.body.flags),
                             res->response.cas, res->response.datatype);
        TRACE_GET_END(res->response.opaque, command_data->vbucket,
                      res->response.opcode, rc, &resp);
        root->callbacks.get(root, command_data->cookie, rc, &resp);
    } else {
        lcb_get_resp_t resp;
        setup_lcb_get_resp_t(&resp, key, nkey, NULL, 0, 0,
                             0, res->response.datatype);
        TRACE_GET_END(res->response.opaque, command_data->vbucket,
                      res->response.opcode, rc, &resp);
        root->callbacks.get(root, command_data->cookie, rc, &resp);
    }
    release_key(server, packet);
}
示例#26
0
/**
 * Spool a store request
 *
 * @author Trond Norbye
 * @todo add documentation
 * @todo fix the expiration so that it works relative/absolute etc..
 * @todo we might want to wait to write the data to the sockets if the
 *       user want to run a batch of store requests?
 */
LIBCOUCHBASE_API
lcb_error_t lcb_store(lcb_t instance,
                      const void *command_cookie,
                      lcb_size_t num,
                      const lcb_store_cmd_t *const *items)
{
    lcb_size_t ii;
    lcb_error_t err;
    vbcheck_ctx vbc;

    VBC_SANITY(instance);
    err = vbcheck_ctx_init(&vbc, instance, num);
    if (err != LCB_SUCCESS) {
        return lcb_synchandler_return(instance, err);
    }

    for (ii = 0; ii < num; ii++) {
        const void *k;
        lcb_size_t n;
        VBC_GETK0(items[ii], k, n);
        err = vbcheck_populate(&vbc, instance, ii, k, n);
        if (err != LCB_SUCCESS) {
            vbcheck_ctx_clean(&vbc);
            return lcb_synchandler_return(instance, err);
        }
    }

    for (ii = 0; ii < num; ++ii) {
        lcb_server_t *server;
        protocol_binary_request_set req;
        lcb_size_t headersize;
        lcb_size_t bodylen;

        lcb_storage_t operation = items[ii]->v.v0.operation;
        const void *key = items[ii]->v.v0.key;
        lcb_size_t nkey = items[ii]->v.v0.nkey;
        lcb_cas_t cas = items[ii]->v.v0.cas;
        lcb_uint32_t flags = items[ii]->v.v0.flags;
        lcb_time_t exp = items[ii]->v.v0.exptime;
        const void *bytes = items[ii]->v.v0.bytes;
        lcb_size_t nbytes = items[ii]->v.v0.nbytes;
        vbcheck_keyinfo *ki = vbc.ptr_ki + ii;
        server = instance->servers + ki->ix;

        memset(&req, 0, sizeof(req));
        req.message.header.request.magic = PROTOCOL_BINARY_REQ;
        req.message.header.request.keylen = ntohs((lcb_uint16_t)nkey);
        req.message.header.request.extlen = 8;
        req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
        req.message.header.request.vbucket = ntohs(ki->vb);
        req.message.header.request.opaque = ++instance->seqno;
        req.message.header.request.cas = cas;
        req.message.body.flags = htonl(flags);
        req.message.body.expiration = htonl((lcb_uint32_t)exp);

        headersize = sizeof(req.bytes);
        switch (operation) {
        case LCB_ADD:
            req.message.header.request.opcode = PROTOCOL_BINARY_CMD_ADD;
            break;
        case LCB_REPLACE:
            req.message.header.request.opcode = PROTOCOL_BINARY_CMD_REPLACE;
            break;
        case LCB_SET:
            req.message.header.request.opcode = PROTOCOL_BINARY_CMD_SET;
            break;
        case LCB_APPEND:
            req.message.header.request.opcode = PROTOCOL_BINARY_CMD_APPEND;
            req.message.header.request.extlen = 0;
            headersize -= 8;
            break;
        case LCB_PREPEND:
            req.message.header.request.opcode = PROTOCOL_BINARY_CMD_PREPEND;
            req.message.header.request.extlen = 0;
            headersize -= 8;
            break;
        default:
            /* We were given an unknown storage operation. */
            return lcb_synchandler_return(instance,
                                          lcb_error_handler(instance, LCB_EINVAL,
                                                            "Invalid value passed as storage operation"));
        }

        /* Make it known that this was a success. */
        lcb_error_handler(instance, LCB_SUCCESS, NULL);

        bodylen = nkey + nbytes + req.message.header.request.extlen;
        req.message.header.request.bodylen = htonl((lcb_uint32_t)bodylen);

        lcb_server_start_packet(server, command_cookie, &req, headersize);
        lcb_server_write_packet(server, key, nkey);
        lcb_server_write_packet(server, bytes, nbytes);
        lcb_server_end_packet(server);
    }

    for (ii = 0; ii < instance->nservers; ii++) {
        if (vbc.ptr_srv[ii]) {
            lcb_server_send_packets(instance->servers + ii);
        }
    }
    vbcheck_ctx_clean(&vbc);
    return lcb_synchandler_return(instance, LCB_SUCCESS);
}
示例#27
0
/**
 * Spool a store request
 *
 * @author Trond Norbye
 * @todo add documentation
 * @todo fix the expiration so that it works relative/absolute etc..
 * @todo we might want to wait to write the data to the sockets if the
 *       user want to run a batch of store requests?
 */
LIBCOUCHBASE_API
lcb_error_t lcb_store(lcb_t instance,
                      const void *command_cookie,
                      lcb_size_t num,
                      const lcb_store_cmd_t *const *items)
{
    lcb_size_t ii;

    /* we need a vbucket config before we can start getting data.. */
    if (instance->vbucket_config == NULL) {
        switch (instance->type) {
        case LCB_TYPE_CLUSTER:
            return lcb_synchandler_return(instance, LCB_EBADHANDLE);
        case LCB_TYPE_BUCKET:
        default:
            return lcb_synchandler_return(instance, LCB_CLIENT_ETMPFAIL);
        }
    }

    for (ii = 0; ii < num; ++ii) {
        lcb_server_t *server;
        protocol_binary_request_set req;
        lcb_size_t headersize;
        lcb_size_t bodylen;
        int vb, idx;

        lcb_storage_t operation = items[ii]->v.v0.operation;
        const void *key = items[ii]->v.v0.key;
        lcb_size_t nkey = items[ii]->v.v0.nkey;
        lcb_cas_t cas = items[ii]->v.v0.cas;
        lcb_uint32_t flags = items[ii]->v.v0.flags;
        lcb_time_t exp = items[ii]->v.v0.exptime;
        const void *bytes = items[ii]->v.v0.bytes;
        lcb_size_t nbytes = items[ii]->v.v0.nbytes;
        const void *hashkey = items[ii]->v.v0.hashkey;
        lcb_size_t nhashkey = items[ii]->v.v0.nhashkey;

        if (nhashkey == 0) {
            hashkey = key;
            nhashkey = nkey;
        }

        (void)vbucket_map(instance->vbucket_config, hashkey, nhashkey,
                          &vb, &idx);
        if (idx < 0 || idx > (int)instance->nservers) {
            return lcb_synchandler_return(instance, LCB_NO_MATCHING_SERVER);
        }
        server = instance->servers + idx;

        memset(&req, 0, sizeof(req));
        req.message.header.request.magic = PROTOCOL_BINARY_REQ;
        req.message.header.request.keylen = ntohs((lcb_uint16_t)nkey);
        req.message.header.request.extlen = 8;
        req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
        req.message.header.request.vbucket = ntohs((lcb_uint16_t)vb);
        req.message.header.request.opaque = ++instance->seqno;
        req.message.header.request.cas = cas;
        req.message.body.flags = htonl(flags);
        req.message.body.expiration = htonl((lcb_uint32_t)exp);

        headersize = sizeof(req.bytes);
        switch (operation) {
        case LCB_ADD:
            req.message.header.request.opcode = PROTOCOL_BINARY_CMD_ADD;
            break;
        case LCB_REPLACE:
            req.message.header.request.opcode = PROTOCOL_BINARY_CMD_REPLACE;
            break;
        case LCB_SET:
            req.message.header.request.opcode = PROTOCOL_BINARY_CMD_SET;
            break;
        case LCB_APPEND:
            req.message.header.request.opcode = PROTOCOL_BINARY_CMD_APPEND;
            req.message.header.request.extlen = 0;
            headersize -= 8;
            break;
        case LCB_PREPEND:
            req.message.header.request.opcode = PROTOCOL_BINARY_CMD_PREPEND;
            req.message.header.request.extlen = 0;
            headersize -= 8;
            break;
        default:
            /* We were given an unknown storage operation. */
            return lcb_synchandler_return(instance,
                                          lcb_error_handler(instance, LCB_EINVAL,
                                                            "Invalid value passed as storage operation"));
        }

        /* Make it known that this was a success. */
        lcb_error_handler(instance, LCB_SUCCESS, NULL);

        bodylen = nkey + nbytes + req.message.header.request.extlen;
        req.message.header.request.bodylen = htonl((lcb_uint32_t)bodylen);

        TRACE_STORE_BEGIN(&req, key, nkey, bytes, nbytes, flags, exp);
        lcb_server_start_packet(server, command_cookie, &req, headersize);
        lcb_server_write_packet(server, key, nkey);
        lcb_server_write_packet(server, bytes, nbytes);
        lcb_server_end_packet(server);
        lcb_server_send_packets(server);
    }

    return lcb_synchandler_return(instance, LCB_SUCCESS);
}
示例#28
0
static void observe_response_handler(lcb_server_t *server,
                                     packet_info *info)
{
    lcb_t root = server->instance;
    lcb_error_t rc = map_error(root, PACKET_STATUS(info));
    lcb_uint32_t ttp;
    lcb_uint32_t ttr;
    lcb_size_t pos;

    VBUCKET_CONFIG_HANDLE config;
    const char *end, *ptr;

    /**
     * If we have an error we must decode the request instead
     */
    if (rc != LCB_SUCCESS) {
        protocol_binary_request_header req;
        lcb_size_t nr;

        nr = ringbuffer_peek(&server->cmd_log, req.bytes, sizeof(req.bytes));
        if (nr != sizeof(req.bytes)) {
            lcb_error_handler(server->instance, LCB_EINTERNAL, NULL);
            abort();
        }

        if (req.request.bodylen) {
            lcb_size_t npacket = sizeof(req.bytes) + ntohl(req.request.bodylen);
            char *packet = server->cmd_log.read_head;
            int allocated = 0;

            if (!ringbuffer_is_continous(&server->cmd_log, RINGBUFFER_READ, npacket)) {
                packet = malloc(npacket);
                if (packet == NULL) {
                    lcb_error_handler(root, LCB_CLIENT_ENOMEM, NULL);
                    abort();
                }
                nr = ringbuffer_peek(&server->cmd_log, packet, npacket);
                if (nr != npacket) {
                    lcb_error_handler(root, LCB_EINTERNAL, NULL);
                    free(packet);
                    abort();
                }
                allocated = 1;
            }
            lcb_failout_observe_request(server, &info->ct, packet, npacket, rc);
            if (allocated) {
                free(packet);
            }
        }
        return;
    }

    /** The CAS field is split into TTP/TTR values */
    ptr = (char *)&info->res.response.cas;
    memcpy(&ttp, ptr, sizeof(ttp));
    memcpy(&ttr, ptr + sizeof(ttp), sizeof(ttp));

    ttp = ntohl(ttp);
    ttr = ntohl(ttr);

    /** Actual payload sequence of (vb, nkey, key). Repeats multiple times */
    ptr = info->payload;
    end = (char *)ptr + PACKET_NBODY(info);
    config = root->vbucket_config;

    for (pos = 0; ptr < end; pos++) {
        lcb_cas_t cas;
        lcb_uint8_t obs;
        lcb_uint16_t nkey, vb;
        const char *key;
        lcb_observe_resp_t resp;

        memcpy(&vb, ptr, sizeof(vb));
        vb = ntohs(vb);
        ptr += sizeof(vb);
        memcpy(&nkey, ptr, sizeof(nkey));
        nkey = ntohs(nkey);
        ptr += sizeof(nkey);
        key = (const char *)ptr;
        ptr += nkey;
        obs = *((lcb_uint8_t *)ptr);
        ptr += sizeof(obs);
        memcpy(&cas, ptr, sizeof(cas));
        ptr += sizeof(cas);

        setup_lcb_observe_resp_t(&resp, key, nkey, cas, obs,
                                 server->index == vbucket_get_master(config, vb),
                                 ttp, ttr);
        PACKET_TRACE(TRACE_OBSERVE_PROGRESS, info, rc, &resp);
        lcb_observe_invoke_callback(root, &info->ct, rc, &resp);
    }

    /* run callback with null-null-null to signal the end of transfer */
    if ((info->ct.flags & LCB_CMD_F_OBS_BCAST) &&
            lcb_lookup_server_with_command(root, CMD_OBSERVE,
                                           PACKET_OPAQUE(info), server) < 0) {

        lcb_observe_resp_t resp;
        memset(&resp, 0, sizeof(resp));
        PACKET_TRACE_NORES(TRACE_OBSERVE_END, info, rc);
        lcb_observe_invoke_callback(root, &info->ct, LCB_SUCCESS, &resp);
    }
}
示例#29
0
static void get_replica_response_handler(lcb_server_t *server,
                                         packet_info *info)
{
    lcb_t root = server->instance;
    lcb_uint16_t nkey;
    const char *key;
    char *packet;
    lcb_uint16_t status = PACKET_STATUS(info);

    lcb_error_t rc = map_error(root, status);

    /**
     * Success? always perform the callback
     */
    if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
        const protocol_binary_response_get *get = PACKET_EPHEMERAL_START(info);
        lcb_get_resp_t resp;
        setup_lcb_get_resp_t(&resp,
                             PACKET_KEY(info), PACKET_NKEY(info),
                             PACKET_VALUE(info), PACKET_NVALUE(info),
                             ntohl(get->message.body.flags),
                             PACKET_CAS(info),
                             PACKET_DATATYPE(info));
        root->callbacks.get(root, info->ct.cookie, rc, &resp);
        return;
    }

    key = get_key(server, &nkey, &packet);

    /**
     * Following code handles errors.
     */
    if (info->ct.replica == -1) {
        /* Perform the callback. Either SELECT or ALL */
        lcb_get_resp_t resp;
        setup_lcb_get_resp_t(&resp, key, nkey, NULL, 0, 0, 0, 0);
        PACKET_TRACE(TRACE_GET_END, info, rc, &resp);
        root->callbacks.get(root, info->ct.cookie, rc, &resp);
        release_key(server, packet);
        return;
    }

    /** LCB_REPLICA_FIRST */
    if (status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET) {
        /**
         * the config was updated, start from first replica.
         * Reset the iteration count
         */
        info->ct.replica = 0;
    } else {
        info->ct.replica++;
    }

    if (info->ct.replica < root->nreplicas) {
        /* try next replica */
        protocol_binary_request_get req;
        lcb_server_t *new_server;
        int idx = vbucket_get_replica(root->vbucket_config,
                                      info->ct.vbucket,
                                      info->ct.replica);
        if (idx < 0 || idx > (int)root->nservers) {
            lcb_error_handler(root, LCB_NETWORK_ERROR,
                              "GET_REPLICA: missing server");
            release_key(server, packet);
            return;
        }
        new_server = root->servers + idx;
        memset(&req, 0, sizeof(req));
        req.message.header.request.magic = PROTOCOL_BINARY_REQ;
        req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
        req.message.header.request.opcode = CMD_GET_REPLICA;
        req.message.header.request.keylen = ntohs((lcb_uint16_t)nkey);
        req.message.header.request.vbucket = ntohs(info->ct.vbucket);
        req.message.header.request.bodylen = ntohl((lcb_uint32_t)nkey);
        req.message.header.request.opaque = ++root->seqno;
        TRACE_GET_BEGIN(&req, key, nkey, 0);
        lcb_server_retry_packet(new_server, &info->ct,
                                req.bytes, sizeof(req.bytes));
        lcb_server_write_packet(new_server, key, nkey);
        lcb_server_end_packet(new_server);
        lcb_server_send_packets(new_server);
    } else {
        /* give up and report the error */
        lcb_get_resp_t resp;
        setup_lcb_get_resp_t(&resp, key, nkey, NULL, 0, 0, 0, 0);
        PACKET_TRACE(TRACE_GET_END, info, rc, &resp)
        root->callbacks.get(root, info->ct.cookie, rc, &resp);
    }

    release_key(server, packet);
}
示例#30
0
/**
 * Send a preformatted packet to the cluster
 * This prototype copies the buffers into the internal structures
 * instead of just keeping a reference...
 */
LIBCOUCHBASE_API
lcb_error_t lcb_forward_packet(lcb_t instance,
                               const void *command_cookie,
                               lcb_size_t num,
                               const lcb_packet_fwd_cmd_t *const *commands)
{
    lcb_size_t ii;

    lcb_error_handler(instance, LCB_SUCCESS, NULL);

    /* we need a vbucket config before we can start getting data.. */
    if (instance->vbucket_config == NULL) {
        switch (instance->type) {
        case LCB_TYPE_CLUSTER:
            return lcb_synchandler_return(instance, LCB_EBADHANDLE);
        case LCB_TYPE_BUCKET:
        default:
            return lcb_synchandler_return(instance, LCB_CLIENT_ETMPFAIL);
        }
    }

    /* Now handle all of the requests */
    for (ii = 0; ii < num; ++ii) {
        lcb_server_t *server;
        protocol_binary_request_no_extras *req;
        int idx;
        int vb = 0;

        /* @todo ensure that we support the current command */

        /* @todo currently the entire header needs to be in the first
         *       chunk */
        assert(commands[ii]->v.v0.buffer.iov[0].iov_len >= 24);

        /* I need to update the sequence number in the packet! */
        req = (void *)commands[ii]->v.v0.buffer.iov[0].iov_base;
        vb = ntohs(req->message.header.request.vbucket);

        if (commands[ii]->v.v0.to_master) {
            idx = vbucket_get_master(instance->vbucket_config, vb);
        } else {
            idx = vbucket_get_replica(instance->vbucket_config, vb,
                                      commands[ii]->v.v0.replica_index);
        }

        if (idx < 0 || idx > (int)instance->nservers) {
            return lcb_synchandler_return(instance, LCB_NO_MATCHING_SERVER);
        }

        server = instance->servers + idx;

        ++instance->seqno;
        /* avoid alignment crash by using memcpy */
        memcpy(&req->message.header.request.opaque, &instance->seqno, 4);

        lcb_server_start_packet(server, command_cookie,
                                commands[ii]->v.v0.buffer.iov[0].iov_base,
                                commands[ii]->v.v0.buffer.iov[0].iov_len);
        lcb_server_write_packet(server,
                                commands[ii]->v.v0.buffer.iov[1].iov_base,
                                commands[ii]->v.v0.buffer.iov[1].iov_len);
        lcb_server_end_packet(server);
        lcb_server_send_packets(server);
    }

    return lcb_synchandler_return(instance, LCB_SUCCESS);
}