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); }
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); } }
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); } }
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++; }
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(©, &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); } }
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); }
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); }
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); }
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); }
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); }
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; }
/** * 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; }
/** * 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); }
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); } }
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; }
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; }
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); }
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; }
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); }
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); } }
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); }
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); } }
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); }
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); } }
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); }
/** * 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); }
/** * 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); }
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); } }
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); }
/** * 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); }