Added MD5 hashing scheme. Refactored code to allow for more hashing types.
authorBrian Aker <brian@tangent.org>
Fri, 5 Oct 2007 04:37:44 +0000 (21:37 -0700)
committerBrian Aker <brian@tangent.org>
Fri, 5 Oct 2007 04:37:44 +0000 (21:37 -0700)
12 files changed:
include/memcached.h
lib/common.h
lib/md5.c
lib/memcached_auto.c
lib/memcached_behavior.c
lib/memcached_delete.c
lib/memcached_get.c
lib/memcached_hash.c
lib/memcached_io.c
lib/memcached_storage.c
tests/output.res
tests/test.c

index 20acf76a029dc70446f6774a5b71eb7e17725a7b..42cfe77b9b3f55e500389f5faef5b917292f7f72 100644 (file)
@@ -74,6 +74,7 @@ typedef enum {
   MEMCACHED_BEHAVIOR_BLOCK,
   MEMCACHED_BEHAVIOR_TCP_NODELAY,
   MEMCACHED_BEHAVIOR_TCP_DELAY,
+  MEMCACHED_BEHAVIOR_MD5_HASHING,
 } memcached_behavior;
 
 typedef enum {
@@ -116,10 +117,6 @@ struct memcached_stat_st {
   unsigned int limit_maxbytes;
 };
 
-#define MEM_NO_BLOCK     (1 << 0)
-#define MEM_TCP_NODELAY  (1 << 1)
-#define MEM_REUSE_MEMORY (1 << 2)
-
 struct memcached_string_st {
   char *string;
   char *end;
@@ -225,6 +222,11 @@ size_t memcached_string_backspace(memcached_st *ptr, memcached_string_st *string
 memcached_return memcached_string_reset(memcached_st *ptr, memcached_string_st *string);
 void memcached_string_free(memcached_st *ptr, memcached_string_st *string);
 
+char *memcached_stat_get_value(memcached_st *ptr, memcached_stat_st *stat, 
+                               char *key, memcached_return *error);
+char ** memcached_stat_get_keys(memcached_st *ptr, memcached_stat_st *stat, 
+                                memcached_return *error);
+
 /* Some personal debugging functions */
 #define WATCHPOINT printf("\nWATCHPOINT %s:%d (%s)\n", __FILE__, __LINE__,__func__);fflush(stdout);
 #define WATCHPOINT_ERROR(A) printf("\nWATCHPOINT %s:%d %s\n", __FILE__, __LINE__, memcached_strerror(NULL, A));fflush(stdout);
index 603e7823cc8b6698878bc1f0ef02d4b0d160d7d2..607b6373b9108a004c5d8673a1eee68921104c2d 100644 (file)
 
 #include "libmemcached_probes.h"
 
-void md5_signature(const unsigned char *key, unsigned int length, char *result);
+#define MEM_NO_BLOCK     (1 << 0)
+#define MEM_TCP_NODELAY  (1 << 1)
+#define MEM_REUSE_MEMORY (1 << 2)
+#define MEM_USE_MD5      (1 << 3)
+
+void md5_signature(unsigned char *key, unsigned int length, unsigned char *result);
 memcached_return memcached_connect(memcached_st *ptr);
 memcached_return memcached_response(memcached_st *ptr, 
                                     char *buffer, size_t buffer_length,
                                     unsigned int server_key);
-unsigned int memcached_generate_hash(char *key, size_t key_length);
-char *memcached_stat_get_value(memcached_st *ptr, memcached_stat_st *stat, 
-                               char *key, memcached_return *error);
-char ** memcached_stat_get_keys(memcached_st *ptr, memcached_stat_st *stat, 
-                                memcached_return *error);
+unsigned int memcached_generate_hash(memcached_st *ptr, char *key, size_t key_length);
 
 #endif /* __COMMON_H__ */
index e12d5d1bea57d3fb480f250626696e96d7d9fd78..781aba833bdeb2ce95968c45b183d4de18eb5f0c 100644 (file)
--- a/lib/md5.c
+++ b/lib/md5.c
@@ -47,9 +47,12 @@ typedef struct {
   unsigned char buffer[64];                         /* input buffer */
 } MD5_CTX;
 
-static void MD5Init PROTO_LIST ((MD5_CTX *));
-static void MD5Update PROTO_LIST ((MD5_CTX *, unsigned char *, unsigned int));
-static void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
+static void MD5Init (MD5_CTX *context);      /* context */
+static void MD5Update ( MD5_CTX *context,                                        /* context */
+                        unsigned char *input,                                /* input block */
+                        unsigned int inputLen);                     /* length of input block */
+static void MD5Final ( unsigned char digest[16],                         /* message digest */
+                       MD5_CTX *context);                              /* context */
 
 /* Constants for MD5Transform routine. */
 
@@ -71,13 +74,14 @@ static void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
 #define S44 21
 
 
-static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
-static void Encode PROTO_LIST
-  ((unsigned char *, UINT4 *, unsigned int));
-static void Decode PROTO_LIST
-  ((UINT4 *, unsigned char *, unsigned int));
-static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
-static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+static void MD5Transform (UINT4 state[4],
+                          unsigned char block[64]);
+static void Encode (unsigned char *output,
+                    UINT4 *input,
+                    unsigned int len);
+static void Decode(UINT4 *output, unsigned char *input, unsigned int len);
+static void MD5_memcpy(unsigned char *, unsigned char *, unsigned int);
+static void MD5_memset(unsigned char *, int, unsigned int);
 
 static unsigned char PADDING[64] = {
   0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -123,24 +127,15 @@ Rotation is separate from addition to prevent recomputation.
 
 /* 
   Just a simple method for getting the signature
-  result must be == 32
+  result must be == 16
 */
-void md5_signature(const unsigned char *key, unsigned int length, char *result)
+void md5_signature(unsigned char *key, unsigned int length, unsigned char *result)
 {
-    const char *hex = "0123456789abcdef";
     MD5_CTX my_md5;
-    unsigned char hash[16];
-    char *r, i;
 
     MD5Init(&my_md5);
-    (void)MD5Update(&my_md5, buf, length);
-    MD5Final(hash, &my_md5);
-
-    for (i = 0, r = result; i < 16; i++) 
-    {
-       *r++ = hex[hash[i] >> 4];
-       *r++ = hex[hash[i] & 0xF];
-    }
+    (void)MD5Update(&my_md5, key, length);
+    MD5Final(result, &my_md5);
 }
 
 /* MD5 initialization. Begins an MD5 operation, writing a new context.
index 29bcf2a6b340261906425dbb27aaca139613a42f..653764ab981a51a2ef61b86f63b68eb3338b1177 100644 (file)
@@ -16,7 +16,7 @@ static memcached_return memcached_auto(memcached_st *ptr,
   if (rc != MEMCACHED_SUCCESS)
     return rc;
 
-  server_key= memcached_generate_hash(key, key_length) % ptr->number_of_hosts;
+  server_key= memcached_generate_hash(ptr, key, key_length);
 
   send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
                         "%s %.*s %u\r\n", verb, 
index e084af352ec926d26a79100597a15849722fc8da..38b1e9bb43a3c51587bcc4a31c27b3bdf989b0dd 100644 (file)
@@ -1,4 +1,4 @@
-#include <memcached.h>
+#include "common.h" 
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/tcp.h>
@@ -28,6 +28,8 @@ memcached_return memcached_behavior_set(memcached_st *ptr,
     /* We quit all connections so we can reset the sockets */
     memcached_quit(ptr);
     ptr->flags+= MEM_TCP_NODELAY;
+  case MEMCACHED_BEHAVIOR_MD5_HASHING:
+    ptr->flags+= MEM_USE_MD5;
     break;
   }
 
index e44277d44128f62833efab0951fc14a1fc022cac..6fa2d4a8ff6833a3527f38ef57a31921439e1e7e 100644 (file)
@@ -15,7 +15,7 @@ memcached_return memcached_delete(memcached_st *ptr, char *key, size_t key_lengt
   if (rc != MEMCACHED_SUCCESS)
     return rc;
 
-  server_key= memcached_generate_hash(key, key_length) % ptr->number_of_hosts;
+  server_key= memcached_generate_hash(ptr, key, key_length);
 
   if (expiration)
     send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
index 201cfcdf82d62b9661f838fa7e2fba70e9422573..8ea1fabc964c59888be79358d167304fc65f0fb0 100644 (file)
@@ -136,7 +136,7 @@ char *memcached_get(memcached_st *ptr, char *key, size_t key_length,
   if (*error != MEMCACHED_SUCCESS)
     goto error;
 
-  server_key= memcached_generate_hash(key, key_length) % ptr->number_of_hosts;
+  server_key= memcached_generate_hash(ptr, key, key_length);
 
   send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, "get %.*s\r\n", 
                         (int)key_length, key);
@@ -208,7 +208,7 @@ memcached_return memcached_mget(memcached_st *ptr,
   {
     unsigned int server_key;
 
-    server_key= memcached_generate_hash(keys[x], key_length[x]) % ptr->number_of_hosts;
+    server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
 
     if (cursor_key_exec[server_key])
     {
index a8ecebf5c419cb912778e899a08c9cc6687ef246..cb3d5218391037f052061bbfc64f2c552fb58277 100644 (file)
@@ -1,6 +1,30 @@
 #include "common.h"
 
-unsigned int memcached_generate_hash(char *key, size_t key_length)
+/* Prototypes */
+static unsigned int internal_generate_hash(char *key, size_t key_length);
+
+unsigned int memcached_generate_hash(memcached_st *ptr, char *key, size_t key_length)
+{
+  unsigned int return_value;
+
+  if (ptr->flags & MEM_USE_MD5)
+  {
+    unsigned char results[16];
+
+    md5_signature((unsigned char*)key, (unsigned int)key_length, results);
+
+    return_value= (unsigned int)(( results[3] << 24 )
+                                | ( results[2] << 16 )
+                                | ( results[1] <<  8 )
+                                |   results[0] );
+  }
+  else
+    return_value= internal_generate_hash(key, key_length);
+
+  return return_value % ptr->number_of_hosts;
+}
+
+static unsigned int internal_generate_hash(char *key, size_t key_length)
 {
   char *ptr= key;
   unsigned int value= 0;
index 401039b4efbd831ee2c0eddc1ab0e3f8692aac23..9277b6ba3a883a387829acc9130046843f3756f4 100644 (file)
@@ -2,7 +2,7 @@
   Basic socket buffered IO
 */
 
-#include <memcached.h>
+#include "common.h"
 #include "memcached_io.h"
 #include <sys/select.h>
 
index fc3c3cbab73f199e0e0fce477f1dc690a2c735bd..eabe6ce981bd6ea61bb16b3b4253010c9dbab750 100644 (file)
@@ -44,7 +44,7 @@ static memcached_return memcached_send(memcached_st *ptr,
   /* Leaveing this assert in since only a library fubar could blow this */
   assert(ptr->write_buffer_offset == 0);
 
-  server_key= memcached_generate_hash(key, key_length) % ptr->number_of_hosts;
+  server_key= memcached_generate_hash(ptr, key, key_length);
 
   write_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
                         "%s %.*s %x %llu %zu\r\n", storage_op_string(verb),
index ec7fdd96a8befa19caf730088374de252f64bfc7..dd73ee14104f6fc434d88ca1548e024ea93c6bd7 100644 (file)
@@ -305,3 +305,105 @@ Found key bytes_read
 Found key bytes_written
 Found key limit_maxbytes
 Found key threads
+Error 0 -> SUCCESS
+Error 1 -> FAILURE
+Error 2 -> HOSTNAME LOOKUP FAILURE
+Error 3 -> CONNECTION FAILURE
+Error 4 -> CONNECTION BIND FAILURE
+Error 5 -> WRITE FAILURE
+Error 6 -> READ FAILURE
+Error 7 -> UNKNOWN READ FAILURE
+Error 8 -> PROTOCOL ERROR
+Error 9 -> CLIENT ERROR
+Error 10 -> SERVER ERROR
+Error 11 -> CONNECTION SOCKET CREATE FAILURE
+Error 12 -> CONNECTION DATA EXISTS
+Error 13 -> CONNECTION DATA DOES NOT EXIST
+Error 14 -> NOT STORED
+Error 15 -> STORED
+Error 16 -> NOT FOUND
+Error 17 -> MEMORY ALLOCATION FAILURE
+Error 18 -> PARTIAL READ
+Error 19 -> SOME ERRORS WERE REPORTED
+Error 20 -> NO SERVERS DEFINED
+Error 21 -> SERVER END
+Error 22 -> SERVER DELETE
+Error 23 -> SERVER VALUE
+Found key pid
+Found key uptime
+Found key time
+Found key version
+Found key pointer_size
+Found key rusage_user
+Found key rusage_system
+Found key rusage_user_seconds
+Found key rusage_user_microseconds
+Found key rusage_system_seconds
+Found key rusage_system_microseconds
+Found key curr_items
+Found key total_items
+Found key bytes
+Found key curr_connections
+Found key total_connections
+Found key connection_structures
+Found key cmd_get
+Found key cmd_set
+Found key get_hits
+Found key get_misses
+Found key evictions
+Found key bytes_read
+Found key bytes_written
+Found key limit_maxbytes
+Found key threads
+Found key pid
+Found key uptime
+Found key time
+Found key version
+Found key pointer_size
+Found key rusage_user
+Found key rusage_system
+Found key rusage_user_seconds
+Found key rusage_user_microseconds
+Found key rusage_system_seconds
+Found key rusage_system_microseconds
+Found key curr_items
+Found key total_items
+Found key bytes
+Found key curr_connections
+Found key total_connections
+Found key connection_structures
+Found key cmd_get
+Found key cmd_set
+Found key get_hits
+Found key get_misses
+Found key evictions
+Found key bytes_read
+Found key bytes_written
+Found key limit_maxbytes
+Found key threads
+Found key pid
+Found key uptime
+Found key time
+Found key version
+Found key pointer_size
+Found key rusage_user
+Found key rusage_system
+Found key rusage_user_seconds
+Found key rusage_user_microseconds
+Found key rusage_system_seconds
+Found key rusage_system_microseconds
+Found key curr_items
+Found key total_items
+Found key bytes
+Found key curr_connections
+Found key total_connections
+Found key connection_structures
+Found key cmd_get
+Found key cmd_set
+Found key get_hits
+Found key get_misses
+Found key evictions
+Found key bytes_read
+Found key bytes_written
+Found key limit_maxbytes
+Found key threads
index e0f50adb7f816d1ea07977b9de3702a34c3c462b..8da111b316d627e7627ee8ff202c80ec8ed64236 100644 (file)
@@ -588,6 +588,25 @@ int main(int argc, char *argv[])
     memcached_free(memc);
   }
 
+  fprintf(stderr, "\nMD5 Hashing\n\n");
+  for (x= 0; tests[x].function_name; x++)
+  {
+    memcached_st *memc;
+    memcached_return rc;
+    memc= memcached_create(NULL);
+    assert(memc);
+
+    rc= memcached_server_push(memc, servers);
+    assert(rc == MEMCACHED_SUCCESS);
+
+    fprintf(stderr, "Testing %s", tests[x].function_name);
+    memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_MD5_HASHING, NULL);
+    tests[x].function(memc);
+    fprintf(stderr, "\t\t\t\t\t[ ok ]\n");
+    assert(memc);
+    memcached_free(memc);
+  }
+
   /* Clean up whatever we might have left */
   {
     memcached_st *memc;