Make sure we use the correct strerror() in case someone is using threads.
[awesomized/libmemcached] / libmemcached / protocol / ascii_handler.c
index 8238a36dd5bac6cae561525b1518c83b1889e979..5e7307ae7cdcdbd50fc2fdfd4ab8f6326da2407d 100644 (file)
@@ -1,10 +1,48 @@
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#include "libmemcached/protocol/common.h"
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ *
+ *      * Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *
+ *      * Redistributions in binary form must reproduce the above
+ *  copyright notice, this list of conditions and the following disclaimer
+ *  in the documentation and/or other materials provided with the
+ *  distribution.
+ *
+ *      * The names of its contributors may not be used to endorse or
+ *  promote products derived from this software without specific prior
+ *  written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+
+#include <libmemcached/protocol/common.h>
+#include <libmemcached/byteorder.h>
 
 #include <ctype.h>
-#include <string.h>
-#include <strings.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 /**
  * Try to parse a key from the string.
@@ -16,7 +54,7 @@
 static uint16_t parse_ascii_key(char **start)
 {
   uint16_t len= 0;
-  char *c = *start;
+  char *c= *start;
   /* Strip leading whitespaces */
   while (isspace(*c))
   {
@@ -47,7 +85,7 @@ static uint16_t parse_ascii_key(char **start)
  * @return status of the spool operation
  */
 static protocol_binary_response_status
-spool_string(struct memcached_protocol_client_st *client, const char *text)
+spool_string(memcached_protocol_client_st *client, const char *text)
 {
   return client->root->spool(client, text, strlen(text));
 }
@@ -57,7 +95,7 @@ spool_string(struct memcached_protocol_client_st *client, const char *text)
  * format of the command being sent
  * @param client the client to send the message to
  */
-static void send_command_usage(struct memcached_protocol_client_st *client)
+static void send_command_usage(memcached_protocol_client_st *client)
 {
   const char *errmsg[]= {
     [GET_CMD]= "CLIENT_ERROR: Syntax error: get <key>*\r\n",
@@ -80,6 +118,7 @@ static void send_command_usage(struct memcached_protocol_client_st *client)
     [UNKNOWN_CMD]= "CLIENT_ERROR: Unknown command\r\n",
   };
 
+  client->mute = false;
   spool_string(client, errmsg[client->ascii_command]);
 }
 
@@ -91,10 +130,10 @@ static void send_command_usage(struct memcached_protocol_client_st *client)
  */
 static protocol_binary_response_status
 ascii_version_response_handler(const void *cookie,
-                         const void *text,
-                         uint32_t textlen)
+                               const void *text,
+                               uint32_t textlen)
 {
-  struct memcached_protocol_client_st *client= (void*)cookie;
+  memcached_protocol_client_st *client= (memcached_protocol_client_st*)cookie;
   spool_string(client, "VERSION ");
   client->root->spool(client, text, textlen);
   spool_string(client, "\r\n");
@@ -120,17 +159,17 @@ ascii_get_response_handler(const void *cookie,
                            uint32_t flags,
                            uint64_t cas)
 {
-  struct memcached_protocol_client_st *client= (void*)cookie;
+  memcached_protocol_client_st *client= (void*)cookie;
   char buffer[300];
   strcpy(buffer, "VALUE ");
-  const char *source = key;
-  char *dest = buffer + 6;
+  const char *source= key;
+  char *dest= buffer + 6;
 
   for (int x= 0; x < keylen; ++x)
   {
     if (*source != '\0' && !isspace(*source) && !iscntrl(*source))
     {
-      *dest = *source;
+      *dest= *source;
     }
     else
     {
@@ -145,12 +184,12 @@ ascii_get_response_handler(const void *cookie,
 
   if (client->ascii_command == GETS_CMD)
   {
-    snprintf(dest, sizeof(buffer) - used, " %u %u %llu\r\n", flags,
-             flags, (unsigned long long)cas);
+    snprintf(dest, sizeof(buffer) - used, " %u %u %" PRIu64 "\r\n", flags,
+             bodylen, cas);
   }
   else
   {
-    snprintf(dest, sizeof(buffer) - used, " %u %u\r\n", flags, flags);
+    snprintf(dest, sizeof(buffer) - used, " %u %u\r\n", flags, bodylen);
   }
 
   client->root->spool(client, buffer, strlen(buffer));
@@ -176,7 +215,7 @@ ascii_stat_response_handler(const void *cookie,
                      uint32_t bodylen)
 {
 
-  struct memcached_protocol_client_st *client= (void*)cookie;
+  memcached_protocol_client_st *client= (void*)cookie;
 
   if (key != NULL)
   {
@@ -200,7 +239,7 @@ ascii_stat_response_handler(const void *cookie,
  * @param buffer the complete get(s) command
  * @param end the last character in the command
  */
-static void ascii_process_gets(struct memcached_protocol_client_st *client,
+static void ascii_process_gets(memcached_protocol_client_st *client,
                                char *buffer, char *end)
 {
   char *key= buffer;
@@ -265,7 +304,7 @@ static int ascii_tokenize_command(char *str, char *end, char **vec, int size)
     }
 
     /* zero-terminate it for easier parsing later on */
-    *str = '\0';
+    *str= '\0';
     ++str;
 
     /* Is the vector full? */
@@ -292,7 +331,7 @@ static void recover_tokenize_command(char *start, char *end)
   while (start < end)
   {
     if (*start == '\0')
-      *start = ' ';
+      *start= ' ';
     ++start;
   }
 
@@ -308,7 +347,7 @@ static enum ascii_cmd ascii_to_cmd(char *start, size_t length)
     const char *cmd;
     size_t len;
     enum ascii_cmd cc;
-  } commands[] = {
+  } commands[]= {
     { .cmd= "get", .len= 3, .cc= GET_CMD },
     { .cmd= "gets", .len= 4, .cc= GETS_CMD },
     { .cmd= "set", .len= 3, .cc= SET_CMD },
@@ -353,7 +392,7 @@ static enum ascii_cmd ascii_to_cmd(char *start, size_t length)
  * @param tokens the command as a vector
  * @param ntokens the number of items in the vector
  */
-static void process_delete(struct memcached_protocol_client_st *client,
+static void process_delete(memcached_protocol_client_st *client,
                            char **tokens, int ntokens)
 {
   char *key= tokens[1];
@@ -385,12 +424,12 @@ static void process_delete(struct memcached_protocol_client_st *client,
   else
   {
     char msg[80];
-    snprintf(msg, sizeof(msg), "SERVER_ERROR: delete failed %u\r\n",(int)rval);
+    snprintf(msg, sizeof(msg), "SERVER_ERROR: delete failed %u\r\n",(uint32_t)rval);
     spool_string(client, msg);
   }
 }
 
-static void process_arithmetic(struct memcached_protocol_client_st *client,
+static void process_arithmetic(memcached_protocol_client_st *client,
                                char **tokens, int ntokens)
 {
   char *key= tokens[1];
@@ -404,7 +443,7 @@ static void process_arithmetic(struct memcached_protocol_client_st *client,
 
   uint64_t cas;
   uint64_t result;
-  uint64_t delta = strtoull(tokens[2], NULL, 10);
+  uint64_t delta= strtoull(tokens[2], NULL, 10);
 
   protocol_binary_response_status rval;
   if (client->ascii_command == INCR_CMD)
@@ -439,8 +478,7 @@ static void process_arithmetic(struct memcached_protocol_client_st *client,
   if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
   {
     char buffer[80];
-    snprintf(buffer, sizeof(buffer), "%llu\r\n",
-             (unsigned long long)result);
+    snprintf(buffer, sizeof(buffer), "%"PRIu64"\r\n", result);
     spool_string(client, buffer);
   }
   else
@@ -454,7 +492,7 @@ static void process_arithmetic(struct memcached_protocol_client_st *client,
  * @param key pointer to the first character after "stats"
  * @param end pointer to the "\n"
  */
-static void process_stats(struct memcached_protocol_client_st *client,
+static void process_stats(memcached_protocol_client_st *client,
                           char *key, char *end)
 {
   if (client->root->callback->interface.v1.stat == NULL)
@@ -471,7 +509,7 @@ static void process_stats(struct memcached_protocol_client_st *client,
                                                   ascii_stat_response_handler);
 }
 
-static void process_version(struct memcached_protocol_client_st *client,
+static void process_version(memcached_protocol_client_st *client,
                             char **tokens, int ntokens)
 {
   (void)tokens;
@@ -491,7 +529,7 @@ static void process_version(struct memcached_protocol_client_st *client,
                                               ascii_version_response_handler);
 }
 
-static void process_flush(struct memcached_protocol_client_st *client,
+static void process_flush(memcached_protocol_client_st *client,
                           char **tokens, int ntokens)
 {
   if (ntokens > 2)
@@ -509,7 +547,7 @@ static void process_flush(struct memcached_protocol_client_st *client,
   uint32_t timeout= 0;
   if (ntokens == 2)
   {
-    timeout = (uint32_t)strtoul(tokens[1], NULL, 10);
+    timeout= (uint32_t)strtoul(tokens[1], NULL, 10);
   }
 
   protocol_binary_response_status rval;
@@ -534,7 +572,7 @@ static void process_flush(struct memcached_protocol_client_st *client,
  *         0 storage command completed, continue processing
  *         1 We need more data, so just go ahead and wait for more!
  */
-static inline int process_storage_command(struct memcached_protocol_client_st *client,
+static inline int process_storage_command(memcached_protocol_client_st *client,
                                      char **tokens, int ntokens, char *start,
                                      char **end, ssize_t length)
 {
@@ -548,12 +586,12 @@ static inline int process_storage_command(struct memcached_protocol_client_st *c
     return -1;
   }
 
-  uint32_t flags = (uint32_t)strtoul(tokens[2], NULL, 10);
-  uint32_t timeout = (uint32_t)strtoul(tokens[3], NULL, 10);
-  unsigned long nbytes = strtoul(tokens[4], NULL, 10);
+  uint32_t flags= (uint32_t)strtoul(tokens[2], NULL, 10);
+  uint32_t timeout= (uint32_t)strtoul(tokens[3], NULL, 10);
+  unsigned long nbytes= strtoul(tokens[4], NULL, 10);
 
   /* Do we have all data? */
-  unsigned long need = nbytes + (unsigned long)((*end - start) + 1) + 2; /* \n\r\n */
+  unsigned long need= nbytes + (unsigned long)((*end - start) + 1) + 2; /* \n\r\n */
   if ((ssize_t)need > length)
   {
     /* Keep on reading */
@@ -561,7 +599,7 @@ static inline int process_storage_command(struct memcached_protocol_client_st *c
     return 1;
   }
 
-  void *data = (*end) + 1;
+  void *data= (*end) + 1;
   uint64_t cas= 0;
   uint64_t result_cas;
   protocol_binary_response_status rval;
@@ -585,7 +623,7 @@ static inline int process_storage_command(struct memcached_protocol_client_st *c
                                                    timeout, &result_cas);
     break;
   case CAS_CMD:
-    cas = strtoull(tokens[5], NULL, 10);
+    cas= strtoull(tokens[5], NULL, 10);
     /* FALLTHROUGH */
   case REPLACE_CMD:
     rval= client->root->callback->interface.v1.replace(client, key,
@@ -661,7 +699,7 @@ static inline int process_storage_command(struct memcached_protocol_client_st *c
   return 0;
 }
 
-static int process_cas_command(struct memcached_protocol_client_st *client,
+static int process_cas_command(memcached_protocol_client_st *client,
                                 char **tokens, int ntokens, char *start,
                                 char **end, ssize_t length)
 {
@@ -680,7 +718,7 @@ static int process_cas_command(struct memcached_protocol_client_st *client,
   return process_storage_command(client, tokens, ntokens, start, end, length);
 }
 
-static int process_set_command(struct memcached_protocol_client_st *client,
+static int process_set_command(memcached_protocol_client_st *client,
                                 char **tokens, int ntokens, char *start,
                                 char **end, ssize_t length)
 {
@@ -699,7 +737,7 @@ static int process_set_command(struct memcached_protocol_client_st *client,
   return process_storage_command(client, tokens, ntokens, start, end, length);
 }
 
-static int process_add_command(struct memcached_protocol_client_st *client,
+static int process_add_command(memcached_protocol_client_st *client,
                                 char **tokens, int ntokens, char *start,
                                 char **end, ssize_t length)
 {
@@ -718,7 +756,7 @@ static int process_add_command(struct memcached_protocol_client_st *client,
   return process_storage_command(client, tokens, ntokens, start, end, length);
 }
 
-static int process_replace_command(struct memcached_protocol_client_st *client,
+static int process_replace_command(memcached_protocol_client_st *client,
                                     char **tokens, int ntokens, char *start,
                                     char **end, ssize_t length)
 {
@@ -737,7 +775,7 @@ static int process_replace_command(struct memcached_protocol_client_st *client,
   return process_storage_command(client, tokens, ntokens, start, end, length);
 }
 
-static int process_append_command(struct memcached_protocol_client_st *client,
+static int process_append_command(memcached_protocol_client_st *client,
                                    char **tokens, int ntokens, char *start,
                                    char **end, ssize_t length)
 {
@@ -756,7 +794,7 @@ static int process_append_command(struct memcached_protocol_client_st *client,
   return process_storage_command(client, tokens, ntokens, start, end, length);
 }
 
-static int process_prepend_command(struct memcached_protocol_client_st *client,
+static int process_prepend_command(memcached_protocol_client_st *client,
                                     char **tokens, int ntokens, char *start,
                                     char **end, ssize_t length)
 {
@@ -780,7 +818,7 @@ static int process_prepend_command(struct memcached_protocol_client_st *client,
  * a optimal ascii support, I just convert the ASCII commands to the binary
  * protocol and calls back into the command handlers for the binary protocol ;)
  */
-enum MEMCACHED_PROTOCOL_EVENT memcached_ascii_protocol_process_data(struct memcached_protocol_client_st *client, ssize_t *length, void **endptr)
+memcached_protocol_event_t memcached_ascii_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length, void **endptr)
 {
   char *ptr= (char*)client->root->input_buffer;
   *endptr= ptr;
@@ -791,7 +829,7 @@ enum MEMCACHED_PROTOCOL_EVENT memcached_ascii_protocol_process_data(struct memca
     if (end == NULL)
     {
       *endptr= ptr;
-      return READ_EVENT;
+      return MEMCACHED_PROTOCOL_READ_EVENT;
     }
 
     client->ascii_command= ascii_to_cmd(ptr, (size_t)(*length));
@@ -832,9 +870,10 @@ enum MEMCACHED_PROTOCOL_EVENT memcached_ascii_protocol_process_data(struct memca
       case REPLACE_CMD:
         error= process_replace_command(client, tokens, ntokens,
                                        ptr, &end, *length);
+        break;
       case CAS_CMD:
         error= process_cas_command(client, tokens, ntokens, ptr, &end, *length);
-       break;
+        break;
       case APPEND_CMD:
         error= process_append_command(client, tokens, ntokens,
                                       ptr, &end, *length);
@@ -852,24 +891,40 @@ enum MEMCACHED_PROTOCOL_EVENT memcached_ascii_protocol_process_data(struct memca
         process_arithmetic(client, tokens, ntokens);
         break;
       case STATS_CMD:
-        recover_tokenize_command(ptr, end);
-        process_stats(client, ptr + 6, end);
+        if (client->mute)
+        {
+          send_command_usage(client);
+        }
+        else
+        {
+          recover_tokenize_command(ptr, end);
+          process_stats(client, ptr + 6, end);
+        }
         break;
       case FLUSH_ALL_CMD:
         process_flush(client, tokens, ntokens);
         break;
       case VERSION_CMD:
-        process_version(client, tokens, ntokens);
+        if (client->mute)
+        {
+          send_command_usage(client);
+        }
+        else
+        {
+          process_version(client, tokens, ntokens);
+        }
         break;
       case QUIT_CMD:
-        if (ntokens != 1)
+        if (ntokens != 1 || client->mute)
+        {
           send_command_usage(client);
+        }
         else
         {
           if (client->root->callback->interface.v1.quit != NULL)
             client->root->callback->interface.v1.quit(client);
 
-          return ERROR_EVENT;
+          return MEMCACHED_PROTOCOL_ERROR_EVENT;
         }
         break;
 
@@ -892,9 +947,9 @@ enum MEMCACHED_PROTOCOL_EVENT memcached_ascii_protocol_process_data(struct memca
       }
 
       if (error == -1)
-        return ERROR_EVENT;
+        return MEMCACHED_PROTOCOL_ERROR_EVENT;
       else if (error == 1)
-        return READ_EVENT;
+        return MEMCACHED_PROTOCOL_READ_EVENT;
     }
 
     /* Move past \n */
@@ -903,6 +958,6 @@ enum MEMCACHED_PROTOCOL_EVENT memcached_ascii_protocol_process_data(struct memca
     ptr= end;
   } while (*length > 0);
 
-  *endptr = ptr;
-  return READ_EVENT;
+  *endptr= ptr;
+  return MEMCACHED_PROTOCOL_READ_EVENT;
 }