/** * Receive the response packet from a stats call and split it up * into the key/value pair. * * @param bio the connection to read the packet from * @param st where to stash the result */ static void receive_stat_response(BIO *bio, struct statistic *st) { protocol_binary_response_no_extras response; ensure_recv(bio, &response, sizeof(response.bytes)); st->key = st->value = NULL; uint16_t keylen = ntohs(response.message.header.response.keylen); uint32_t vallen = ntohl(response.message.header.response.bodylen) - keylen; st->key = allocate(keylen); ensure_recv(bio, st->key, keylen); st->value = allocate(vallen); ensure_recv(bio, st->value, vallen); protocol_binary_response_status status; status = ntohs(response.message.header.response.status); if (status != PROTOCOL_BINARY_RESPONSE_SUCCESS) { fprintf(stderr, "Error from server requesting stats: %s\n", memcached_status_2_text(status)); /* Just terminate.. we might have multiple packets in the * pipeline and this makes the error handling easier and * safer */ exit(EXIT_FAILURE); } }
/** * Sets a property (to the specified value). * @param bio connection to the server. * @param property the name of the property to set. * @param value value to set the property to (NULL == no value). */ static int ioctl_set(BIO *bio, const char *property, const char* value) { char *buffer = NULL; uint16_t keylen = 0; uint32_t valuelen = 0; int result; protocol_binary_request_ioctl_set request; protocol_binary_response_no_extras response; protocol_binary_response_status status; if (property != NULL) { keylen = (uint16_t)strlen(property); } if (value != NULL) { valuelen = (uint32_t)strlen(value); } memset(&request, 0, sizeof(request)); request.message.header.request.magic = PROTOCOL_BINARY_REQ; request.message.header.request.opcode = PROTOCOL_BINARY_CMD_IOCTL_SET; request.message.header.request.keylen = htons(keylen); request.message.header.request.bodylen = htonl(valuelen); ensure_send(bio, &request, sizeof(request)); if (keylen > 0) { ensure_send(bio, property, keylen); } if (valuelen > 0) { ensure_send(bio, value, valuelen); } ensure_recv(bio, &response, sizeof(response.bytes)); if (response.message.header.response.bodylen != 0) { valuelen = ntohl(response.message.header.response.bodylen); buffer = malloc(valuelen); if (buffer == NULL) { fprintf(stderr, "Failed to allocate memory for set response\n"); exit(EXIT_FAILURE); } ensure_recv(bio, buffer, valuelen); } status = htons(response.message.header.response.status); if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) { result = 0; } else { fprintf(stderr, "Error from server: %s\n", memcached_protocol_errcode_2_text(status)); result = 1; } if (buffer != NULL) { fwrite(buffer, valuelen, 1, stdout); fputs("\n", stdout); fflush(stdout); free(buffer); } return result; }
static void *get_response(BIO *bio, protocol_binary_response_no_extras *res) { uint32_t vallen; ensure_recv(bio, res, sizeof(*res)); vallen = ntohl(res->message.header.response.bodylen); if (vallen == 0) { return NULL; } else { void *buffer = malloc(vallen); cb_assert(buffer != NULL); ensure_recv(bio, buffer, vallen); return buffer; } }
/** * Request all features from the server and dump the available ones * @param sock socket connected to the server * @param key the name of the stat to receive (NULL == ALL) */ static void request_hello(BIO *bio, const char *key) { protocol_binary_request_hello req; protocol_binary_response_hello res; char buffer[1024]; const char useragent[] = "mchello v1.0"; uint16_t nkey = (uint16_t)strlen(useragent); uint16_t features[MEMCACHED_TOTAL_HELLO_FEATURES]; uint32_t total = nkey + MEMCACHED_TOTAL_HELLO_FEATURES * 2; int ii; memset(&req, 0, sizeof(req)); req.message.header.request.magic = PROTOCOL_BINARY_REQ; req.message.header.request.opcode = PROTOCOL_BINARY_CMD_HELLO; req.message.header.request.bodylen = htonl(total); req.message.header.request.keylen = htons(nkey); req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; ensure_send(bio, &req, sizeof(req)); ensure_send(bio, useragent, nkey); for (ii = 0; ii < MEMCACHED_TOTAL_HELLO_FEATURES; ++ii) { features[ii] = htons(MEMCACHED_FIRST_HELLO_FEATURE + ii); } ensure_send(bio, &features, MEMCACHED_TOTAL_HELLO_FEATURES * 2); ensure_recv(bio, &res, sizeof(res.bytes)); total = ntohl(res.message.header.response.bodylen); ensure_recv(bio, buffer, total); if (res.message.header.response.status != 0) { fprintf(stderr, "Got return value: %d\n", ntohs(res.message.header.response.status)); return; } memcpy(features, buffer, total); total /= 2; fprintf(stdout, "Features:\n"); for (ii = 0; ii < total; ++ii) { fprintf(stderr, "\t- %s\n", protocol_feature_2_text(ntohs(features[ii]))); } }
/** * Request a stat from the server * @param sock socket connected to the server * @param key the name of the stat to receive (NULL == ALL) */ static void request_stat(BIO *bio, const char *key) { uint32_t buffsize = 0; char *buffer = NULL; uint16_t keylen = 0; protocol_binary_request_stats request; protocol_binary_response_no_extras response; if (key != NULL) { keylen = (uint16_t)strlen(key); } memset(&request, 0, sizeof(request)); request.message.header.request.magic = PROTOCOL_BINARY_REQ; request.message.header.request.opcode = PROTOCOL_BINARY_CMD_STAT; request.message.header.request.keylen = htons(keylen); request.message.header.request.bodylen = htonl(keylen); ensure_send(bio, &request, sizeof(request)); if (keylen > 0) { ensure_send(bio, key, keylen); } do { ensure_recv(bio, &response, sizeof(response.bytes)); if (response.message.header.response.keylen != 0) { uint16_t keylen = ntohs(response.message.header.response.keylen); uint32_t vallen = ntohl(response.message.header.response.bodylen); if (vallen > buffsize) { if ((buffer = realloc(buffer, vallen)) == NULL) { fprintf(stderr, "Failed to allocate memory\n"); exit(1); } buffsize = vallen; } ensure_recv(bio, buffer, vallen); print(buffer, keylen, buffer + keylen, vallen - keylen); } } while (response.message.header.response.keylen != 0); }
/** * Refresh the cbsasl password database * @param sock socket connected to the server */ static void refresh(BIO *bio) { protocol_binary_response_no_extras response; protocol_binary_request_no_extras request; memset(&request, 0, sizeof(request)); request.message.header.request.magic = PROTOCOL_BINARY_REQ; request.message.header.request.opcode = PROTOCOL_BINARY_CMD_ISASL_REFRESH; ensure_send(bio, &request, sizeof(request)); ensure_recv(bio, &response, sizeof(response.bytes)); if (response.message.header.response.status != 0) { uint16_t err = ntohs(response.message.header.response.status); fprintf(stderr, "Failed to refresh cbsasl passwd db: %d\n", err); } }
static int set_ascii(BIO *bio, const char *key, size_t size) { char line[1024]; int len = snprintf(line, sizeof(line), "set %s 0 0 %lu\r\n", key, (unsigned long)size); ensure_send(bio, &line, len); if (size > 0) { char* value = malloc(size); if (value) { ensure_send(bio, value, (int)size); free(value); } else { for (size_t ii = 0; ii < size; ++ii) { ensure_send(bio, key, 1); } } } ensure_send(bio, "\r\n", 2); memset(line, 0, sizeof(line)); int ii = -1; do { ++ii; ensure_recv(bio, line + ii, 1); } while (line[ii] != '\n'); while (ii >= 0 && isspace(line[ii])) { line[ii] = '\0'; --ii; } if (strcasecmp(line, "stored") == 0) { fprintf(stdout, "Stored %s with %lu bytes\n", key, (unsigned long)size); return EXIT_SUCCESS; } fprintf(stderr, "FAILURE: Received %s", line); return EXIT_FAILURE; }