From d3ef73cd144dfdbcaff41d3373e4458fb351f7af Mon Sep 17 00:00:00 2001 From: Brian Aker Date: Thu, 4 Oct 2007 21:37:44 -0700 Subject: [PATCH] Added MD5 hashing scheme. Refactored code to allow for more hashing types. --- include/memcached.h | 10 ++-- lib/common.h | 13 ++--- lib/md5.c | 41 +++++++--------- lib/memcached_auto.c | 2 +- lib/memcached_behavior.c | 4 +- lib/memcached_delete.c | 2 +- lib/memcached_get.c | 4 +- lib/memcached_hash.c | 26 +++++++++- lib/memcached_io.c | 2 +- lib/memcached_storage.c | 2 +- tests/output.res | 102 +++++++++++++++++++++++++++++++++++++++ tests/test.c | 19 ++++++++ 12 files changed, 186 insertions(+), 41 deletions(-) diff --git a/include/memcached.h b/include/memcached.h index 20acf76a..42cfe77b 100644 --- a/include/memcached.h +++ b/include/memcached.h @@ -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); diff --git a/lib/common.h b/lib/common.h index 603e7823..607b6373 100644 --- a/lib/common.h +++ b/lib/common.h @@ -18,15 +18,16 @@ #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__ */ diff --git a/lib/md5.c b/lib/md5.c index e12d5d1b..781aba83 100644 --- 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. diff --git a/lib/memcached_auto.c b/lib/memcached_auto.c index 29bcf2a6..653764ab 100644 --- a/lib/memcached_auto.c +++ b/lib/memcached_auto.c @@ -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, diff --git a/lib/memcached_behavior.c b/lib/memcached_behavior.c index e084af35..38b1e9bb 100644 --- a/lib/memcached_behavior.c +++ b/lib/memcached_behavior.c @@ -1,4 +1,4 @@ -#include +#include "common.h" #include #include #include @@ -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; } diff --git a/lib/memcached_delete.c b/lib/memcached_delete.c index e44277d4..6fa2d4a8 100644 --- a/lib/memcached_delete.c +++ b/lib/memcached_delete.c @@ -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, diff --git a/lib/memcached_get.c b/lib/memcached_get.c index 201cfcdf..8ea1fabc 100644 --- a/lib/memcached_get.c +++ b/lib/memcached_get.c @@ -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]) { diff --git a/lib/memcached_hash.c b/lib/memcached_hash.c index a8ecebf5..cb3d5218 100644 --- a/lib/memcached_hash.c +++ b/lib/memcached_hash.c @@ -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; diff --git a/lib/memcached_io.c b/lib/memcached_io.c index 401039b4..9277b6ba 100644 --- a/lib/memcached_io.c +++ b/lib/memcached_io.c @@ -2,7 +2,7 @@ Basic socket buffered IO */ -#include +#include "common.h" #include "memcached_io.h" #include diff --git a/lib/memcached_storage.c b/lib/memcached_storage.c index fc3c3cba..eabe6ce9 100644 --- a/lib/memcached_storage.c +++ b/lib/memcached_storage.c @@ -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), diff --git a/tests/output.res b/tests/output.res index ec7fdd96..dd73ee14 100644 --- a/tests/output.res +++ b/tests/output.res @@ -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 diff --git a/tests/test.c b/tests/test.c index e0f50adb..8da111b3 100644 --- a/tests/test.c +++ b/tests/test.c @@ -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; -- 2.30.2