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 H_stats(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->cqdata; lcb_RESPSTATS resp = { 0 }; mc_REQDATAEX *exdata; MK_ERROR(root, &resp, response, immerr); resp.version = 0; exdata = request->u_rdata.exdata; if (resp.rc != LCB_SUCCESS || PACKET_NKEY(response) == 0) { /* Call the handler without a response, this indicates that this server * has finished responding */ exdata->procs->handler(pipeline, request, resp.rc, NULL); return; } if ((resp.nkey = PACKET_NKEY(response))) { resp.key = PACKET_KEY(response); if ((resp.value = PACKET_VALUE(response))) { resp.nvalue = PACKET_NVALUE(response); } } exdata->procs->handler(pipeline, request, resp.rc, &resp); }
static void H_getreplica(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_error_t rc; lcb_get_resp_t resp; lcb_t instance = pipeline->parent->instance; void *freeptr = NULL; MK_RESPKEY(&resp, 0, request); MK_ERROR(instance, rc, response, immerr); resp.version = 0; if (rc == LCB_SUCCESS) { const protocol_binary_response_get *get = PACKET_EPHEMERAL_START(response); resp.v.v0.cas = PACKET_CAS(response); resp.v.v0.datatype = PACKET_DATATYPE(response); resp.v.v0.flags = ntohl(get->message.body.flags); resp.v.v0.bytes = PACKET_VALUE(response); resp.v.v0.nbytes = PACKET_NVALUE(response); } maybe_decompress(instance, response, &resp, &freeptr); request->u_rdata.exdata->callback(pipeline, request, rc, &resp); free(freeptr); }
static int sdlookup_next(const packet_info *response, lcb_SDENTRY *ent, size_t *iter) { const char *buf; lcb_U16 rc; lcb_U32 vlen; if (*iter == PACKET_NVALUE(response)) { return 0; } buf = PACKET_VALUE(response); buf += *iter; memcpy(&rc, buf, 2); memcpy(&vlen, buf + 2, 4); rc = ntohs(rc); vlen = ntohl(vlen); ent->status = map_error(NULL, rc); ent->nvalue = vlen; if (ent->status == LCB_SUCCESS) { ent->value = buf + 6; } else { ent->value = NULL; ent->nvalue = 0; } *iter += (6 + vlen); return 1; }
/** * Optionally decompress an incoming payload. * @param o The instance * @param resp The response received * @param[out] bytes pointer to the final payload * @param[out] nbytes pointer to the size of the final payload * @param[out] freeptr pointer to free. This should be initialized to `NULL`. * If temporary dynamic storage is required this will be set to the allocated * pointer upon return. Otherwise it will be set to NULL. In any case it must */ static void maybe_decompress(lcb_t o, const packet_info *respkt, lcb_RESPGET *rescmd, void **freeptr) { lcb_U8 dtype = 0; if (!PACKET_NVALUE(respkt)) { return; } if (PACKET_DATATYPE(respkt) & PROTOCOL_BINARY_DATATYPE_JSON) { dtype = LCB_VALUE_F_JSON; } if (PACKET_DATATYPE(respkt) & PROTOCOL_BINARY_DATATYPE_COMPRESSED) { if (LCBT_SETTING(o, compressopts) & LCB_COMPRESS_IN) { /* if we inflate, we don't set the flag */ mcreq_inflate_value( PACKET_VALUE(respkt), PACKET_NVALUE(respkt), &rescmd->value, &rescmd->nvalue, freeptr); } else { /* user doesn't want inflation. signal it's compressed */ dtype |= LCB_VALUE_F_SNAPPYCOMP; } } rescmd->datatype = dtype; }
static void H_get(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t o; lcb_RESPGET resp = { 0 }; void *freeptr = NULL; o = pipeline->parent->cqdata; init_resp3(o, response, request, immerr, (lcb_RESPBASE *)&resp); if (resp.rc == LCB_SUCCESS) { const protocol_binary_response_getq *getq = PACKET_EPHEMERAL_START(response); resp.datatype = PACKET_DATATYPE(response); resp.itmflags = ntohl(getq->message.body.flags); resp.value = PACKET_VALUE(response); resp.nvalue = PACKET_NVALUE(response); resp.bufh = response->bufh; } maybe_decompress(o, response, &resp, &freeptr); TRACE_GET_END(response, &resp); INVOKE_CALLBACK3(request, &resp, o, LCB_CALLBACK_GET); free(freeptr); }
static void H_stats(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->instance; lcb_error_t rc; lcb_server_stat_resp_t resp; mc_REQDATAEX *exdata; MK_ERROR(root, rc, response, immerr); resp.version = 0; exdata = request->u_rdata.exdata; if (rc != LCB_SUCCESS || PACKET_NKEY(response) == 0) { /* Call the handler without a response, this indicates that this server * has finished responding */ exdata->callback(pipeline, request, rc, NULL); return; } if ((resp.v.v0.nkey = PACKET_NKEY(response))) { resp.v.v0.key = PACKET_KEY(response); if ((resp.v.v0.nbytes = PACKET_NVALUE(response))) { resp.v.v0.bytes = PACKET_VALUE(response); } } exdata->callback(pipeline, request, rc, &resp); }
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 int sdmutate_next(const packet_info *response, lcb_SDENTRY *ent, size_t *iter) { const char *buf, *buf_end; lcb_U16 rc; lcb_U32 vlen; if (*iter == PACKET_NVALUE(response)) { return 0; } buf_end = (const char *)PACKET_VALUE(response) + PACKET_NVALUE(response); buf = ((const char *)(PACKET_VALUE(response))) + *iter; #define ADVANCE_BUF(sz) \ buf += sz; \ *iter += sz; \ assert(buf <= buf_end); \ /* Index */ ent->index = *(lcb_U8*)buf; ADVANCE_BUF(1); /* Status */ memcpy(&rc, buf, 2); ADVANCE_BUF(2); rc = ntohs(rc); ent->status = map_error(NULL, rc); if (rc == PROTOCOL_BINARY_RESPONSE_SUCCESS) { memcpy(&vlen, buf, 4); ADVANCE_BUF(4); vlen = ntohl(vlen); ent->nvalue = vlen; ent->value = buf; ADVANCE_BUF(vlen); } else { ent->value = NULL; ent->nvalue = 0; } return 1; #undef ADVANCE_BUF }
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); }
/** * Invoked when get a NOT_MY_VBUCKET response. If the response contains a JSON * payload then we refresh the configuration with it. * * This function returns 1 if the operation was successfully rescheduled; * otherwise it returns 0. If it returns 0 then we give the error back to the * user. */ static int handle_nmv(mc_SERVER *oldsrv, packet_info *resinfo, mc_PACKET *oldpkt) { mc_PACKET *newpkt; protocol_binary_request_header hdr; lcb_error_t err = LCB_ERROR; lcb_t instance = oldsrv->instance; lcb_U16 vbid; clconfig_provider *cccp = lcb_confmon_get_provider(instance->confmon, LCB_CLCONFIG_CCCP); mcreq_read_hdr(oldpkt, &hdr); vbid = ntohs(hdr.request.vbucket); lcb_log(LOGARGS(oldsrv, WARN), LOGFMT "NOT_MY_VBUCKET. Packet=%p (S=%u). VBID=%u", LOGID(oldsrv), (void*)oldpkt, oldpkt->opaque, vbid); /* Notify of new map */ lcb_vbguess_remap(instance, vbid, oldsrv->pipeline.index); if (PACKET_NBODY(resinfo) && cccp->enabled) { lcb_string s; lcb_string_init(&s); lcb_string_append(&s, PACKET_VALUE(resinfo), PACKET_NVALUE(resinfo)); err = lcb_cccp_update(cccp, mcserver_get_host(oldsrv), &s); lcb_string_release(&s); } if (err != LCB_SUCCESS) { int bs_options; if (instance->cur_configinfo->origin == LCB_CLCONFIG_CCCP) { /** * XXX: Not enough to see if cccp was enabled, since cccp might * be requested by a user, but would still not actually be active * for clusters < 2.5 If our current config is from CCCP * then we can be fairly certain that CCCP is indeed working. * * For this reason, we don't use if (cccp->enabled) {...} */ bs_options = LCB_BS_REFRESH_THROTTLE; } else { bs_options = LCB_BS_REFRESH_ALWAYS; } lcb_bootstrap_common(instance, bs_options); } if (!lcb_should_retry(oldsrv->settings, oldpkt, LCB_NOT_MY_VBUCKET)) { return 0; } /** Reschedule the packet again .. */ newpkt = mcreq_renew_packet(oldpkt); newpkt->flags &= ~MCREQ_STATE_FLAGS; lcb_retryq_nmvadd(instance->retryq, (mc_EXPACKET*)newpkt); return 1; }
static void H_arithmetic(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->cqdata; lcb_RESPCOUNTER resp = { 0 }; init_resp3(root, response, request, immerr, (lcb_RESPBASE*)&resp); if (resp.rc == LCB_SUCCESS) { memcpy(&resp.value, PACKET_VALUE(response), sizeof(resp.value)); resp.value = lcb_ntohll(resp.value); handle_synctoken(root, response, request, &resp.synctoken); } resp.cas = PACKET_CAS(response); TRACE_ARITHMETIC_END(response, &resp); INVOKE_CALLBACK3(request, &resp, root, LCB_CALLBACK_COUNTER); }
/** * Invoked when get a NOT_MY_VBUCKET response. If the response contains a JSON * payload then we refresh the configuration with it. * * This function returns 1 if the operation was successfully rescheduled; * otherwise it returns 0. If it returns 0 then we give the error back to the * user. */ static int handle_nmv(mc_SERVER *oldsrv, packet_info *resinfo, mc_PACKET *oldpkt) { mc_PACKET *newpkt; protocol_binary_request_header hdr; lcb_error_t err = LCB_ERROR; lcb_t instance = oldsrv->instance; lcb_U16 vbid; int tmpix; clconfig_provider *cccp = lcb_confmon_get_provider(instance->confmon, LCB_CLCONFIG_CCCP); mcreq_read_hdr(oldpkt, &hdr); vbid = ntohs(hdr.request.vbucket); lcb_log(LOGARGS(oldsrv, WARN), LOGFMT "NOT_MY_VBUCKET. Packet=%p (S=%u). VBID=%u", LOGID(oldsrv), (void*)oldpkt, oldpkt->opaque, vbid); /* Notify of new map */ tmpix = lcb_vbguess_remap(LCBT_VBCONFIG(instance), instance->vbguess, vbid, oldsrv->pipeline.index); if (tmpix > -1 && tmpix != oldsrv->pipeline.index) { lcb_log(LOGARGS(oldsrv, TRACE), LOGFMT "Heuristically set IX=%d as master for VBID=%u", LOGID(oldsrv), tmpix, vbid); } if (PACKET_NBODY(resinfo) && cccp->enabled) { lcb_string s; lcb_string_init(&s); lcb_string_append(&s, PACKET_VALUE(resinfo), PACKET_NVALUE(resinfo)); err = lcb_cccp_update(cccp, mcserver_get_host(oldsrv), &s); lcb_string_release(&s); } if (err != LCB_SUCCESS) { lcb_bootstrap_common(instance, LCB_BS_REFRESH_ALWAYS); } if (!lcb_should_retry(oldsrv->settings, oldpkt, LCB_NOT_MY_VBUCKET)) { return 0; } /** Reschedule the packet again .. */ newpkt = mcreq_renew_packet(oldpkt); newpkt->flags &= ~MCREQ_STATE_FLAGS; lcb_retryq_add(instance->retryq, (mc_EXPACKET*)newpkt, LCB_NOT_MY_VBUCKET); return 1; }
static void H_arithmetic(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->cqdata; respack_COUNTER w = { { 0 } }; init_resp3(root, response, request, immerr, (lcb_RESPBASE*)&w.resp); if (w.resp.rc == LCB_SUCCESS) { memcpy(&w.resp.value, PACKET_VALUE(response), sizeof(w.resp.value)); w.resp.value = lcb_ntohll(w.resp.value); w.resp.rflags |= LCB_RESP_F_EXTDATA; handle_mutation_token(root, response, request, &w.mt); } w.resp.cas = PACKET_CAS(response); TRACE_ARITHMETIC_END(response, &w.resp); INVOKE_CALLBACK3(request, &w.resp, root, LCB_CALLBACK_COUNTER); }
static void H_getreplica(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_RESPGET resp = { 0 }; lcb_t instance = pipeline->parent->cqdata; void *freeptr = NULL; mc_REQDATAEX *rd = request->u_rdata.exdata; init_resp3(instance, response, request, immerr, (lcb_RESPBASE *)&resp); if (resp.rc == LCB_SUCCESS) { const protocol_binary_response_get *get = PACKET_EPHEMERAL_START(response); resp.itmflags = ntohl(get->message.body.flags); resp.datatype = PACKET_DATATYPE(response); resp.value = PACKET_VALUE(response); resp.nvalue = PACKET_NVALUE(response); resp.bufh = response->bufh; } maybe_decompress(instance, response, &resp, &freeptr); rd->procs->handler(pipeline, request, resp.rc, &resp); free(freeptr); }
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 H_get(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_error_t rc; lcb_t o; lcb_get_resp_t resp; void *freeptr = NULL; o = pipeline->parent->instance; MK_RESPKEY(&resp, 0, request); MK_ERROR(o, rc, response, immerr); resp.version = 0; if (rc == LCB_SUCCESS) { const protocol_binary_response_getq *getq = PACKET_EPHEMERAL_START(response); resp.v.v0.cas = PACKET_CAS(response); resp.v.v0.datatype = PACKET_DATATYPE(response); resp.v.v0.flags = ntohl(getq->message.body.flags); resp.v.v0.bytes = PACKET_VALUE(response); resp.v.v0.nbytes = PACKET_NVALUE(response); rc = LCB_SUCCESS; } else { resp.v.v0.cas = 0; resp.v.v0.nbytes = 0; resp.v.v0.bytes = NULL; resp.v.v0.flags = 0; } maybe_decompress(o, response, &resp, &freeptr); INVOKE_CALLBACK(request, o->callbacks.get, (o, MCREQ_PKT_COOKIE(request), rc, &resp)); free(freeptr); }
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); }
/** * Returns 1 if retried, 0 if the command should fail, -1 for an internal * error */ static int handle_not_my_vbucket(lcb_server_t *c, packet_info *resinfo, protocol_binary_request_header *oldreq, struct lcb_command_data_st *oldct) { int idx; char *body; lcb_size_t nbody, nr; lcb_server_t *new_srv; struct lcb_command_data_st ct; protocol_binary_request_header req; hrtime_t now; lcb_string config_string; lcb_error_t err = LCB_ERROR; lcb_log(LOGARGS(c, WARN), "NOT_MY_VBUCKET; Server=%p,ix=%d,real_start=%lu,vb=%d", (void *)c, c->index, (unsigned long)oldct->real_start, (int)ntohs(oldreq->request.vbucket)); lcb_string_init(&config_string); if (PACKET_NBODY(resinfo)) { lcb_string_append(&config_string, PACKET_VALUE(resinfo), PACKET_NVALUE(resinfo)); err = lcb_cccp_update(lcb_confmon_get_provider(c->instance->confmon, LCB_CLCONFIG_CCCP), c->curhost.host, &config_string); } lcb_string_release(&config_string); if (err != LCB_SUCCESS) { lcb_bootstrap_refresh(c->instance); } /* re-schedule command to new server */ if (!c->instance->settings.vb_noguess) { idx = vbucket_found_incorrect_master(c->instance->vbucket_config, ntohs(oldreq->request.vbucket), (int)c->index); } else { idx = c->index; } if (idx == -1) { lcb_log(LOGARGS(c, ERR), "no alternate server"); return 0; } lcb_log(LOGARGS(c, INFO), "Mapped key to new server %d -> %d", c->index, idx); now = gethrtime(); if (oldct->real_start) { hrtime_t min_ok = now - MCSERVER_TIMEOUT(c) * 1000; if (oldct->real_start < min_ok) { /** Timed out in a 'natural' manner */ return 0; } } req = *oldreq; lcb_assert((lcb_size_t)idx < c->instance->nservers); new_srv = c->instance->servers + idx; nr = ringbuffer_read(&c->cmd_log, req.bytes, sizeof(req)); lcb_assert(nr == sizeof(req)); req.request.opaque = ++c->instance->seqno; nbody = ntohl(req.request.bodylen); body = malloc(nbody); if (body == NULL) { lcb_error_handler(c->instance, LCB_CLIENT_ENOMEM, NULL); return -1; } nr = ringbuffer_read(&c->cmd_log, body, nbody); lcb_assert(nr == nbody); nr = ringbuffer_read(&c->output_cookies, &ct, sizeof(ct)); lcb_assert(nr == sizeof(ct)); /* Preserve the cookie and reset timestamp for the command. This * means that the library will retry the command until it will * get code different from LCB_NOT_MY_VBUCKET */ if (!ct.real_start) { ct.real_start = ct.start; } ct.start = now; lcb_server_retry_packet(new_srv, &ct, &req, sizeof(req)); /* FIXME dtrace instrumentation */ lcb_server_write_packet(new_srv, body, nbody); lcb_server_end_packet(new_srv); lcb_server_send_packets(new_srv); free(body); return 1; }