static void shutdown_http(clconfig_provider *provider) { http_provider *http = (http_provider *)provider; reset_stream_state(http); lcb_string_release(&http->stream.chunk); lcb_string_release(&http->stream.input); lcb_string_release(&http->stream.header); lcb_connection_close(&http->connection); lcb_connection_cleanup(&http->connection); if (http->current_config) { lcb_clconfig_decref(http->current_config); } if (http->disconn_timer) { lcb_timer_destroy(NULL, http->disconn_timer); } if (http->io_timer) { lcb_timer_destroy(NULL, http->io_timer); } if (http->as_schederr) { lcb_timer_destroy(NULL, http->as_schederr); } if (http->nodes) { hostlist_destroy(http->nodes); } free(http); }
void lcb_n1p_free(lcb_N1QLPARAMS *params) { lcb_string_release(¶ms->form); lcb_string_release(¶ms->posargs); lcb_string_release(¶ms->scanvec); free(params); }
void lcbvrow_free(lcbvrow_PARSER *ctx) { jsonsl_jpr_match_state_cleanup(ctx->jsn); jsonsl_destroy(ctx->jsn); jsonsl_destroy(ctx->jsn_rdetails); jsonsl_jpr_destroy(ctx->jpr); lcb_string_release(&ctx->current_buf); lcb_string_release(&ctx->meta_buf); lcb_string_release(&ctx->last_hk); free(ctx); }
LIBCOUCHBASE_API lcb_error_t lcb_cbflush3(lcb_t instance, const void *cookie, const lcb_CMDBASE *cmd) { lcb_http_request_t htr; lcb_CMDHTTP htcmd = { 0 }; lcb_string urlpath; lcb_error_t rc; (void)cmd; lcb_string_init(&urlpath); lcb_string_appendz(&urlpath, "/pools/default/buckets/"); lcb_string_appendz(&urlpath, LCBT_SETTING(instance, bucket)); lcb_string_appendz(&urlpath, "/controller/doFlush"); htcmd.type = LCB_HTTP_TYPE_MANAGEMENT; htcmd.method = LCB_HTTP_METHOD_POST; htcmd.reqhandle = &htr; LCB_CMD_SET_KEY(&htcmd, urlpath.base, urlpath.nused); rc = lcb_http3(instance, cookie, &htcmd); lcb_string_release(&urlpath); if (rc != LCB_SUCCESS) { return rc; } lcb_htreq_setcb(htr, flush_cb); return LCB_SUCCESS; }
void lcb_cccp_update2(const void *cookie, lcb_error_t err, const void *bytes, lcb_size_t nbytes, const lcb_host_t *origin) { cccp_cookie *ck = (cccp_cookie *)cookie; cccp_provider *cccp = ck->parent; if (err == LCB_SUCCESS) { lcb_string ss; lcb_string_init(&ss); lcb_string_append(&ss, bytes, nbytes); err = lcb_cccp_update(&cccp->base, origin->host, &ss); lcb_string_release(&ss); if (err != LCB_SUCCESS && ck->ignore_errors == 0) { mcio_error(cccp, err); } } else if (!ck->ignore_errors) { mcio_error(cccp, err); } if (ck == cccp->cmdcookie) { cccp->cmdcookie = NULL; } free(ck); }
static void destroy_requests(OBSERVECTX *reqs) { size_t ii; for (ii = 0; ii < reqs->nrequests; ii++) { lcb_string_release(reqs->requests + ii); } }
/** Update the configuration from a server. */ lcb_error_t lcb_cccp_update(clconfig_provider *provider, const char *host, lcb_string *data) { VBUCKET_CONFIG_HANDLE vbc; lcb_string sanitized; int rv; clconfig_info *new_config; cccp_provider *cccp = (cccp_provider *)provider; vbc = vbucket_config_create(); if (!vbc) { return LCB_CLIENT_ENOMEM; } lcb_string_init(&sanitized); sanitize_config(data, host, &sanitized); rv = vbucket_config_parse(vbc, LIBVBUCKET_SOURCE_MEMORY, sanitized.base); if (rv) { lcb_string_release(&sanitized); vbucket_config_destroy(vbc); lcb_string_release(&sanitized); return LCB_PROTOCOL_ERROR; } new_config = lcb_clconfig_create(vbc, &sanitized, LCB_CLCONFIG_CCCP); lcb_string_release(&sanitized); if (!new_config) { vbucket_config_destroy(vbc); return LCB_CLIENT_ENOMEM; } if (cccp->config) { lcb_clconfig_decref(cccp->config); } /** TODO: Figure out the comparison vector */ new_config->cmpclock = gethrtime(); cccp->config = new_config; lcb_confmon_provider_success(provider, new_config); return LCB_SUCCESS; }
/** * 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 destroy_requests(OBSERVECTX *reqs) { lcb_size_t ii; for (ii = 0; ii < reqs->nrequests; ii++) { struct observe_st *rr = reqs->requests + ii; if (!rr->allocated) { continue; } lcb_string_release(&rr->body); rr->allocated = 0; } }
static lcb_error_t parse_body(struct htvb_st *vbs, int *done) { lcb_error_t err = LCB_BUSY; char *term; if ((err = parse_chunk(vbs)) != LCB_SUCCESS) { *done = 1; /* no data */ lcb_assert(err == LCB_BUSY); return err; } if (lcb_string_append(&vbs->input, vbs->chunk.base, vbs->chunk_size)) { return LCB_CLIENT_ENOMEM; } lcb_string_erase_end(&vbs->input, 2); lcb_string_erase_beginning(&vbs->chunk, vbs->chunk_size); vbs->chunk_size = (lcb_size_t) - 1; if (vbs->chunk.nused > 0) { *done = 0; } term = strstr(vbs->input.base, "\n\n\n\n"); if (term != NULL) { lcb_string tmp; lcb_error_t ret; /** Next input */ lcb_string_init(&tmp); lcb_string_appendz(&tmp, term + 4); *term = '\0'; ret = set_next_config(vbs); /** Now, erase everything until the end of the 'term' */ if (vbs->input.base) { lcb_string_release(&vbs->input); } lcb_string_transfer(&tmp, &vbs->input); return ret; } return err; }
/** * 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; }
/** * Actually free the resources allocated by the dset (and all its entries). * Called by some other functions in libcouchbase */ void lcbdur_destroy(lcb_DURSET *dset) { lcb_t instance = dset->instance; if (DSET_PROCS(dset)->clean) { DSET_PROCS(dset)->clean(dset); } if (dset->timer) { lcbio_TABLE *io = instance->iotable; io->timer.cancel(io->p, dset->timer); io->timer.destroy(io->p, dset->timer); dset->timer = NULL; } lcb_aspend_del(&dset->instance->pendops, LCB_PENDTYPE_DURABILITY, dset); LCB_SSOBUF_CLEAN(&dset->entries_); lcb_string_release(&dset->kvbufs); free(dset); lcb_maybe_breakout(instance); }
/** * Actually free the resources allocated by the dset (and all its entries). * Called by some other functions in libcouchbase */ void lcb_durability_dset_destroy(lcb_DURSET *dset) { lcb_t instance = dset->instance; if (dset->timer) { lcbio_TABLE *io = instance->iotable; io->timer.cancel(io->p, dset->timer); io->timer.destroy(io->p, dset->timer); dset->timer = NULL; } lcb_aspend_del(&dset->instance->pendops, LCB_PENDTYPE_DURABILITY, dset); if (dset->nentries > 1) { if (dset->ht) { genhash_free(dset->ht); } free(dset->entries); } lcb_string_release(&dset->kvbufs); free(dset); lcb_maybe_breakout(instance); }
static int load_cache(file_provider *provider) { lcb_string str; char line[1024]; lcb_ssize_t nr; int fail; FILE *fp = NULL; VBUCKET_CONFIG_HANDLE config = NULL; char *end; struct stat st; int status = -1; lcb_string_init(&str); if (provider->filename == NULL) { return -1; } fp = fopen(provider->filename, "r"); if (fp == NULL) { LOG(provider, ERROR, "Couldn't open filename"); return -1; } if (fstat(fileno(fp), &st)) { provider->last_errno = errno; goto GT_DONE; } if (provider->last_mtime == st.st_mtime) { LOG(provider, INFO, "Rejecting file. Modification time too old"); goto GT_DONE; } config = vbucket_config_create(); if (config == NULL) { goto GT_DONE; } lcb_string_init(&str); while ((nr = fread(line, 1, sizeof(line), fp)) > 0) { if (lcb_string_append(&str, line, nr)) { goto GT_DONE; } } if (ferror(fp)) { goto GT_DONE; } fclose(fp); fp = NULL; if (!str.nused) { status = -1; goto GT_DONE; } end = strstr(str.base, CONFIG_CACHE_MAGIC); if (end == NULL) { LOG(provider, ERROR, "Couldn't find magic in file"); remove(provider->filename); status = -1; goto GT_DONE; } fail = vbucket_config_parse(config, LIBVBUCKET_SOURCE_MEMORY, str.base); if (fail) { status = -1; LOG(provider, ERROR, "Couldn't parse configuration"); remove(provider->filename); goto GT_DONE; } if (vbucket_config_get_distribution_type(config) != VBUCKET_DISTRIBUTION_VBUCKET) { status = -1; LOG(provider, ERROR, "Not applying cached memcached config"); goto GT_DONE; } if (provider->config) { lcb_clconfig_decref(provider->config); } provider->config = lcb_clconfig_create(config, &str, LCB_CLCONFIG_FILE); provider->config->cmpclock = gethrtime(); provider->config->origin = provider->base.type; provider->last_mtime = st.st_mtime; status = 0; config = NULL; GT_DONE: if (fp != NULL) { fclose(fp); } if (config != NULL) { vbucket_config_destroy(config); } lcb_string_release(&str); return status; }
static int load_cache(file_provider *provider) { lcb_string str; char line[1024]; lcb_ssize_t nr; int fail; FILE *fp = NULL; lcbvb_CONFIG *config = NULL; char *end; struct stat st; int status = -1; lcb_string_init(&str); if (provider->filename == NULL) { return -1; } fp = fopen(provider->filename, "r"); if (fp == NULL) { int save_errno = errno; lcb_log(LOGARGS(provider, ERROR), LOGFMT "Couldn't open for reading: %s", LOGID(provider), strerror(save_errno)); return -1; } if (fstat(fileno(fp), &st)) { provider->last_errno = errno; goto GT_DONE; } if (provider->last_mtime == st.st_mtime) { lcb_log(LOGARGS(provider, WARN), LOGFMT "Modification time too old", LOGID(provider)); goto GT_DONE; } config = lcbvb_create(); if (config == NULL) { goto GT_DONE; } lcb_string_init(&str); while ((nr = fread(line, 1, sizeof(line), fp)) > 0) { if (lcb_string_append(&str, line, nr)) { goto GT_DONE; } } if (ferror(fp)) { goto GT_DONE; } fclose(fp); fp = NULL; if (!str.nused) { status = -1; goto GT_DONE; } end = strstr(str.base, CONFIG_CACHE_MAGIC); if (end == NULL) { lcb_log(LOGARGS(provider, ERROR), LOGFMT "Couldn't find magic", LOGID(provider)); if (!provider->ro_mode) { remove(provider->filename); } status = -1; goto GT_DONE; } fail = lcbvb_load_json(config, str.base); if (fail) { status = -1; lcb_log(LOGARGS(provider, ERROR), LOGFMT "Couldn't parse configuration", LOGID(provider)); lcb_log_badconfig(LOGARGS(provider, ERROR), config, str.base); if (!provider->ro_mode) { remove(provider->filename); } goto GT_DONE; } if (lcbvb_get_distmode(config) != LCBVB_DIST_VBUCKET) { status = -1; lcb_log(LOGARGS(provider, ERROR), LOGFMT "Not applying cached memcached config", LOGID(provider)); goto GT_DONE; } if (strcmp(config->bname, PROVIDER_SETTING(&provider->base, bucket)) != 0) { status = -1; lcb_log(LOGARGS(provider, ERROR), LOGFMT "Bucket name in file is different from the one requested", LOGID(provider)); } if (provider->config) { lcb_clconfig_decref(provider->config); } provider->config = lcb_clconfig_create(config, LCB_CLCONFIG_FILE); provider->config->cmpclock = gethrtime(); provider->config->origin = provider->base.type; provider->last_mtime = st.st_mtime; status = 0; config = NULL; GT_DONE: if (fp != NULL) { fclose(fp); } if (config != NULL) { lcbvb_destroy(config); } lcb_string_release(&str); return status; }
/** * 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; }
lcb_error_t hostlist_add_string(hostlist_t hostlist, const char *spec, int speclen, int deflport) { lcb_error_t err = LCB_SUCCESS; lcb_string str; char *delim; char *curstart; if (speclen < 0) { speclen = strlen(spec); } if (lcb_string_init(&str)) { return LCB_CLIENT_ENOMEM; } if (lcb_string_append(&str, spec, speclen)) { lcb_string_release(&str); return LCB_CLIENT_ENOMEM; } if (!str.nused) { lcb_string_release(&str); return LCB_SUCCESS; } if (str.base[str.nused-1] != ';') { if (lcb_string_appendz(&str, ";")) { lcb_string_release(&str); return LCB_CLIENT_ENOMEM; } } curstart = str.base; while ( (delim = strstr(curstart, ";"))) { lcb_host_t curhost; lcb_size_t curlen; if (delim == curstart) { curstart++; continue; } /** { 'f', 'o', 'o', ';' } */ curlen = delim - curstart; err = lcb_host_parse(&curhost, curstart, curlen, deflport); if (err != LCB_SUCCESS) { break; } err = hostlist_add_host(hostlist, &curhost); if (err != LCB_SUCCESS) { break; } curstart = delim + 1; } lcb_string_release(&str); return err; }
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); } }
lcb_error_t lcb_host_parse(lcb_host_t *host, const char *spec, int speclen, int deflport) { lcb_string zspec; char *host_s; char *port_s; char *delim; /** Parse the host properly */ if (speclen < 0) { speclen = strlen(spec); } else if (speclen == 0) { return LCB_INVALID_HOST_FORMAT; } if (deflport < 1) { return LCB_INVALID_HOST_FORMAT; } if (lcb_string_init(&zspec)) { return LCB_CLIENT_ENOMEM; } if (lcb_string_append(&zspec, spec, speclen)) { lcb_string_release(&zspec); return LCB_CLIENT_ENOMEM; } host_s = zspec.base; if (*host_s == ':') { lcb_string_release(&zspec); return LCB_INVALID_HOST_FORMAT; } if ( (delim = strstr(host_s, "://"))) { host_s = delim + 3; } if ((delim = strstr(host_s, "/"))) { *delim = '\0'; } port_s = strstr(host_s, ":"); if (port_s != NULL) { char *endp; long ll; *port_s = '\0'; port_s++; if (! *port_s) { lcb_string_release(&zspec); return LCB_INVALID_HOST_FORMAT; } ll = strtol(port_s, &endp, 10); if (ll == LONG_MIN || ll == LONG_MAX) { lcb_string_release(&zspec); return LCB_INVALID_HOST_FORMAT; } if (*endp) { lcb_string_release(&zspec); return LCB_INVALID_HOST_FORMAT; } } else { port_s = ""; } if (strlen(host_s) > sizeof(host->host)-1 || strlen(port_s) > sizeof(host->port)-1 || *host_s == '\0') { lcb_string_release(&zspec); return LCB_INVALID_HOST_FORMAT; } { lcb_size_t ii, hostlen = strlen(host_s); for (ii = 0; ii < hostlen; ii++) { if (isalnum(host_s[ii])) { continue; } switch (host_s[ii]) { case '.': case '-': case '_': break; default: lcb_string_release(&zspec); return LCB_INVALID_HOST_FORMAT; } } } strcpy(host->host, host_s); if (*port_s) { strcpy(host->port, port_s); } else { sprintf(host->port, "%d", deflport); } lcb_string_release(&zspec); return LCB_SUCCESS; }
/** * 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; }