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 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 version_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); lcb_uint32_t nvstring = PACKET_NBODY(info); const char *vstring; lcb_server_version_resp_t resp; struct lcb_command_data_st *command_data = &info->ct; if (nvstring) { vstring = info->payload; } else { vstring = NULL; } setup_lcb_server_version_resp_t(&resp, server->authority, vstring, nvstring); PACKET_TRACE(TRACE_VERSIONS_PROGRESS, info, rc, &resp); root->callbacks.version(root, command_data->cookie, rc, &resp); if (lcb_lookup_server_with_command(root, PROTOCOL_BINARY_CMD_VERSION, PACKET_OPAQUE(info), server) < 0) { memset(&resp, 0, sizeof(resp)); PACKET_TRACE_NORES(TRACE_VERSIONS_END, info, LCB_SUCCESS); root->callbacks.version(root, command_data->cookie, LCB_SUCCESS, &resp); } }
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 stat_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); lcb_server_stat_resp_t resp; struct lcb_command_data_st *command_data = &info->ct; if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) { if (!PACKET_NKEY(info)) { if (lcb_lookup_server_with_command(root, PROTOCOL_BINARY_CMD_STAT, PACKET_OPAQUE(info), server) < 0) { /* notify client that data is ready */ setup_lcb_server_stat_resp_t(&resp, NULL, NULL, 0, NULL, 0); root->callbacks.stat(root, command_data->cookie, rc, &resp); } return; } setup_lcb_server_stat_resp_t(&resp, server->authority, PACKET_KEY(info), PACKET_NKEY(info), PACKET_VALUE(info), PACKET_NVALUE(info)); root->callbacks.stat(root, command_data->cookie, rc, &resp); } else { setup_lcb_server_stat_resp_t(&resp, server->authority, NULL, 0, NULL, 0); root->callbacks.stat(root, command_data->cookie, rc, &resp); /* run callback with null-null-null to signal the end of transfer */ if (lcb_lookup_server_with_command(root, PROTOCOL_BINARY_CMD_STAT, PACKET_OPAQUE(info), server) < 0) { setup_lcb_server_stat_resp_t(&resp, NULL, NULL, 0, NULL, 0); root->callbacks.stat(root, command_data->cookie, LCB_SUCCESS, &resp); } } }
static void config_handler(lcb_server_t *server, packet_info *info) { lcb_error_t rc = map_error(server->instance, PACKET_STATUS(info)); lcb_cccp_update2(info->ct.cookie, rc, PACKET_VALUE(info), PACKET_NVALUE(info), &server->curhost); }
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 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 flush_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); lcb_flush_resp_t resp; struct lcb_command_data_st *command_data = &info->ct; setup_lcb_flush_resp_t(&resp, server->authority); root->callbacks.flush(root, command_data->cookie, rc, &resp); if (lcb_lookup_server_with_command(root, PROTOCOL_BINARY_CMD_FLUSH, PACKET_OPAQUE(info), server) < 0) { setup_lcb_flush_resp_t(&resp, NULL); root->callbacks.flush(root, command_data->cookie, LCB_SUCCESS, &resp); } }
static void verbosity_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); lcb_verbosity_resp_t resp; struct lcb_command_data_st *command_data = &info->ct; setup_lcb_verbosity_resp_t(&resp, server->authority); root->callbacks.verbosity(root, command_data->cookie, rc, &resp); /* run callback with null-null-null to signal the end of transfer */ if (lcb_lookup_server_with_command(root, PROTOCOL_BINARY_CMD_VERBOSITY, PACKET_OPAQUE(info), server) < 0) { setup_lcb_verbosity_resp_t(&resp, NULL); root->callbacks.verbosity(root, command_data->cookie, LCB_SUCCESS, &resp); } }
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); } }
LIBCOUCHBASE_API int lcb_sdresult_next(const lcb_RESPSUBDOC *resp, lcb_SDENTRY *ent, size_t *iter) { size_t iter_s = 0; const packet_info *response = (const packet_info*)resp->responses; if (!response) { return 0; } if (!iter) { /* Single response */ iter = &iter_s; } switch (PACKET_OPCODE(response)) { case PROTOCOL_BINARY_CMD_SUBDOC_MULTI_LOOKUP: return sdlookup_next(response, ent, iter); case PROTOCOL_BINARY_CMD_SUBDOC_MULTI_MUTATION: return sdmutate_next(response, ent, iter); default: if (*iter) { return 0; } *iter = 1; if (resp->rc == LCB_SUCCESS || resp->rc == LCB_SUBDOC_MULTI_FAILURE) { ent->status = map_error(NULL, PACKET_STATUS(response)); ent->value = PACKET_VALUE(response); ent->nvalue = PACKET_NVALUE(response); ent->index = 0; return 1; } else { return 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); } }
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); }
int lcb_proto_parse_single(lcb_server_t *c, hrtime_t stop) { int rv; packet_info info; protocol_binary_request_header req; lcb_size_t nr; lcb_connection_t conn = &c->connection; rv = lcb_packet_read_ringbuffer(&info, conn->input); if (rv == -1) { return -1; } else if (rv == 0) { return 0; } /* Is it already timed out? */ nr = ringbuffer_peek(&c->cmd_log, req.bytes, sizeof(req)); if (nr < sizeof(req) || /* the command log doesn't know about it */ (PACKET_OPAQUE(&info) < req.request.opaque && PACKET_OPAQUE(&info) > 0)) { /* sasl comes with zero opaque */ /* already processed. */ lcb_packet_release_ringbuffer(&info, conn->input); return 1; } nr = ringbuffer_peek(&c->output_cookies, &info.ct, sizeof(info.ct)); if (nr != sizeof(info.ct)) { lcb_error_handler(c->instance, LCB_EINTERNAL, NULL); lcb_packet_release_ringbuffer(&info, conn->input); return -1; } info.ct.vbucket = ntohs(req.request.vbucket); switch (info.res.response.magic) { case PROTOCOL_BINARY_REQ: /* * The only way to get request packets is if someone started * to send us TAP requests, and we don't support that anymore */ lcb_error_handler(c->instance, LCB_EINTERNAL, "Protocol error. someone sent us a command!"); return -1; case PROTOCOL_BINARY_RES: { int was_connected = c->connection_ready; rv = lcb_server_purge_implicit_responses(c, PACKET_OPAQUE(&info), stop, 0); if (rv != 0) { lcb_packet_release_ringbuffer(&info, conn->input); return -1; } if (c->instance->histogram) { lcb_record_metrics(c->instance, stop - info.ct.start, PACKET_OPCODE(&info)); } if (PACKET_STATUS(&info) != PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET || PACKET_OPCODE(&info) == CMD_GET_REPLICA || PACKET_OPCODE(&info) == CMD_OBSERVE) { rv = lcb_dispatch_response(c, &info); if (rv == -1) { lcb_error_handler(c->instance, LCB_EINTERNAL, "Received unknown command response"); abort(); return -1; } /* keep command and cookie until we get complete STAT response */ swallow_command(c, &info.res, was_connected); } else { rv = handle_not_my_vbucket(c, &info, &req, &info.ct); if (rv == -1) { return -1; } else if (rv == 0) { lcb_dispatch_response(c, &info); swallow_command(c, &info.res, was_connected); } } break; } default: lcb_error_handler(c->instance, LCB_PROTOCOL_ERROR, NULL); lcb_packet_release_ringbuffer(&info, conn->input); return -1; } lcb_packet_release_ringbuffer(&info, conn->input); return 1; }
/* This function is called within a loop to process a single packet. * * If a full packet is available, it will process the packet and return * PKT_READ_COMPLETE, resulting in the `on_read()` function calling this * function in a loop. * * When a complete packet is not available, PKT_READ_PARTIAL will be returned * and the `on_read()` loop will exit, scheduling any required pending I/O. */ static int try_read(lcbio_CTX *ctx, mc_SERVER *server, rdb_IOROPE *ior) { packet_info info_s, *info = &info_s; mc_PACKET *request; mc_PIPELINE *pl = &server->pipeline; unsigned pktsize = 24, is_last = 1; #define RETURN_NEED_MORE(n) \ if (mcserver_has_pending(server)) { \ lcbio_ctx_rwant(ctx, n); \ } \ return PKT_READ_PARTIAL; \ #define DO_ASSIGN_PAYLOAD() \ rdb_consumed(ior, sizeof(info->res.bytes)); \ if (PACKET_NBODY(info)) { \ info->payload = rdb_get_consolidated(ior, PACKET_NBODY(info)); \ } { #define DO_SWALLOW_PAYLOAD() \ } if (PACKET_NBODY(info)) { \ rdb_consumed(ior, PACKET_NBODY(info)); \ } if (rdb_get_nused(ior) < pktsize) { RETURN_NEED_MORE(pktsize) } /* copy bytes into the info structure */ rdb_copyread(ior, info->res.bytes, sizeof info->res.bytes); pktsize += PACKET_NBODY(info); if (rdb_get_nused(ior) < pktsize) { RETURN_NEED_MORE(pktsize); } /* Find the packet */ if (PACKET_OPCODE(info) == PROTOCOL_BINARY_CMD_STAT && PACKET_NKEY(info) != 0) { is_last = 0; request = mcreq_pipeline_find(pl, PACKET_OPAQUE(info)); } else { is_last = 1; request = mcreq_pipeline_remove(pl, PACKET_OPAQUE(info)); } if (!request) { lcb_log(LOGARGS(server, WARN), LOGFMT "Found stale packet (OP=0x%x, RC=0x%x, SEQ=%u)", LOGID(server), PACKET_OPCODE(info), PACKET_STATUS(info), PACKET_OPAQUE(info)); rdb_consumed(ior, pktsize); return PKT_READ_COMPLETE; } if (PACKET_STATUS(info) == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET) { /* consume the header */ DO_ASSIGN_PAYLOAD() if (!handle_nmv(server, info, request)) { mcreq_dispatch_response(pl, request, info, LCB_NOT_MY_VBUCKET); } DO_SWALLOW_PAYLOAD() return PKT_READ_COMPLETE; }
/** * It's assumed the server buffers will be reset upon close(), so we must make * sure to _not_ release the ringbuffer if that happens. */ static void handle_read(lcbio_CTX *ioctx, unsigned nb) { mc_pSESSREQ sreq = lcbio_ctx_data(ioctx); packet_info info; unsigned required; uint16_t status; sreq_STATE state = SREQ_S_WAIT; int rc; GT_NEXT_PACKET: memset(&info, 0, sizeof(info)); rc = lcb_pktinfo_ectx_get(&info, ioctx, &required); if (rc == 0) { LCBIO_CTX_RSCHEDULE(ioctx, required); return; } else if (rc < 0) { state = SREQ_S_ERROR; } status = PACKET_STATUS(&info); switch (PACKET_OPCODE(&info)) { case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS: { lcb_string str; int saslrc; const char *mechlist_data; unsigned int nmechlist_data; if (lcb_string_init(&str)) { set_error_ex(sreq, LCB_CLIENT_ENOMEM, NULL); state = SREQ_S_ERROR; break; } if (lcb_string_append(&str, info.payload, PACKET_NBODY(&info))) { lcb_string_release(&str); set_error_ex(sreq, LCB_CLIENT_ENOMEM, NULL); state = SREQ_S_ERROR; break; } saslrc = set_chosen_mech(sreq, &str, &mechlist_data, &nmechlist_data); if (saslrc == 0) { if (0 == send_sasl_auth(sreq, mechlist_data, nmechlist_data)) { state = SREQ_S_WAIT; } else { state = SREQ_S_ERROR; } } else if (saslrc < 0) { state = SREQ_S_ERROR; } else { state = SREQ_S_HELLODONE; } lcb_string_release(&str); break; } case PROTOCOL_BINARY_CMD_SASL_AUTH: { if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) { send_hello(sreq); state = SREQ_S_AUTHDONE; break; } if (status != PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE) { set_error_ex(sreq, LCB_AUTH_ERROR, "SASL AUTH failed"); state = SREQ_S_ERROR; break; } if (send_sasl_step(sreq, &info) == 0 && send_hello(sreq) == 0) { state = SREQ_S_WAIT; } else { state = SREQ_S_ERROR; } break; } case PROTOCOL_BINARY_CMD_SASL_STEP: { if (status != PROTOCOL_BINARY_RESPONSE_SUCCESS) { lcb_log(LOGARGS(sreq, WARN), SESSREQ_LOGFMT "SASL auth failed with STATUS=0x%x", SESSREQ_LOGID(sreq), status); set_error_ex(sreq, LCB_AUTH_ERROR, "SASL Step Failed"); state = SREQ_S_ERROR; } else { /* Wait for pipelined HELLO response */ state = SREQ_S_AUTHDONE; } break; } case PROTOCOL_BINARY_CMD_HELLO: { state = SREQ_S_HELLODONE; if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) { parse_hello(sreq, &info); } else if (status == PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND || status == PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED) { lcb_log(LOGARGS(sreq, DEBUG), SESSREQ_LOGFMT "Server does not support HELLO", SESSREQ_LOGID(sreq)); /* nothing */ } else { set_error_ex(sreq, LCB_PROTOCOL_ERROR, "Hello response unexpected"); state = SREQ_S_ERROR; } break; } default: { state = SREQ_S_ERROR; lcb_log(LOGARGS(sreq, ERROR), SESSREQ_LOGFMT "Received unknown response. OP=0x%x. RC=0x%x", SESSREQ_LOGID(sreq), PACKET_OPCODE(&info), PACKET_STATUS(&info)); set_error_ex(sreq, LCB_NOT_SUPPORTED, "Received unknown response"); break; } } lcb_pktinfo_ectx_done(&info, ioctx); if (sreq->err != LCB_SUCCESS) { bail_pending(sreq); } else if (state == SREQ_S_ERROR) { set_error_ex(sreq, LCB_ERROR, "FIXME: Error code set without description"); } else if (state == SREQ_S_HELLODONE) { negotiation_success(sreq); } else { goto GT_NEXT_PACKET; } (void)nb; }
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); } }