Esempio n. 1
0
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);
}
Esempio n. 2
0
void
lcb_n1p_free(lcb_N1QLPARAMS *params)
{
    lcb_string_release(&params->form);
    lcb_string_release(&params->posargs);
    lcb_string_release(&params->scanvec);
    free(params);
}
Esempio n. 3
0
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);
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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);
}
Esempio n. 6
0
static void destroy_requests(OBSERVECTX *reqs)
{
    size_t ii;
    for (ii = 0; ii < reqs->nrequests; ii++) {
        lcb_string_release(reqs->requests + ii);
    }
}
Esempio n. 7
0
/** 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;
}
Esempio n. 8
0
/**
 * 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;
}
Esempio n. 9
0
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;
    }
}
Esempio n. 10
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;
}
Esempio n. 11
0
/**
 * 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;
}
Esempio n. 12
0
/**
 * 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);
}
Esempio n. 13
0
/**
 * 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);
}
Esempio n. 14
0
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;
}
Esempio n. 15
0
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;
}
Esempio n. 16
0
/**
 * 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;
}
Esempio n. 17
0
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;
}
Esempio n. 18
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);
    }
}
Esempio n. 19
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;
}
Esempio n. 20
0
/**
 * 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;
}