Update logic around UDP.
[m6w6/libmemcached] / libmemcached / response.cc
index b8d9e0b6e406928aaea3a7e8e21394c9a57c0a45..445b92338b29ca5d45d4c6988298dc1600860b99 100644 (file)
 #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_result_st *result);
-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 memcached_read_one_response(memcached_server_write_instance_st ptr,
-                                               char *buffer, size_t buffer_length,
-                                               memcached_result_st *result)
-{
-  memcached_server_response_decrement(ptr);
-
-  if (result == NULL)
-  {
-    memcached_st *root= (memcached_st *)ptr->root;
-    result = &root->result;
-  }
-
-  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 or
-           rc == MEMCACHED_PROTOCOL_ERROR or
-           rc == MEMCACHED_CLIENT_ERROR or
-           rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
-  {
-    memcached_io_reset(ptr);
-  }
-
-  return rc;
-}
-
-memcached_return_t memcached_response(memcached_server_write_instance_st ptr,
-                                      char *buffer, size_t buffer_length,
-                                      memcached_result_st *result)
-{
-  /* We may have old commands in the buffer not set, first purge */
-  if ((ptr->root->flags.no_block) && (memcached_is_processing_input(ptr->root) == false))
-  {
-    (void)memcached_io_write(ptr, NULL, 0, true);
-  }
-
-  /*
-   * The previous implementation purged all pending requests and just
-   * returned the last one. Purge all pending messages to ensure backwards
-   * compatibility.
- */
-  if (ptr->root->flags.binary_protocol == false)
-  {
-    while (memcached_server_response_count(ptr) > 1)
-    {
-      memcached_return_t rc= memcached_read_one_response(ptr, buffer, buffer_length, result);
-
-      unlikely (rc != MEMCACHED_END &&
-                rc != MEMCACHED_STORED &&
-                rc != MEMCACHED_SUCCESS &&
-                rc != MEMCACHED_STAT &&
-                rc != MEMCACHED_DELETED &&
-                rc != MEMCACHED_NOTFOUND &&
-                rc != MEMCACHED_NOTSTORED &&
-                rc != MEMCACHED_DATA_EXISTS)
-        return rc;
-    }
-  }
-
-  return memcached_read_one_response(ptr, buffer, buffer_length, result);
-}
-
 static memcached_return_t textual_value_fetch(memcached_server_write_instance_st ptr,
                                               char *buffer,
                                               memcached_result_st *result)
 {
-  char *string_ptr;
-  char *end_ptr;
   char *next_ptr;
-  size_t value_length;
-  size_t to_read;
   ssize_t read_length= 0;
-
-  if (ptr->root->flags.use_udp)
-  {
-    return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
-  }
+  size_t value_length;
 
   WATCHPOINT_ASSERT(ptr->root);
-  end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
+  char *end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
 
   memcached_result_reset(result);
 
-  string_ptr= buffer;
+  char *string_ptr= buffer;
   string_ptr+= 6; /* "VALUE " */
 
 
@@ -162,23 +78,31 @@ static memcached_return_t textual_value_fetch(memcached_server_write_instance_st
   }
 
   if (end_ptr == string_ptr)
+  {
     goto read_error;
+  }
 
   /* Flags fetch move past space */
   string_ptr++;
   if (end_ptr == string_ptr)
+  {
     goto read_error;
+  }
 
   for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++) {};
   result->item_flags= (uint32_t) strtoul(next_ptr, &string_ptr, 10);
 
   if (end_ptr == string_ptr)
+  {
     goto read_error;
+  }
 
   /* Length fetch move past space*/
   string_ptr++;
   if (end_ptr == string_ptr)
+  {
     goto read_error;
+  }
 
   for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++) {};
   value_length= (size_t)strtoull(next_ptr, &string_ptr, 10);
@@ -202,7 +126,9 @@ static memcached_return_t textual_value_fetch(memcached_server_write_instance_st
   }
 
   if (end_ptr < string_ptr)
+  {
     goto read_error;
+  }
 
   /* We add two bytes so that we can walk the \r\n */
   if (memcached_failed(memcached_string_check(&result->value, value_length +2)))
