Index: memcached.c
===================================================================
--- memcached.c	(revision 1)
+++ memcached.c	(revision 16)
@@ -715,8 +715,8 @@
     char *key = ITEM_key(it);
     bool delete_locked = false;
     item *old_it = do_item_get_notedeleted(key, it->nkey, &delete_locked);
-    int stored = 0;
-
+    int stored = 0;    
+    
     if (old_it != NULL && comm == NREAD_ADD) {
         /* add only adds a nonexistent item, but promote to head of LRU */
         do_item_update(old_it);
@@ -1052,13 +1052,14 @@
 }
 
 /* ntokens is overwritten here... shrug.. */
-static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens) {
+static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens, bool return_key_ptr) {
     char *key;
     size_t nkey;
     int i = 0;
     item *it;
     token_t *key_token = &tokens[KEY_TOKEN];
-
+    char suffix[255];
+    uint32_t in_memory_ptr;
     assert(c != NULL);
 
     if (settings.managed) {
@@ -1108,12 +1109,30 @@
                  *   key
                  *   " " + flags + " " + data length + "\r\n" + data (with \r\n)
                  */
-                if (add_iov(c, "VALUE ", 6) != 0 ||
-                    add_iov(c, ITEM_key(it), it->nkey) != 0 ||
-                    add_iov(c, ITEM_suffix(it), it->nsuffix + it->nbytes) != 0)
-                    {
-                        break;
-                    }
+
+                if(return_key_ptr == true)
+                {
+                  in_memory_ptr = (uint32_t)item_get(key, nkey);
+                  sprintf(suffix," %d %d %lu\r\n", atoi(ITEM_suffix(it) + 1), it->nbytes - 2, in_memory_ptr);
+                  if (add_iov(c, "VALUE ", 6) != 0 ||
+                      add_iov(c, ITEM_key(it), it->nkey) != 0 ||
+                      add_iov(c, suffix, strlen(suffix)) != 0 ||
+                      add_iov(c, ITEM_data(it), it->nbytes) != 0)
+                      {
+                          break;
+                      }
+                }
+                else
+                {
+                  if (add_iov(c, "VALUE ", 6) != 0 ||
+                      add_iov(c, ITEM_key(it), it->nkey) != 0 ||
+                      add_iov(c, ITEM_suffix(it), it->nsuffix + it->nbytes) != 0)
+                      {
+                          break;
+                      }                  
+                }
+                
+
                 if (settings.verbose > 1)
                     fprintf(stderr, ">%d sending key %s\n", c->sfd, ITEM_key(it));
 
@@ -1152,6 +1171,7 @@
         fprintf(stderr, ">%d END\n", c->sfd);
     add_iov(c, "END\r\n", 5);
 
+    
     if (c->udp && build_udp_headers(c) != 0) {
         out_string(c, "SERVER_ERROR out of memory");
     }
@@ -1162,14 +1182,16 @@
     return;
 }
 
-static void process_update_command(conn *c, token_t *tokens, const size_t ntokens, int comm) {
+static void process_update_command(conn *c, token_t *tokens, const size_t ntokens, int comm, bool handle_cas) {
     char *key;
     size_t nkey;
     int flags;
     time_t exptime;
     int vlen;
+    uint32_t req_memory_ptr, in_memory_ptr;
+    
     item *it;
-
+        
     assert(c != NULL);
 
     if (tokens[KEY_TOKEN].length > KEY_MAX_LENGTH) {
@@ -1184,6 +1206,12 @@
     exptime = strtol(tokens[3].value, NULL, 10);
     vlen = strtol(tokens[4].value, NULL, 10);
 
+    // does cas value exist?
+    if(tokens[5].value)
+    {
+      req_memory_ptr = strtoull(tokens[5].value, NULL, 10);
+    }
+
     if(errno == ERANGE || ((flags == 0 || exptime == 0) && errno == EINVAL)) {
         out_string(c, "CLIENT_ERROR bad command line format");
         return;
@@ -1208,6 +1236,38 @@
 
     it = item_alloc(key, nkey, flags, realtime(exptime), vlen+2);
 
+    /* HANDLE_CAS VALIDATION */
+    if(handle_cas == true)
+    {
+      item *itmp=item_get(key, it->nkey);
+      /* Release the reference */
+      if(itmp) {
+        item_remove(itmp);
+      }
+      in_memory_ptr = (uint32_t)itmp;
+      if(in_memory_ptr == req_memory_ptr)
+      {
+        // validates allow the set
+      }
+      else if(in_memory_ptr)
+      {
+        out_string(c, "EXISTS");
+        
+        /* swallow the data line */
+        c->write_and_go = conn_swallow;
+        c->sbytes = vlen + 2;
+        return;
+      }
+      else
+      {
+        out_string(c, "NOT FOUND");
+        /* swallow the data line */
+        c->write_and_go = conn_swallow;
+        c->sbytes = vlen + 2;
+        return;
+      }
+    }
+
     if (it == 0) {
         if (! item_size_ok(nkey, flags, vlen + 2))
             out_string(c, "SERVER_ERROR object too large for cache");
@@ -1446,24 +1506,31 @@
     }
 
     ntokens = tokenize_command(command, tokens, MAX_TOKENS);
-
     if (ntokens >= 3 &&
         ((strcmp(tokens[COMMAND_TOKEN].value, "get") == 0) ||
          (strcmp(tokens[COMMAND_TOKEN].value, "bget") == 0))) {
 
-        process_get_command(c, tokens, ntokens);
+        process_get_command(c, tokens, ntokens, false);
 
     } else if (ntokens == 6 &&
                ((strcmp(tokens[COMMAND_TOKEN].value, "add") == 0 && (comm = NREAD_ADD)) ||
                 (strcmp(tokens[COMMAND_TOKEN].value, "set") == 0 && (comm = NREAD_SET)) ||
                 (strcmp(tokens[COMMAND_TOKEN].value, "replace") == 0 && (comm = NREAD_REPLACE)))) {
+                  
+        process_update_command(c, tokens, ntokens, comm, false);
 
-        process_update_command(c, tokens, ntokens, comm);
+    } else if (ntokens == 6 && (strcmp(tokens[COMMAND_TOKEN].value, "cas") == 0)) {
 
+        process_update_command(c, tokens, ntokens, comm, true);
+
     } else if (ntokens == 4 && (strcmp(tokens[COMMAND_TOKEN].value, "incr") == 0)) {
 
         process_arithmetic_command(c, tokens, ntokens, 1);
 
+    } else if (ntokens >= 3 && (strcmp(tokens[COMMAND_TOKEN].value, "gets") == 0)) {
+
+        process_get_command(c, tokens, ntokens, true);
+
     } else if (ntokens == 4 && (strcmp(tokens[COMMAND_TOKEN].value, "decr") == 0)) {
 
         process_arithmetic_command(c, tokens, ntokens, 0);
