static test_return_t drizzle(memcached_st *memc) { memcached_return_t rc; char *return_value; size_t return_value_length; uint32_t flags; infinite: for (size_t x= 0; x < TEST_COUNTER; x++) { uint32_t test_bit; uint8_t which; test_bit= (uint32_t)(random() % GLOBAL_COUNT); which= (uint8_t)(random() % 2); if (which == 0) { return_value= memcached_get(memc, global_keys[test_bit], global_keys_length[test_bit], &return_value_length, &flags, &rc); if (rc == MEMCACHED_SUCCESS && return_value) { free(return_value); } else if (rc == MEMCACHED_NOTFOUND) { continue; } else { WATCHPOINT_ERROR(rc); WATCHPOINT_ASSERT(rc); } } else { rc= memcached_set(memc, global_pairs[test_bit].key, global_pairs[test_bit].key_length, global_pairs[test_bit].value, global_pairs[test_bit].value_length, 0, 0); if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED) { WATCHPOINT_ERROR(rc); WATCHPOINT_ASSERT(0); } } } if (getenv("MEMCACHED_ATOM_BURIN_IN")) goto infinite; return TEST_SUCCESS; }
memcached_return_t memcached_vdo(memcached_server_write_instance_st ptr, const struct libmemcached_io_vector_st *vector, size_t count, bool with_flush) { memcached_return_t rc; ssize_t sent_length; size_t command_length= 0; uint32_t x; WATCHPOINT_ASSERT(count); WATCHPOINT_ASSERT(vector); if ((rc= memcached_connect(ptr)) != MEMCACHED_SUCCESS) { WATCHPOINT_ERROR(rc); return rc; } /* ** Since non buffering ops in UDP mode dont check to make sure they will fit ** before they start writing, if there is any data in buffer, clear it out, ** otherwise we might get a partial write. **/ if (ptr->type == MEMCACHED_CONNECTION_UDP && with_flush && ptr->write_buffer_offset > UDP_DATAGRAM_HEADER_LENGTH) { memcached_io_write(ptr, NULL, 0, true); } sent_length= memcached_io_writev(ptr, vector, count, with_flush); for (x= 0; x < count; ++x, vector++) { command_length+= vector->length; } if (sent_length == -1 || (size_t)sent_length != command_length) { rc= MEMCACHED_WRITE_FAILURE; WATCHPOINT_ERROR(rc); WATCHPOINT_ERRNO(errno); } else if ((ptr->root->flags.no_reply) == 0) { memcached_server_response_increment(ptr); } return rc; }
memcached_return memcached_do(memcached_server_st *ptr, const void *command, size_t command_length, uint8_t with_flush) { memcached_return rc; ssize_t sent_length; WATCHPOINT_ASSERT(command_length); WATCHPOINT_ASSERT(command); if ((rc= memcached_connect(ptr)) != MEMCACHED_SUCCESS) { WATCHPOINT_ERROR(rc); return rc; } /* ** Since non buffering ops in UDP mode dont check to make sure they will fit ** before they start writing, if there is any data in buffer, clear it out, ** otherwise we might get a partial write. **/ if (ptr->type == MEMCACHED_CONNECTION_UDP && with_flush && ptr->write_buffer_offset > UDP_DATAGRAM_HEADER_LENGTH) memcached_io_write(ptr, NULL, 0, 1); sent_length= memcached_io_write(ptr, command, command_length, (char) with_flush); if (sent_length == -1 || (size_t)sent_length != command_length) rc= MEMCACHED_WRITE_FAILURE; else if ((ptr->root->flags & MEM_NOREPLY) == 0) memcached_server_response_increment(ptr); return rc; }
memcached_return memcached_vdo(memcached_server_st *ptr, const struct libmemcached_io_vector_st *vector, size_t count, uint8_t with_flush) { memcached_return rc; ssize_t sent_length; size_t command_length; uint32_t x; WATCHPOINT_ASSERT(count); WATCHPOINT_ASSERT(vector); if ((rc= memcached_connect(ptr)) != MEMCACHED_SUCCESS) { WATCHPOINT_ERROR(rc); return rc; } if (ptr->type == MEMCACHED_CONNECTION_UDP && with_flush && ptr->write_buffer_offset > UDP_DATAGRAM_HEADER_LENGTH) { memcached_io_write(ptr, NULL, 0, true); } sent_length= memcached_io_writev(ptr, vector, count, (char) with_flush); command_length = 0; for (x= 0; x < count; ++x, vector++) command_length+= vector->length; if (sent_length == -1 || (size_t)sent_length != command_length) { rc = MEMCACHED_WRITE_FAILURE; WATCHPOINT_ERROR(rc); } else if ((ptr->root->flags & MEM_NOREPLY) == 0) memcached_server_response_increment(ptr); return rc; }
memcached_return memcached_flush_buffers(memcached_st *mem) { memcached_return ret= MEMCACHED_SUCCESS; for (int x= 0; x < mem->number_of_hosts; ++x) if (mem->hosts[x].write_buffer_offset != 0) { if (mem->hosts[x].fd == -1 && (ret= memcached_connect(&mem->hosts[x])) != MEMCACHED_SUCCESS) { WATCHPOINT_ERROR(ret); return ret; } if (memcached_io_write(&mem->hosts[x], NULL, 0, 1) == -1) ret= MEMCACHED_SOME_ERRORS; } return ret; }
memcached_return_t memcached_purge(memcached_server_write_instance_st ptr) { uint32_t x; memcached_return_t ret= MEMCACHED_SUCCESS; memcached_st *root= (memcached_st *)ptr->root; uint32_t no_msg; if (memcached_is_purging(ptr->root) || /* already purging */ (memcached_server_response_count(ptr) < ptr->root->io_msg_watermark && ptr->io_bytes_sent < ptr->root->io_bytes_watermark) || (ptr->io_bytes_sent >= ptr->root->io_bytes_watermark && memcached_server_response_count(ptr) < 2)) { return MEMCACHED_SUCCESS; } /* memcached_io_write and memcached_response may call memcached_purge so we need to be able stop any recursion.. */ memcached_set_purging(root, true); WATCHPOINT_ASSERT(ptr->fd != -1); /* Force a flush of the buffer to ensure that we don't have the n-1 pending requests buffered up.. */ if (memcached_io_write(ptr, NULL, 0, true) == -1) { memcached_set_purging(root, true); return MEMCACHED_WRITE_FAILURE; } WATCHPOINT_ASSERT(ptr->fd != -1); no_msg= memcached_server_response_count(ptr) - 1; if (no_msg > 0) { memcached_result_st result; memcached_result_st *result_ptr; char buffer[SMALL_STRING_LEN]; /* * We need to increase the timeout, because we might be waiting for * data to be sent from the server (the commands was in the output buffer * and just flushed */ const int32_t timeo= ptr->root->poll_timeout; root->poll_timeout= 2000; result_ptr= memcached_result_create(root, &result); WATCHPOINT_ASSERT(result_ptr); for (x= 0; x < no_msg; x++) { memcached_return_t rc; memcached_result_reset(result_ptr); rc= memcached_read_one_response(ptr, buffer, sizeof (buffer), result_ptr); /* * Purge doesn't care for what kind of command results that is received. * The only kind of errors I care about if is I'm out of sync with the * protocol or have problems reading data from the network.. */ if (rc== MEMCACHED_PROTOCOL_ERROR || rc == MEMCACHED_UNKNOWN_READ_FAILURE) { WATCHPOINT_ERROR(rc); ret = rc; memcached_io_reset(ptr); } if (ptr->root->callbacks != NULL) { memcached_callback_st cb = *ptr->root->callbacks; if (rc == MEMCACHED_SUCCESS) { uint32_t y; for (y= 0; y < cb.number_of_callback; y++) { rc = (*cb.callback[y])(ptr->root, result_ptr, cb.context); if (rc != MEMCACHED_SUCCESS) break; } } } } memcached_result_free(result_ptr); root->poll_timeout= timeo; } memcached_set_purging(root, false); return ret; }
static memcached_return_t binary_read_one_response(memcached_server_write_instance_st ptr, char *buffer, size_t buffer_length, memcached_result_st *result) { memcached_return_t rc; protocol_binary_response_header header; if (ptr->root->flags.use_udp) { // This is how we detect we are expecting a new UDP response ptr->num_datagrams = 0; } for (;;) { if ((rc= memcached_safe_read(ptr, &header.bytes, sizeof(header.bytes))) != MEMCACHED_SUCCESS) { WATCHPOINT_ERROR(rc); return rc; } if (memcached_server_response_decrement(ptr, header.response.opaque)) { break; } else { memcached_safe_read(ptr, NULL, ntohl(header.response.bodylen)); } } if (header.response.magic != PROTOCOL_BINARY_RES) { return MEMCACHED_PROTOCOL_ERROR; } /* * Convert the header to host local endian! */ header.response.keylen= ntohs(header.response.keylen); header.response.status= ntohs(header.response.status); header.response.bodylen= ntohl(header.response.bodylen); header.response.cas= ntohll(header.response.cas); uint32_t bodylen= header.response.bodylen; if (header.response.status == PROTOCOL_BINARY_RESPONSE_SUCCESS || header.response.status == PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE) { switch (header.response.opcode) { case PROTOCOL_BINARY_CMD_GETKQ: /* * We didn't increment the response counter for the GETKQ packet * (only the final NOOP), so we need to increment the counter again. */ if (!ptr->root->flags.check_opaque) { memcached_server_response_increment(ptr, 0); } /* FALLTHROUGH */ case PROTOCOL_BINARY_CMD_GETK: { uint16_t keylen= header.response.keylen; memcached_result_reset(result); result->item_cas= header.response.cas; if ((rc= memcached_safe_read(ptr, &result->item_flags, sizeof (result->item_flags))) != MEMCACHED_SUCCESS) { WATCHPOINT_ERROR(rc); return MEMCACHED_UNKNOWN_READ_FAILURE; } result->item_flags= ntohl(result->item_flags); bodylen -= header.response.extlen; result->key_length= keylen; if ((rc= memcached_safe_read(ptr, result->item_key, keylen)) != MEMCACHED_SUCCESS) { WATCHPOINT_ERROR(rc); return MEMCACHED_UNKNOWN_READ_FAILURE; } bodylen -= keylen; if (memcached_string_check(&result->value, bodylen) != MEMCACHED_SUCCESS) return MEMCACHED_MEMORY_ALLOCATION_FAILURE; char *vptr= memcached_string_value_mutable(&result->value); if ((rc= memcached_safe_read(ptr, vptr, bodylen)) != MEMCACHED_SUCCESS) { WATCHPOINT_ERROR(rc); return MEMCACHED_UNKNOWN_READ_FAILURE; } memcached_string_set_length(&result->value, bodylen); } break; case PROTOCOL_BINARY_CMD_INCREMENT: case PROTOCOL_BINARY_CMD_DECREMENT: { if (bodylen != sizeof(uint64_t) || buffer_length != sizeof(uint64_t)) return MEMCACHED_PROTOCOL_ERROR; WATCHPOINT_ASSERT(bodylen == buffer_length); uint64_t val; if ((rc= memcached_safe_read(ptr, &val, sizeof(val))) != MEMCACHED_SUCCESS) { WATCHPOINT_ERROR(rc); return MEMCACHED_UNKNOWN_READ_FAILURE; } val= ntohll(val); memcpy(buffer, &val, sizeof(val)); } break; case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS: case PROTOCOL_BINARY_CMD_VERSION: { memset(buffer, 0, buffer_length); if (bodylen >= buffer_length) { /* not enough space in buffer.. should not happen... */ return MEMCACHED_UNKNOWN_READ_FAILURE; } else if ((rc= memcached_safe_read(ptr, buffer, bodylen)) != MEMCACHED_SUCCESS) { WATCHPOINT_ERROR(rc); return MEMCACHED_UNKNOWN_READ_FAILURE; } } break; case PROTOCOL_BINARY_CMD_FLUSH: case PROTOCOL_BINARY_CMD_QUIT: case PROTOCOL_BINARY_CMD_SET: case PROTOCOL_BINARY_CMD_ADD: case PROTOCOL_BINARY_CMD_REPLACE: case PROTOCOL_BINARY_CMD_APPEND: case PROTOCOL_BINARY_CMD_PREPEND: case PROTOCOL_BINARY_CMD_DELETE: { WATCHPOINT_ASSERT(bodylen == 0); return MEMCACHED_SUCCESS; } case PROTOCOL_BINARY_CMD_NOOP: { WATCHPOINT_ASSERT(bodylen == 0); return MEMCACHED_END; } case PROTOCOL_BINARY_CMD_STAT: { if (bodylen == 0) { return MEMCACHED_END; } else if (bodylen + 1 > buffer_length) { /* not enough space in buffer.. should not happen... */ return MEMCACHED_UNKNOWN_READ_FAILURE; } else { size_t keylen= header.response.keylen; memset(buffer, 0, buffer_length); if ((rc= memcached_safe_read(ptr, buffer, keylen)) != MEMCACHED_SUCCESS || (rc= memcached_safe_read(ptr, buffer + keylen + 1, bodylen - keylen)) != MEMCACHED_SUCCESS) { WATCHPOINT_ERROR(rc); return MEMCACHED_UNKNOWN_READ_FAILURE; } if (header.response.keylen > 0) { memcached_server_response_increment(ptr, header.response.opaque); } } } break; case PROTOCOL_BINARY_CMD_SASL_AUTH: case PROTOCOL_BINARY_CMD_SASL_STEP: { memcached_result_reset(result); result->item_cas= header.response.cas; if (memcached_string_check(&result->value, bodylen) != MEMCACHED_SUCCESS) return MEMCACHED_MEMORY_ALLOCATION_FAILURE; char *vptr= memcached_string_value_mutable(&result->value); if ((rc= memcached_safe_read(ptr, vptr, bodylen)) != MEMCACHED_SUCCESS) { WATCHPOINT_ERROR(rc); return MEMCACHED_UNKNOWN_READ_FAILURE; } memcached_string_set_length(&result->value, bodylen); } break; default: { /* Command not implemented yet! */ WATCHPOINT_ASSERT(0); return MEMCACHED_PROTOCOL_ERROR; } } } else if (header.response.bodylen) { /* What should I do with the error message??? just discard it for now */ char hole[SMALL_STRING_LEN]; while (bodylen > 0) { size_t nr= (bodylen > SMALL_STRING_LEN) ? SMALL_STRING_LEN : bodylen; if ((rc= memcached_safe_read(ptr, hole, nr)) != MEMCACHED_SUCCESS) { WATCHPOINT_ERROR(rc); return MEMCACHED_UNKNOWN_READ_FAILURE; } bodylen-= (uint32_t) nr; } /* This might be an error from one of the quiet commands.. if * so, just throw it away and get the next one. What about creating * a callback to the user with the error information? */ switch (header.response.opcode) { case PROTOCOL_BINARY_CMD_SETQ: case PROTOCOL_BINARY_CMD_ADDQ: case PROTOCOL_BINARY_CMD_REPLACEQ: case PROTOCOL_BINARY_CMD_APPENDQ: case PROTOCOL_BINARY_CMD_PREPENDQ: if (!ptr->root->flags.check_opaque) memcached_server_response_increment(ptr, 0); return binary_read_one_response(ptr, buffer, buffer_length, result); default: break; } } rc= MEMCACHED_SUCCESS; unlikely(header.response.status != 0) switch (header.response.status) { case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT: rc= MEMCACHED_NOTFOUND; break; case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS: rc= MEMCACHED_DATA_EXISTS; break; case PROTOCOL_BINARY_RESPONSE_NOT_STORED: rc= MEMCACHED_NOTSTORED; break; case PROTOCOL_BINARY_RESPONSE_E2BIG: rc= MEMCACHED_E2BIG; break; case PROTOCOL_BINARY_RESPONSE_ENOMEM: rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE; break; case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE: rc= MEMCACHED_AUTH_CONTINUE; break; case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR: rc= MEMCACHED_AUTH_FAILURE; break; case PROTOCOL_BINARY_RESPONSE_EINVAL: case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND: default: /* @todo fix the error mappings */ rc= MEMCACHED_PROTOCOL_ERROR; break; } return rc; }