@@ -219,7 +145,7 @@ static memcached_return_t textual_value_fetch(memcached_server_write_instance_st
       We are null terminating through, which will most likely make
       some people lazy about using the return length.
     */
-    to_read= (value_length) + 2;
+    size_t 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)
     {
@@ -256,8 +182,10 @@ read_error:
 
 static memcached_return_t textual_read_one_response(memcached_server_write_instance_st ptr,
                                                     char *buffer, size_t buffer_length,
-                                                    memcached_result_st *result)
+                                                    memcached_result_st *result,
+                                                    uint64_t& numeric_value)
 {
+  numeric_value= UINT64_MAX;
   size_t total_read;
   memcached_return_t rc= memcached_io_readline(ptr, buffer, buffer_length, total_read);
 
@@ -359,7 +287,9 @@ static memcached_return_t textual_read_one_response(memcached_server_write_insta
       {
         return MEMCACHED_END;
       }
-      else if (buffer[1] == 'R' and buffer[2] == 'R' and buffer[3] == 'O' and buffer[4] == 'R')
+      else if (buffer[1] == 'R' and buffer[2] == 'O' and buffer[3] == 'T' and buffer[4] == 'O' and buffer[5] == 'C' and buffer[6] == 'O' and buffer[7] == 'L'
+               and buffer[8] == '_'
+               and buffer[9] == 'E' and buffer[10] == 'R' and buffer[11] == 'R' and buffer[12] == 'O' and buffer[13] == 'R')
       {
         return MEMCACHED_PROTOCOL_ERROR;
       }
@@ -410,13 +340,17 @@ static memcached_return_t textual_read_one_response(memcached_server_write_insta
 
       if (auto_return_value == ULLONG_MAX and errno == ERANGE)
       {
-        return MEMCACHED_UNKNOWN_READ_FAILURE;
+        return memcached_set_error(*ptr, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT,
+                                   memcached_literal_param("Numeric response was out of range"));
       }
       else if (errno == EINVAL)
       {
-        return MEMCACHED_UNKNOWN_READ_FAILURE;
+        return memcached_set_error(*ptr, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT,
+                                   memcached_literal_param("Numeric response was out of range"));
       }
 
+      numeric_value= uint64_t(auto_return_value);
+
       WATCHPOINT_STRING(buffer);
       return MEMCACHED_SUCCESS;
     }
@@ -425,7 +359,8 @@ static memcached_return_t textual_read_one_response(memcached_server_write_insta
     break;
   }
 
-  return MEMCACHED_UNKNOWN_READ_FAILURE;
+  return memcached_set_error(*ptr, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT,
+                             memcached_literal_param("Could not determine response"));
 }
 
 static memcached_return_t binary_read_one_response(memcached_server_write_instance_st ptr,
@@ -524,7 +459,7 @@ static memcached_return_t binary_read_one_response(memcached_server_write_instan
     case PROTOCOL_BINARY_CMD_INCREMENT:
     case PROTOCOL_BINARY_CMD_DECREMENT:
       {
-        if (bodylen != sizeof(uint64_t) || buffer_length != sizeof(uint64_t))
+        if (bodylen != sizeof(uint64_t) or buffer_length != sizeof(uint64_t))
         {
           return MEMCACHED_PROTOCOL_ERROR;
         }
@@ -708,3 +643,105 @@ static memcached_return_t binary_read_one_response(memcached_server_write_instan
 
   return rc;
 }
+
+memcached_return_t memcached_read_one_response(memcached_server_write_instance_st ptr,
+                                               char *buffer, size_t buffer_length,
+                                               memcached_result_st *result)
+{
+  uint64_t numeric_value;
+
+  return memcached_read_one_response(ptr, buffer, buffer_length, result, numeric_value);
+}
+
+memcached_return_t memcached_read_one_response(memcached_server_write_instance_st ptr,
+                                               char *buffer, size_t buffer_length,
+                                               memcached_result_st *result,
+                                               uint64_t& numeric_value)
+{
+  if (memcached_is_udp(ptr->root))
+  {
+    return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
+  }
+
+  memcached_server_response_decrement(ptr);
+
+  if (result == NULL)
+  {
+    memcached_st *root= (memcached_st *)ptr->root;
+    result = &root->result;
+  }
+
+  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, numeric_value);
+  }
+
+  if (rc == MEMCACHED_UNKNOWN_READ_FAILURE or
+      rc == MEMCACHED_READ_FAILURE or
+      rc == MEMCACHED_PROTOCOL_ERROR or
+      rc == MEMCACHED_CLIENT_ERROR or
+      rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
+  {
+    memcached_io_reset(ptr);
+  }
+
+  return rc;
+}
+
+memcached_return_t memcached_response(memcached_server_write_instance_st ptr,
+                                      char *buffer, size_t buffer_length,
+                                      memcached_result_st *result)
+{
+  uint64_t numeric_value;
+
+  return memcached_response(ptr, buffer, buffer_length, result, numeric_value);
+}
+
+memcached_return_t memcached_response(memcached_server_write_instance_st ptr,
+                                      char *buffer, size_t buffer_length,
+                                      memcached_result_st *result,
+                                      uint64_t& numeric_value)
+{
+  if (memcached_is_udp(ptr->root))
+  {
+    return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
+  }
+
+  /* We may have old commands in the buffer not set, first purge */
+  if ((ptr->root->flags.no_block) and (memcached_is_processing_input(ptr->root) == false))
+  {
+    (void)memcached_io_write(ptr);
+  }
+
+  /*
+   * The previous implementation purged all pending requests and just
+   * returned the last one. Purge all pending messages to ensure backwards
+   * compatibility.
+ */
+  if (memcached_is_binary(ptr->root) == false)
+  {
+    while (memcached_server_response_count(ptr) > 1)
+    {
+      memcached_return_t rc= memcached_read_one_response(ptr, buffer, buffer_length, result, numeric_value);
+
+      if (rc != MEMCACHED_END &&
+          rc != MEMCACHED_STORED &&
+          rc != MEMCACHED_SUCCESS &&
+          rc != MEMCACHED_STAT &&
+          rc != MEMCACHED_DELETED &&
+          rc != MEMCACHED_NOTFOUND &&
+          rc != MEMCACHED_NOTSTORED &&
+          rc != MEMCACHED_DATA_EXISTS)
+      {
+        return rc;
+      }
+    }
+  }
+
+  return memcached_read_one_response(ptr, buffer, buffer_length, result, numeric_value);
+}