*/
#include <libmemcached/common.h>
+#include <libmemcached/string.hpp>
static memcached_return_t textual_read_one_response(memcached_server_write_instance_st ptr,
char *buffer, size_t buffer_length,
memcached_return_t rc;
if (ptr->root->flags.binary_protocol)
+ {
rc= binary_read_one_response(ptr, buffer, buffer_length, result);
+ }
else
+ {
rc= textual_read_one_response(ptr, buffer, buffer_length, result);
+ }
- unlikely(rc == MEMCACHED_UNKNOWN_READ_FAILURE ||
- rc == MEMCACHED_PROTOCOL_ERROR ||
- rc == MEMCACHED_CLIENT_ERROR ||
+ unlikely(rc == MEMCACHED_UNKNOWN_READ_FAILURE or
+ rc == MEMCACHED_PROTOCOL_ERROR or
+ rc == MEMCACHED_CLIENT_ERROR or
rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
memcached_io_reset(ptr);
char *buffer,
memcached_result_st *result)
{
- memcached_return_t rc= MEMCACHED_SUCCESS;
char *string_ptr;
char *end_ptr;
char *next_ptr;
size_t value_length;
size_t to_read;
- char *value_ptr;
ssize_t read_length= 0;
- memcached_return_t rrc;
if (ptr->root->flags.use_udp)
- return memcached_set_error((memcached_st *)ptr->root, MEMCACHED_NOT_SUPPORTED);
+ return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
WATCHPOINT_ASSERT(ptr->root);
end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
key= result->item_key;
result->key_length= 0;
- for (prefix_length= memcached_array_size(ptr->root->prefix_key); !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++)
+ for (prefix_length= memcached_array_size(ptr->root->_namespace); !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++)
{
if (prefix_length == 0)
{
goto read_error;
/* We add two bytes so that we can walk the \r\n */
- rc= memcached_string_check(&result->value, value_length+2);
- if (rc != MEMCACHED_SUCCESS)
+ if (memcached_failed(memcached_string_check(&result->value, value_length +2)))
{
value_length= 0;
- return memcached_set_error((memcached_st *)ptr->root, MEMCACHED_MEMORY_ALLOCATION_FAILURE);
+ return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
}
- value_ptr= memcached_string_value_mutable(&result->value);
- /*
- We read the \r\n into the string since not doing so is more
- cycles then the waster of memory to do so.
-
- We are null terminating through, which will most likely make
- some people lazy about using the return length.
- */
- to_read= (value_length) + 2;
- rrc= memcached_io_read(ptr, value_ptr, to_read, &read_length);
- if (rrc != MEMCACHED_SUCCESS)
- return rrc;
+ {
+ char *value_ptr= memcached_string_value_mutable(&result->value);
+ /*
+ We read the \r\n into the string since not doing so is more
+ cycles then the waster of memory to do so.
+
+ We are null terminating through, which will most likely make
+ some people lazy about using the return length.
+ */
+ to_read= (value_length) + 2;
+ memcached_return_t rrc= memcached_io_read(ptr, value_ptr, to_read, &read_length);
+ if (memcached_failed(rrc) and rrc == MEMCACHED_IN_PROGRESS)
+ {
+ memcached_quit_server(ptr, true);
+ return memcached_set_error(*ptr, MEMCACHED_IN_PROGRESS, MEMCACHED_AT);
+ }
+ else if (memcached_failed(rrc))
+ {
+ return rrc;
+ }
+ }
if (read_length != (ssize_t)(value_length + 2))
{
char *char_ptr;
char_ptr= memcached_string_value_mutable(&result->value);;
char_ptr[value_length]= 0;
- char_ptr[value_length + 1]= 0;
+ char_ptr[value_length +1]= 0;
memcached_string_set_length(&result->value, value_length);
}
char *buffer, size_t buffer_length,
memcached_result_st *result)
{
- memcached_return_t rc= memcached_io_readline(ptr, buffer, buffer_length);
- if (rc != MEMCACHED_SUCCESS)
+ size_t total_read;
+ memcached_return_t rc= memcached_io_readline(ptr, buffer, buffer_length, total_read);
+
+ if (memcached_failed(rc))
+ {
return rc;
+ }
switch(buffer[0])
{
}
else if (buffer[1] == 'E') /* SERVER_ERROR */
{
- char *rel_ptr;
- char *startptr= buffer + 13, *endptr= startptr;
+ if (total_read == memcached_literal_param_size("SERVER_ERROR"))
+ {
+ return MEMCACHED_SERVER_ERROR;
+ }
- while (*endptr != '\r' && *endptr != '\n') endptr++;
+ if (total_read > memcached_literal_param_size("SERVER_ERROR object too large for cache") and
+ (memcmp(buffer, memcached_literal_param("SERVER_ERROR object too large for cache")) == 0))
+ {
+ return MEMCACHED_E2BIG;
+ }
- /*
- Yes, we could make this "efficent" but to do that we would need
- to maintain more state for the size of the buffer. Why waste
- memory in the struct, which is important, for something that
- rarely should happen?
- */
- rel_ptr= (char *)libmemcached_realloc(ptr->root,
- ptr->cached_server_error,
- (size_t) (endptr - startptr + 1));
-
- if (rel_ptr == NULL)
+ // Move past the basic error message and whitespace
+ char *startptr= buffer + memcached_literal_param_size("SERVER_ERROR");
+ if (startptr[0] == ' ')
{
- /* If we happened to have some memory, we just null it since we don't know the size */
- if (ptr->cached_server_error)
- ptr->cached_server_error[0]= 0;
- return MEMCACHED_SERVER_ERROR;
+ startptr++;
}
- ptr->cached_server_error= rel_ptr;
- memcpy(ptr->cached_server_error, startptr, (size_t) (endptr - startptr));
- ptr->cached_server_error[endptr - startptr]= 0;
- return MEMCACHED_SERVER_ERROR;
+ char *endptr= startptr;
+ while (*endptr != '\r' && *endptr != '\n') endptr++;
+
+ return memcached_set_error(*ptr, MEMCACHED_SERVER_ERROR, MEMCACHED_AT, startptr, size_t(endptr - startptr));
}
else if (buffer[1] == 'T')
+ {
return MEMCACHED_STORED;
+ }
else
{
WATCHPOINT_STRING(buffer);
}
case 'D': /* DELETED */
return MEMCACHED_DELETED;
+
case 'N': /* NOT_FOUND */
{
if (buffer[4] == 'F')
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);
+ header.response.cas= memcached_ntohll(header.response.cas);
uint32_t bodylen= header.response.bodylen;
if (header.response.status == PROTOCOL_BINARY_RESPONSE_SUCCESS ||
bodylen -= header.response.extlen;
result->key_length= keylen;
- if ((rc= memcached_safe_read(ptr, result->item_key, keylen)) != MEMCACHED_SUCCESS)
+ if (memcached_failed(rc= memcached_safe_read(ptr, result->item_key, keylen)))
{
WATCHPOINT_ERROR(rc);
return MEMCACHED_UNKNOWN_READ_FAILURE;
}
+ // Only bother with doing this if key_length > 0
+ if (result->key_length)
+ {
+ if (memcached_array_size(ptr->root->_namespace) and memcached_array_size(ptr->root->_namespace) >= result->key_length)
+ {
+ return memcached_set_error(*ptr, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
+ }
+
+ if (memcached_array_size(ptr->root->_namespace))
+ {
+ result->key_length-= memcached_array_size(ptr->root->_namespace);
+ memmove(result->item_key, result->item_key +memcached_array_size(ptr->root->_namespace), result->key_length);
+ }
+ }
+
bodylen -= keylen;
- if (memcached_string_check(&result->value,
- bodylen) != MEMCACHED_SUCCESS)
+ if (memcached_failed(memcached_string_check(&result->value, bodylen)))
+ {
return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
char *vptr= memcached_string_value_mutable(&result->value);
- if ((rc= memcached_safe_read(ptr, vptr, bodylen)) != MEMCACHED_SUCCESS)
+ if (memcached_failed(rc= memcached_safe_read(ptr, vptr, bodylen)))
{
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;
return MEMCACHED_UNKNOWN_READ_FAILURE;
}
- val= ntohll(val);
+ val= memcached_ntohll(val);
memcpy(buffer, &val, sizeof(val));
}
break;
+
case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS:
case PROTOCOL_BINARY_CMD_VERSION:
{
if ((rc= memcached_safe_read(ptr, hole, nr)) != MEMCACHED_SUCCESS)
{
WATCHPOINT_ERROR(rc);
- return memcached_set_error((memcached_st *)ptr->root, MEMCACHED_UNKNOWN_READ_FAILURE);
+ return memcached_set_error(*ptr, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
}
bodylen-= (uint32_t) nr;
}
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: