memcache/command.c
changeset 42 0e503189af2f
parent 41 540737bf6bac
child 43 e5b714190dee
equal deleted inserted replaced
41:540737bf6bac 42:0e503189af2f
     1 
     1 #include <string.h>
       
     2 #include <stdlib.h>
     2 #include <assert.h>
     3 #include <assert.h>
     3 
     4 
     4 #include "command.h"
     5 #include "command.h"
     5 #include "../common.h"
     6 #include "../common.h"
     6 
     7 
    12     "replace",  // MEMCACHE_CMD_STORE_REPLACE
    13     "replace",  // MEMCACHE_CMD_STORE_REPLACE
    13     "append",   // MEMCACHE_CMD_STORE_APPEND
    14     "append",   // MEMCACHE_CMD_STORE_APPEND
    14     "prepend"   // MEMCACHE_CMD_STORE_PREPEND
    15     "prepend"   // MEMCACHE_CMD_STORE_PREPEND
    15 };
    16 };
    16 
    17 
    17 /*
       
    18 static struct memcache_reply_info {
    18 static struct memcache_reply_info {
    19     enum memcache_reply type;
    19     enum memcache_reply type;
    20     char *name;
    20     char *name;
    21     int has_data;
    21 
    22 
    22 } memcache_cmd_replies[MEMCACHE_RPL_MAX] = {
    23 } *memcache_cmd_replies[MEMCACHE_RPL_MAX] = {
    23     {   MEMCACHE_RPL_INVALID,       NULL            },
    24     MEMCACHE_RPL_INVALID,
    24     {   MEMCACHE_RPL_ERROR,         "ERROR"         },
    25 
    25     {   MEMCACHE_RPL_CLIENT_ERROR,  "CLIENT_ERROR"  },
    26     MEMCACHE_RPL_ERROR,
    26     {   MEMCACHE_RPL_SERVER_ERROR,  "SERVER_ERROR"  },
    27     MEMCACHE_RPL_CLIENT_ERROR,
       
    28     MEMCACHE_RPL_SERVER_ERROR,
       
    29     
    27     
    30     // MEMCACHE_CMD_FETCH_*
    28     // MEMCACHE_CMD_FETCH_*
    31     MEMCACHE_RPL_VALUE,
    29     {   MEMCACHE_RPL_VALUE,         "VALUE"         },
    32     MEMCACHE_RPL_END,
    30     {   MEMCACHE_RPL_END,           "END"           },
    33     
    31     
    34     // MEMCACHE_CMD_STORE_*
    32     // MEMCACHE_CMD_STORE_*
    35     MEMCACHE_RPL_STORED,
    33     {   MEMCACHE_RPL_STORED,        "STORED"        },
    36     MEMCACHE_RPL_NOT_STORED,
    34     {   MEMCACHE_RPL_NOT_STORED,    "NOT_STORED"    },
    37     MEMCACHE_RPL_EXISTS,
    35     {   MEMCACHE_RPL_EXISTS,        "EXISTS"        },
    38     MEMCACHE_RPL_NOT_FOUND,
    36     {   MEMCACHE_RPL_NOT_FOUND,     "NOT_FOUND"     }
    39 
       
    40 };
    37 };
    41 
    38 
    42 */
    39 
    43 
    40 
    44 int memcache_cmd_init (struct memcache_cmd *cmd, enum memcache_command cmd_type, struct memcache_key *key, struct memcache_obj *obj) {
    41 int memcache_cmd_init (struct memcache_cmd *cmd, enum memcache_command cmd_type, struct memcache_key *key, struct memcache_obj *obj) {
    45     // shouldn't already have a request header yet?
    42     // shouldn't already have a request header yet?
    46     assert(cmd->req_header == NULL);
    43     assert(cmd->req_header == NULL);
    47 
    44 
   115     return -1;
   112     return -1;
   116 
   113 
   117 }
   114 }
   118 
   115 
   119 int memcache_cmd_parse_header (struct evbuffer *buf, char **header_data, enum memcache_reply *reply_type, struct memcache_key *key, struct memcache_obj *obj, int *has_data) {
   116 int memcache_cmd_parse_header (struct evbuffer *buf, char **header_data, enum memcache_reply *reply_type, struct memcache_key *key, struct memcache_obj *obj, int *has_data) {
   120     // XXX: implement
   117     size_t line_length, buf_size;
   121     assert(0);
   118     char *line = NULL, *token_cursor, *token, *invalid;
       
   119     int i;
       
   120 
       
   121     // take note of how long the buffer is
       
   122     buf_size = evbuffer_get_length(buf);
       
   123 
       
   124     // first, try and read a full line
       
   125     if ((line = evbuffer_readln(buf, &line_length, EVBUFFER_EOL_CRLF_STRICT)) == NULL) {
       
   126         // check if any data was consumed
       
   127         if (evbuffer_get_length(buf) != buf_size) {
       
   128             // faaaail!
       
   129             return -1;
       
   130 
       
   131         } else {
       
   132             // no complete line found
       
   133             return 0;
       
   134         }
       
   135     }
       
   136     
       
   137     // just check to make sure that it really is null-delimited
       
   138     assert(line[line_length - 1] == '\0');
       
   139 
       
   140     // empty lines?
       
   141     if (line_length == 0) {
       
   142         PWARNING("empty reply line !?!");
       
   143         return 0;
       
   144     }
       
   145 
       
   146     // use strsep
       
   147     token_cursor = line;
       
   148 
       
   149     // the first token should be the reply name
       
   150     if ((token = strsep(&token_cursor, " ")) == NULL)
       
   151         ERROR("no reply name in response line: %s", line);
       
   152     
       
   153     // figure out the reply type
       
   154     for (i = MEMCACHE_RPL_INVALID + 1; i < MEMCACHE_RPL_MAX; i++) {
       
   155         if (strcmp(token, memcache_cmd_replies[i].name) == 0)
       
   156             break;
       
   157     }
       
   158     
       
   159     // did we figure out what this reply means?
       
   160     if (i == MEMCACHE_RPL_MAX)
       
   161         ERROR("unrecognized reply: %s", line);
       
   162     
       
   163     // we found the type
       
   164     *reply_type = memcache_cmd_replies[i].type;
       
   165 
       
   166     // default to no data
       
   167     *has_data = 0;
       
   168 
       
   169     switch (*reply_type) {
       
   170         case MEMCACHE_RPL_ERROR:
       
   171             // no additional data
       
   172 
       
   173             break;
       
   174         
       
   175         case MEMCACHE_RPL_CLIENT_ERROR:
       
   176         case MEMCACHE_RPL_SERVER_ERROR:
       
   177             // the rest of the line is a human-readable error message
       
   178             WARNING("received a %s reply: %s", token, token_cursor);
       
   179             
       
   180             break;
       
   181         
       
   182         case MEMCACHE_RPL_VALUE:
       
   183             // <key> <flags> <bytes> [<cas unique>]
       
   184 
       
   185             // the key field
       
   186             if ((key->buf = strsep(&token_cursor, " ")) == NULL)
       
   187                 ERROR("missing key in VALUE reply");
       
   188             
       
   189             if ((key->len = strlen(key->buf)) == 0)
       
   190                 ERROR("zero-length key in VALUE reply");
       
   191             
       
   192             // the flags field
       
   193             if ((token = strsep(&token_cursor, " ")) == NULL)
       
   194                 ERROR("missing flags in VALUE reply");
       
   195 
       
   196             obj->flags = (u_int32_t) strtol(token, &invalid, 10);
       
   197 
       
   198             if (*invalid != '\0')
       
   199                 ERROR("invalid flags in VALUE reply: %s (%s)", token, invalid);
       
   200             
       
   201             // the bytes field
       
   202             if ((token = strsep(&token_cursor, " ")) == NULL)
       
   203                 ERROR("missing bytes in VALUE reply");
       
   204 
       
   205             obj->bytes = (u_int32_t) strtol(token, &invalid, 10);
       
   206 
       
   207             if (*invalid != '\0')
       
   208                 ERROR("invalid bytes in VALUE reply: %s (%s)", token, invalid);
       
   209 
       
   210             // the optional cas field
       
   211             if ((token = strsep(&token_cursor, " ")) != NULL) {
       
   212                 // there is a cas value present
       
   213                 obj->cas = (u_int64_t) strtoll(token, &invalid, 10);
       
   214                 
       
   215                 if (*invalid != '\0')
       
   216                     ERROR("invalid cas value in VALUE reply: %s (%s)", token, invalid);
       
   217 
       
   218             } else {
       
   219                 obj->cas = 0;
       
   220 
       
   221             }
       
   222             
       
   223             // and we do have data following this
       
   224             *has_data = 1;
       
   225 
       
   226             break;
       
   227         
       
   228         case MEMCACHE_RPL_END:
       
   229             // no additional data
       
   230 
       
   231             break;
       
   232 
       
   233         case MEMCACHE_RPL_STORED:
       
   234         case MEMCACHE_RPL_NOT_STORED:
       
   235         case MEMCACHE_RPL_EXISTS:
       
   236         case MEMCACHE_RPL_NOT_FOUND:
       
   237             // no additional data
       
   238 
       
   239             break;
       
   240         
       
   241         default:
       
   242             assert(0);
       
   243     };
       
   244 
       
   245     // success
       
   246     *header_data = line;
       
   247 
       
   248     return 0;
       
   249 
       
   250 error:
       
   251     free(line);
       
   252 
       
   253     return -1;
   122 }
   254 }
   123 
   255