Пример #1
0
static void
H_store(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response,
        lcb_error_t immerr)
{
    lcb_t root = pipeline->parent->cqdata;
    lcb_RESPSTORE resp = { 0 };
    lcb_U8 opcode;
    init_resp3(root, response, request, immerr, (lcb_RESPBASE*)&resp);
    if (!immerr) {
        opcode = PACKET_OPCODE(response);
    } else {
        protocol_binary_request_header hdr;
        mcreq_read_hdr(request, &hdr);
        opcode = hdr.request.opcode;
    }
    if (opcode == PROTOCOL_BINARY_CMD_ADD) {
        resp.op = LCB_ADD;
    } else if (opcode == PROTOCOL_BINARY_CMD_REPLACE) {
        resp.op = LCB_REPLACE;
    } else if (opcode == PROTOCOL_BINARY_CMD_APPEND) {
        resp.op = LCB_APPEND;
    } else if (opcode == PROTOCOL_BINARY_CMD_PREPEND) {
        resp.op = LCB_PREPEND;
    } else if (opcode == PROTOCOL_BINARY_CMD_SET) {
        resp.op = LCB_SET;
    }
    handle_synctoken(root, response, request, &resp.synctoken);
    TRACE_STORE_END(response, &resp);
    if (request->flags & MCREQ_F_REQEXT) {
        request->u_rdata.exdata->procs->handler(pipeline, request, immerr, &resp);
    } else {
        INVOKE_CALLBACK3(request, &resp, root, LCB_CALLBACK_STORE);
    }
}
Пример #2
0
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);
    }
}
Пример #3
0
static void
record_metrics(mc_PIPELINE *pipeline, mc_PACKET *req, packet_info *res)
{
    lcb_t instance = pipeline->parent->cqdata;
    if (instance->histogram) {
        lcb_record_metrics(
                instance, gethrtime() - MCREQ_PKT_RDATA(req)->start,
                PACKET_OPCODE(res));
    }
}
Пример #4
0
static void
H_subdoc(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response,
    lcb_error_t immerr)
{
    lcb_t o;
    respack_SUBDOC w = { { 0 } };
    int cbtype;
    o = pipeline->parent->cqdata;
    init_resp3(o, response, request, immerr, (lcb_RESPBASE *)&w.resp);

    /* For mutations, add the mutation token */
    switch (PACKET_OPCODE(response)) {
    case PROTOCOL_BINARY_CMD_SUBDOC_GET:
    case PROTOCOL_BINARY_CMD_SUBDOC_EXISTS:
    case PROTOCOL_BINARY_CMD_SUBDOC_MULTI_LOOKUP:
        cbtype = LCB_CALLBACK_SDLOOKUP;
        break;

    default:
        handle_mutation_token(o, response, request, &w.mt);
        w.resp.rflags |= LCB_RESP_F_EXTDATA;
        cbtype = LCB_CALLBACK_SDMUTATE;
        break;
    }

    if (PACKET_OPCODE(response) == PROTOCOL_BINARY_CMD_SUBDOC_MULTI_LOOKUP ||
            PACKET_OPCODE(response) == PROTOCOL_BINARY_CMD_SUBDOC_MULTI_MUTATION) {
        if (w.resp.rc == LCB_SUCCESS || w.resp.rc == LCB_SUBDOC_MULTI_FAILURE) {
            w.resp.responses = response;
        }
    } else {
        /* Single response */
        w.resp.rflags |= LCB_RESP_F_SDSINGLE;
        if (w.resp.rc == LCB_SUCCESS) {
            w.resp.responses = response;
        } else if (LCB_EIFSUBDOC(w.resp.rc)) {
            w.resp.responses = response;
            w.resp.rc = LCB_SUBDOC_MULTI_FAILURE;
        }
    }
    INVOKE_CALLBACK3(request, &w.resp, o, cbtype);
}
Пример #5
0
static void
H_store(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response,
        lcb_error_t immerr)
{
    lcb_t root = pipeline->parent->instance;
    lcb_storage_t op;
    lcb_error_t rc;
    lcb_store_resp_t resp;

    MK_ERROR(root, rc, response, immerr);

    switch (PACKET_OPCODE(response)) {
    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:
        abort();
        break;
    }

    resp.version = 0;
    MK_RESPKEY(&resp, 0, request);
    SET_RESP_CAS(&resp, 0, PACKET_CAS(response));

    INVOKE_CALLBACK(request, root->callbacks.store,
                    (root, MCREQ_PKT_COOKIE(request), op, rc, &resp));
}
Пример #6
0
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;
        }
    }
}
Пример #7
0
int
mcreq_dispatch_response(
        mc_PIPELINE *pipeline, mc_PACKET *req, packet_info *res,
        lcb_error_t immerr)
{
    record_metrics(pipeline, req, res);

    if (req->flags & MCREQ_F_UFWD) {
        dispatch_ufwd_error(pipeline, req, immerr);
        return 0;
    }


#define INVOKE_OP(handler) \
    handler(pipeline, req, res, immerr); \
    return 0; \
    break;

    switch (PACKET_OPCODE(res)) {
    case PROTOCOL_BINARY_CMD_GETQ:
    case PROTOCOL_BINARY_CMD_GATQ:
    case PROTOCOL_BINARY_CMD_GET:
    case PROTOCOL_BINARY_CMD_GAT:
    case PROTOCOL_BINARY_CMD_GET_LOCKED:
        INVOKE_OP(H_get);

    case PROTOCOL_BINARY_CMD_ADD:
    case PROTOCOL_BINARY_CMD_REPLACE:
    case PROTOCOL_BINARY_CMD_SET:
    case PROTOCOL_BINARY_CMD_APPEND:
    case PROTOCOL_BINARY_CMD_PREPEND:
        INVOKE_OP(H_store);

    case PROTOCOL_BINARY_CMD_INCREMENT:
    case PROTOCOL_BINARY_CMD_DECREMENT:
        INVOKE_OP(H_arithmetic);

    case PROTOCOL_BINARY_CMD_OBSERVE:
        INVOKE_OP(H_observe);

    case PROTOCOL_BINARY_CMD_GET_REPLICA:
        INVOKE_OP(H_getreplica);

    case PROTOCOL_BINARY_CMD_UNLOCK_KEY:
        INVOKE_OP(H_unlock);

    case PROTOCOL_BINARY_CMD_DELETE:
        INVOKE_OP(H_delete);

    case PROTOCOL_BINARY_CMD_TOUCH:
        INVOKE_OP(H_touch);

    case PROTOCOL_BINARY_CMD_OBSERVE_SEQNO:
        INVOKE_OP(H_observe_seqno);

    case PROTOCOL_BINARY_CMD_STAT:
        INVOKE_OP(H_stats);

    case PROTOCOL_BINARY_CMD_FLUSH:
        INVOKE_OP(H_flush);

    case PROTOCOL_BINARY_CMD_VERSION:
        INVOKE_OP(H_version);

    case PROTOCOL_BINARY_CMD_VERBOSITY:
        INVOKE_OP(H_verbosity);

#if 0
    case PROTOCOL_BINARY_CMD_NOOP:
        INVOKE_OP(H_noop);
#endif

    case PROTOCOL_BINARY_CMD_GET_CLUSTER_CONFIG:
        INVOKE_OP(H_config);

    default:
        return -1;
    }
}
Пример #8
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;
}
Пример #9
0
/* 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;
    }
Пример #10
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);
    }
}
Пример #11
0
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;
}
Пример #12
0
int
mcreq_dispatch_response(
        mc_PIPELINE *pipeline, mc_PACKET *req, packet_info *res,
        lcb_error_t immerr)
{
    record_metrics(pipeline, req, res);

    if (req->flags & MCREQ_F_UFWD) {
        dispatch_ufwd_error(pipeline, req, immerr);
        return 0;
    }


#define INVOKE_OP(handler) \
    handler(pipeline, req, res, immerr); \
    return 0; \
    break;

    switch (PACKET_OPCODE(res)) {
    case PROTOCOL_BINARY_CMD_GETQ:
    case PROTOCOL_BINARY_CMD_GATQ:
    case PROTOCOL_BINARY_CMD_GET:
    case PROTOCOL_BINARY_CMD_GAT:
    case PROTOCOL_BINARY_CMD_GET_LOCKED:
        INVOKE_OP(H_get);

    case PROTOCOL_BINARY_CMD_ADD:
    case PROTOCOL_BINARY_CMD_REPLACE:
    case PROTOCOL_BINARY_CMD_SET:
    case PROTOCOL_BINARY_CMD_APPEND:
    case PROTOCOL_BINARY_CMD_PREPEND:
        INVOKE_OP(H_store);

    case PROTOCOL_BINARY_CMD_INCREMENT:
    case PROTOCOL_BINARY_CMD_DECREMENT:
        INVOKE_OP(H_arithmetic);

    case PROTOCOL_BINARY_CMD_SUBDOC_GET:
    case PROTOCOL_BINARY_CMD_SUBDOC_EXISTS:
    case PROTOCOL_BINARY_CMD_SUBDOC_ARRAY_ADD_UNIQUE:
    case PROTOCOL_BINARY_CMD_SUBDOC_ARRAY_PUSH_FIRST:
    case PROTOCOL_BINARY_CMD_SUBDOC_ARRAY_PUSH_LAST:
    case PROTOCOL_BINARY_CMD_SUBDOC_ARRAY_INSERT:
    case PROTOCOL_BINARY_CMD_SUBDOC_DICT_ADD:
    case PROTOCOL_BINARY_CMD_SUBDOC_DICT_UPSERT:
    case PROTOCOL_BINARY_CMD_SUBDOC_REPLACE:
    case PROTOCOL_BINARY_CMD_SUBDOC_DELETE:
    case PROTOCOL_BINARY_CMD_SUBDOC_COUNTER:
    case PROTOCOL_BINARY_CMD_SUBDOC_MULTI_LOOKUP:
    case PROTOCOL_BINARY_CMD_SUBDOC_MULTI_MUTATION:
        INVOKE_OP(H_subdoc);

    case PROTOCOL_BINARY_CMD_OBSERVE:
        INVOKE_OP(H_observe);

    case PROTOCOL_BINARY_CMD_GET_REPLICA:
        INVOKE_OP(H_getreplica);

    case PROTOCOL_BINARY_CMD_UNLOCK_KEY:
        INVOKE_OP(H_unlock);

    case PROTOCOL_BINARY_CMD_DELETE:
        INVOKE_OP(H_delete);

    case PROTOCOL_BINARY_CMD_TOUCH:
        INVOKE_OP(H_touch);

    case PROTOCOL_BINARY_CMD_OBSERVE_SEQNO:
        INVOKE_OP(H_observe_seqno);

    case PROTOCOL_BINARY_CMD_STAT:
        INVOKE_OP(H_stats);

    case PROTOCOL_BINARY_CMD_FLUSH:
        INVOKE_OP(H_flush);

    case PROTOCOL_BINARY_CMD_VERSION:
        INVOKE_OP(H_version);

    case PROTOCOL_BINARY_CMD_VERBOSITY:
        INVOKE_OP(H_verbosity);

#if 0
    case PROTOCOL_BINARY_CMD_NOOP:
        INVOKE_OP(H_noop);
#endif

    case PROTOCOL_BINARY_CMD_GET_CLUSTER_CONFIG:
        INVOKE_OP(H_config);

    default:
        fprintf(stderr, "COUCHBASE: Received unknown opcode=0x%x\n", PACKET_OPCODE(res));
        return -1;
    }
}