static char * fetch(BIO *bio, const void *key, uint16_t nkey) { protocol_binary_request_get request; protocol_binary_response_no_extras response; char *payload; memset(&request, 0, sizeof(request)); request.message.header.request.magic = PROTOCOL_BINARY_REQ; request.message.header.request.opcode = PROTOCOL_BINARY_CMD_GET; request.message.header.request.keylen = htons((uint16_t)nkey); request.message.header.request.bodylen = htonl(nkey); ensure_send(bio, &request, sizeof(request.bytes)); ensure_send(bio, key, nkey); if (BIO_flush(bio) != 1) { fprintf(stderr, "Failed to flush bio instance\n"); exit(EXIT_FAILURE); } payload = get_response(bio, &response); cb_assert(ntohs(response.message.header.response.status) == PROTOCOL_BINARY_RESPONSE_SUCCESS); cb_assert(payload != NULL); return payload; }
/** * 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; }
/** * 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]))); } }
/** * Get the verbosity level on the server. * * There isn't a single command to retrieve the current verbosity level, * but it is available through the settings stats... * * @param bio connection to the server. */ static int get_verbosity(BIO *bio) { const char *settings = "settings"; const uint16_t settingslen = (uint16_t)strlen(settings); protocol_binary_request_stats request = { .message.header.request.magic = PROTOCOL_BINARY_REQ, .message.header.request.opcode = PROTOCOL_BINARY_CMD_STAT, .message.header.request.keylen = htons(settingslen), .message.header.request.bodylen = htonl(settingslen) }; ensure_send(bio, &request, sizeof(request)); ensure_send(bio, settings, settingslen); // loop and receive the result and print the verbosity when we get it struct statistic st; do { receive_stat_response(bio, &st); if (st.key != NULL && strcasecmp(st.key, "verbosity") == 0) { uint32_t level; if (safe_strtoul(st.value, &level)) { const char *levels[] = { "warning", "info", "debug", "detail", "unknown" }; const char *ptr = levels[4]; if (level < 4) { ptr = levels[level]; } fprintf(stderr, "%s\n", ptr); } else { fprintf(stderr, "%s\n", st.value); } } free(st.key); free(st.value); } while (st.key != NULL); return EXIT_SUCCESS; }
/** * 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); }
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; }
/** * 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); } }