xref: /3.0.2-MP2/memcached/tests/testapp.c (revision c358829d)
1/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2#include "config.h"
3#include <sys/types.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <errno.h>
7#include <string.h>
8#include <fcntl.h>
9#include <ctype.h>
10#include <time.h>
11#include <evutil.h>
12#include <snappy-c.h>
13#include <cJSON.h>
14
15
16#include "daemon/cache.h"
17#include <memcached/util.h>
18#include <memcached/protocol_binary.h>
19#include <memcached/config_parser.h>
20#include "extensions/protocol/fragment_rw.h"
21#include "extensions/protocol/testapp_extension.h"
22#include "platform/platform.h"
23#include "memcached/openssl.h"
24#include "programs/utilities.h"
25
26/* Set the read/write commands differently than the default values
27 * so that we can verify that the override works
28 */
29static uint8_t read_command = 0xe1;
30static uint8_t write_command = 0xe2;
31
32const char config_file[] = "memcached_testapp.json";
33
34#define TMP_TEMPLATE "/tmp/test_file.XXXXXXX"
35
36enum test_return { TEST_SKIP, TEST_PASS, TEST_FAIL };
37
38/* test phases */
39#define phase_plain 1
40#define phase_ssl 2
41#define phase_cleanup 4
42#define phase_max 3
43static int current_phase = 0;
44
45static pid_t server_pid;
46static in_port_t port = -1;
47static in_port_t ssl_port = -1;
48static SOCKET sock;
49static SOCKET sock_ssl;
50static bool allow_closed_read = false;
51static time_t server_start_time = 0;
52static SSL_CTX *ssl_ctx = NULL;
53static SSL *ssl = NULL;
54static BIO *ssl_bio_r = NULL;
55static BIO *ssl_bio_w = NULL;
56
57static enum test_return cache_create_test(void)
58{
59    cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
60                                  NULL, NULL);
61    cb_assert(cache != NULL);
62    cache_destroy(cache);
63    return TEST_PASS;
64}
65
66const uint64_t constructor_pattern = 0xdeadcafebabebeef;
67
68static int cache_constructor(void *buffer, void *notused1, int notused2) {
69    uint64_t *ptr = buffer;
70    *ptr = constructor_pattern;
71    return 0;
72}
73
74static enum test_return cache_constructor_test(void)
75{
76    uint64_t *ptr;
77    uint64_t pattern;
78    cache_t *cache = cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
79                                  cache_constructor, NULL);
80
81
82    cb_assert(cache != NULL);
83    ptr = cache_alloc(cache);
84    pattern = *ptr;
85    cache_free(cache, ptr);
86    cache_destroy(cache);
87    return (pattern == constructor_pattern) ? TEST_PASS : TEST_FAIL;
88}
89
90static int cache_fail_constructor(void *buffer, void *notused1, int notused2) {
91    return 1;
92}
93
94static enum test_return cache_fail_constructor_test(void)
95{
96    enum test_return ret = TEST_PASS;
97    uint64_t *ptr;
98    cache_t *cache = cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
99                                  cache_fail_constructor, NULL);
100    cb_assert(cache != NULL);
101    ptr = cache_alloc(cache);
102    if (ptr != NULL) {
103        ret = TEST_FAIL;
104    }
105    cache_destroy(cache);
106    return ret;
107}
108
109static void *destruct_data = 0;
110
111static void cache_destructor(void *buffer, void *notused) {
112    destruct_data = buffer;
113}
114
115static enum test_return cache_destructor_test(void)
116{
117    char *ptr;
118    cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
119                                  NULL, cache_destructor);
120    cb_assert(cache != NULL);
121    ptr = cache_alloc(cache);
122    cache_free(cache, ptr);
123    cache_destroy(cache);
124
125    return (ptr == destruct_data) ? TEST_PASS : TEST_FAIL;
126}
127
128static enum test_return cache_reuse_test(void)
129{
130    int ii;
131    cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
132                                  NULL, NULL);
133    char *ptr = cache_alloc(cache);
134    cache_free(cache, ptr);
135    for (ii = 0; ii < 100; ++ii) {
136        char *p = cache_alloc(cache);
137        cb_assert(p == ptr);
138        cache_free(cache, ptr);
139    }
140    cache_destroy(cache);
141    return TEST_PASS;
142}
143
144
145static enum test_return cache_bulkalloc(size_t datasize)
146{
147    cache_t *cache = cache_create("test", datasize, sizeof(char*),
148                                  NULL, NULL);
149#define ITERATIONS 1024
150    void *ptr[ITERATIONS];
151    int ii;
152    for (ii = 0; ii < ITERATIONS; ++ii) {
153        ptr[ii] = cache_alloc(cache);
154        cb_assert(ptr[ii] != 0);
155        memset(ptr[ii], 0xff, datasize);
156    }
157
158    for (ii = 0; ii < ITERATIONS; ++ii) {
159        cache_free(cache, ptr[ii]);
160    }
161
162#undef ITERATIONS
163    cache_destroy(cache);
164    return TEST_PASS;
165}
166
167static enum test_return test_issue_161(void)
168{
169    enum test_return ret = cache_bulkalloc(1);
170    if (ret == TEST_PASS) {
171        ret = cache_bulkalloc(512);
172    }
173
174    return ret;
175}
176
177static enum test_return cache_redzone_test(void)
178{
179#if !defined(HAVE_UMEM_H) && !defined(NDEBUG) && !defined(WIN32)
180    cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
181                                  NULL, NULL);
182
183    /* Ignore SIGABORT */
184    struct sigaction old_action;
185    struct sigaction action;
186    char *p;
187    char old;
188
189    memset(&action, 0, sizeof(action));
190    action.sa_handler = SIG_IGN;
191    sigemptyset(&action.sa_mask);
192    sigaction(SIGABRT, &action, &old_action);
193
194    /* check memory debug.. */
195    p = cache_alloc(cache);
196    old = *(p - 1);
197    *(p - 1) = 0;
198    cache_free(cache, p);
199    cb_assert(cache_error == -1);
200    *(p - 1) = old;
201
202    p[sizeof(uint32_t)] = 0;
203    cache_free(cache, p);
204    cb_assert(cache_error == 1);
205
206    /* restore signal handler */
207    sigaction(SIGABRT, &old_action, NULL);
208
209    cache_destroy(cache);
210
211    return TEST_PASS;
212#else
213    return TEST_SKIP;
214#endif
215}
216
217static enum test_return test_safe_strtoul(void) {
218    uint32_t val;
219    cb_assert(safe_strtoul("123", &val));
220    cb_assert(val == 123);
221    cb_assert(safe_strtoul("+123", &val));
222    cb_assert(val == 123);
223    cb_assert(!safe_strtoul("", &val));  /* empty */
224    cb_assert(!safe_strtoul("123BOGUS", &val));  /* non-numeric */
225    /* Not sure what it does, but this works with ICC :/
226       cb_assert(!safe_strtoul("92837498237498237498029383", &val)); // out of range
227    */
228
229    /* extremes: */
230    cb_assert(safe_strtoul("4294967295", &val)); /* 2**32 - 1 */
231    cb_assert(val == 4294967295L);
232    /* This actually works on 64-bit ubuntu
233       cb_assert(!safe_strtoul("4294967296", &val)); 2**32
234    */
235    cb_assert(!safe_strtoul("-1", &val));  /* negative */
236    return TEST_PASS;
237}
238
239
240static enum test_return test_safe_strtoull(void) {
241    uint64_t val;
242    uint64_t exp = -1;
243    cb_assert(safe_strtoull("123", &val));
244    cb_assert(val == 123);
245    cb_assert(safe_strtoull("+123", &val));
246    cb_assert(val == 123);
247    cb_assert(!safe_strtoull("", &val));  /* empty */
248    cb_assert(!safe_strtoull("123BOGUS", &val));  /* non-numeric */
249    cb_assert(!safe_strtoull("92837498237498237498029383", &val)); /* out of range */
250
251    /* extremes: */
252    cb_assert(safe_strtoull("18446744073709551615", &val)); /* 2**64 - 1 */
253    cb_assert(val == exp);
254    cb_assert(!safe_strtoull("18446744073709551616", &val)); /* 2**64 */
255    cb_assert(!safe_strtoull("-1", &val));  /* negative */
256    return TEST_PASS;
257}
258
259static enum test_return test_safe_strtoll(void) {
260    int64_t val;
261    int64_t exp = 1;
262    exp <<= 63;
263    exp -= 1;
264    cb_assert(safe_strtoll("123", &val));
265    cb_assert(val == 123);
266    cb_assert(safe_strtoll("+123", &val));
267    cb_assert(val == 123);
268    cb_assert(safe_strtoll("-123", &val));
269    cb_assert(val == -123);
270    cb_assert(!safe_strtoll("", &val));  /* empty */
271    cb_assert(!safe_strtoll("123BOGUS", &val));  /* non-numeric */
272    cb_assert(!safe_strtoll("92837498237498237498029383", &val)); /* out of range */
273
274    /* extremes: */
275    cb_assert(!safe_strtoll("18446744073709551615", &val)); /* 2**64 - 1 */
276    cb_assert(safe_strtoll("9223372036854775807", &val)); /* 2**63 - 1 */
277
278    cb_assert(val == exp); /* 9223372036854775807LL); */
279    /*
280      cb_assert(safe_strtoll("-9223372036854775808", &val)); // -2**63
281      cb_assert(val == -9223372036854775808LL);
282    */
283    cb_assert(!safe_strtoll("-9223372036854775809", &val)); /* -2**63 - 1 */
284
285    /* We'll allow space to terminate the string.  And leading space. */
286    cb_assert(safe_strtoll(" 123 foo", &val));
287    cb_assert(val == 123);
288    return TEST_PASS;
289}
290
291static enum test_return test_safe_strtol(void) {
292    int32_t val;
293    cb_assert(safe_strtol("123", &val));
294    cb_assert(val == 123);
295    cb_assert(safe_strtol("+123", &val));
296    cb_assert(val == 123);
297    cb_assert(safe_strtol("-123", &val));
298    cb_assert(val == -123);
299    cb_assert(!safe_strtol("", &val));  /* empty */
300    cb_assert(!safe_strtol("123BOGUS", &val));  /* non-numeric */
301    cb_assert(!safe_strtol("92837498237498237498029383", &val)); /* out of range */
302
303    /* extremes: */
304    /* This actually works on 64-bit ubuntu
305       cb_assert(!safe_strtol("2147483648", &val)); // (expt 2.0 31.0)
306    */
307    cb_assert(safe_strtol("2147483647", &val)); /* (- (expt 2.0 31) 1) */
308    cb_assert(val == 2147483647L);
309    /* This actually works on 64-bit ubuntu
310       cb_assert(!safe_strtol("-2147483649", &val)); // (- (expt -2.0 31) 1)
311    */
312
313    /* We'll allow space to terminate the string.  And leading space. */
314    cb_assert(safe_strtol(" 123 foo", &val));
315    cb_assert(val == 123);
316    return TEST_PASS;
317}
318
319static enum test_return test_safe_strtof(void) {
320    float val;
321    cb_assert(safe_strtof("123", &val));
322    cb_assert(val == 123.00f);
323    cb_assert(safe_strtof("+123", &val));
324    cb_assert(val == 123.00f);
325    cb_assert(safe_strtof("-123", &val));
326    cb_assert(val == -123.00f);
327    cb_assert(!safe_strtof("", &val));  /* empty */
328    cb_assert(!safe_strtof("123BOGUS", &val));  /* non-numeric */
329
330    /* We'll allow space to terminate the string.  And leading space. */
331    cb_assert(safe_strtof(" 123 foo", &val));
332    cb_assert(val == 123.00f);
333
334    cb_assert(safe_strtof("123.23", &val));
335    cb_assert(val == 123.23f);
336
337    cb_assert(safe_strtof("123.00", &val));
338    cb_assert(val == 123.00f);
339
340    return TEST_PASS;
341}
342
343#ifdef WIN32
344static void log_network_error(const char* prefix) {
345    LPVOID error_msg;
346    DWORD err = WSAGetLastError();
347
348    if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
349                      FORMAT_MESSAGE_FROM_SYSTEM |
350                      FORMAT_MESSAGE_IGNORE_INSERTS,
351                      NULL, err, 0,
352                      (LPTSTR)&error_msg, 0, NULL) != 0) {
353        fprintf(stderr, prefix, error_msg);
354        LocalFree(error_msg);
355    } else {
356        fprintf(stderr, prefix, "unknown error");
357    }
358}
359#else
360static void log_network_error(const char* prefix) {
361    fprintf(stderr, prefix, strerror(errno));
362}
363#endif
364
365#ifdef WIN32
366#define CERTIFICATE_PATH(file) ("\\tests\\cert\\"#file)
367#else
368#define CERTIFICATE_PATH(file) ("/tests/cert/"#file)
369#endif
370
371static void get_working_current_directory(char* out_buf, int out_buf_len) {
372    bool ok = false;
373#ifdef WIN32
374    ok = GetCurrentDirectory(out_buf_len, out_buf) != 0;
375#else
376    ok = getcwd(out_buf, out_buf_len) != NULL;
377#endif
378    /* memcached may throw a warning, but let's push through */
379    if (!ok) {
380        fprintf(stderr, "Failed to determine current working directory");
381        strncpy(out_buf, ".", out_buf_len);
382    }
383}
384
385static int generate_config(const char *fname)
386{
387    FILE *fp;
388    cJSON *root = cJSON_CreateObject();
389    cJSON *array = cJSON_CreateArray();
390    cJSON *obj = cJSON_CreateObject();
391    cJSON *obj_ssl = NULL;
392    char pem_path[256];
393    char cert_path[256];
394
395    get_working_current_directory(pem_path, 256);
396    strncpy(cert_path, pem_path, 256);
397    strncat(pem_path, CERTIFICATE_PATH(testapp.pem), 256);
398    strncat(cert_path, CERTIFICATE_PATH(testapp.cert), 256);
399
400    cJSON_AddStringToObject(obj, "module", "default_engine.so");
401    cJSON_AddItemReferenceToObject(root, "engine", obj);
402
403    obj = cJSON_CreateObject();
404    cJSON_AddStringToObject(obj, "module", "blackhole_logger.so");
405    cJSON_AddItemToArray(array, obj);
406    obj = cJSON_CreateObject();
407    cJSON_AddStringToObject(obj, "module", "fragment_rw_ops.so");
408    cJSON_AddStringToObject(obj, "config", "r=225;w=226");
409    cJSON_AddItemToArray(array, obj);
410    obj = cJSON_CreateObject();
411    cJSON_AddStringToObject(obj, "module", "testapp_extension.so");
412    cJSON_AddItemToArray(array, obj);
413
414    cJSON_AddItemReferenceToObject(root, "extensions", array);
415
416    array = cJSON_CreateArray();
417    obj = cJSON_CreateObject();
418    obj_ssl = cJSON_CreateObject();
419
420#ifdef WIN32
421    cJSON_AddNumberToObject(obj, "port", 11211);
422#else
423    cJSON_AddNumberToObject(obj, "port", 0);
424#endif
425    cJSON_AddNumberToObject(obj, "maxconn", 1000);
426    cJSON_AddNumberToObject(obj, "backlog", 1024);
427    cJSON_AddStringToObject(obj, "host", "*");
428    cJSON_AddItemToArray(array, obj);
429
430    obj = cJSON_CreateObject();
431    cJSON_AddNumberToObject(obj, "port", 11996);
432    cJSON_AddNumberToObject(obj, "maxconn", 1000);
433    cJSON_AddNumberToObject(obj, "backlog", 1024);
434    cJSON_AddStringToObject(obj, "host", "*");
435    cJSON_AddItemToObject(obj, "ssl", obj_ssl = cJSON_CreateObject());
436    cJSON_AddStringToObject(obj_ssl, "key", pem_path);
437    cJSON_AddStringToObject(obj_ssl, "cert", cert_path);
438    cJSON_AddItemToArray(array, obj);
439    cJSON_AddItemReferenceToObject(root, "interfaces", array);
440
441    cJSON_AddStringToObject(root, "admin", "");
442    cJSON_AddTrueToObject(root, "datatype_support");
443
444    if ((fp = fopen(fname, "w")) == NULL) {
445        return -1;
446    } else {
447        fprintf(fp, "%s", cJSON_Print(root));
448        fclose(fp);
449    }
450
451    return 0;
452}
453
454#ifdef WIN32
455static HANDLE start_server(in_port_t *port_out, in_port_t *ssl_port_out, bool daemon, int timeout) {
456    STARTUPINFO sinfo;
457    PROCESS_INFORMATION pinfo;
458    char *commandline = malloc(1024);
459    char env[80];
460    sprintf_s(env, sizeof(env), "MEMCACHED_PARENT_MONITOR=%u", GetCurrentProcessId());
461    putenv(env);
462
463    memset(&sinfo, 0, sizeof(sinfo));
464    memset(&pinfo, 0, sizeof(pinfo));
465    sinfo.cb = sizeof(sinfo);
466
467    sprintf(commandline, "memcached.exe -C %s", config_file);
468
469    if (!CreateProcess("memcached.exe",
470                       commandline,
471                       NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW, NULL, NULL, &sinfo, &pinfo)) {
472        LPVOID error_msg;
473        DWORD err = GetLastError();
474
475        if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
476                          FORMAT_MESSAGE_FROM_SYSTEM |
477                          FORMAT_MESSAGE_IGNORE_INSERTS,
478                          NULL, err, 0,
479                          (LPTSTR)&error_msg, 0, NULL) != 0) {
480            fprintf(stderr, "Failed to start process: %s\n", error_msg);
481            LocalFree(error_msg);
482        } else {
483            fprintf(stderr, "Failed to start process: unknown error\n");
484        }
485        exit(EXIT_FAILURE);
486    }
487    /* Do a short sleep to let the other process to start */
488    Sleep(1);
489    CloseHandle(pinfo.hThread);
490
491    *port_out = 11211;
492    *ssl_port_out = 11996;
493    return pinfo.hProcess;
494}
495#else
496/**
497 * Function to start the server and let it listen on a random port
498 *
499 * @param port_out where to store the TCP port number the server is
500 *                 listening on
501 * @param daemon set to true if you want to run the memcached server
502 *               as a daemon process
503 * @return the pid of the memcached server
504 */
505
506static pid_t start_server(in_port_t *port_out, in_port_t *ssl_port_out, bool daemon, int timeout) {
507    char environment[80];
508    char *filename= environment + strlen("MEMCACHED_PORT_FILENAME=");
509#ifdef __sun
510    char coreadm[128];
511#endif
512    pid_t pid;
513    FILE *fp;
514    char buffer[80];
515
516    char env[80];
517    snprintf(env, sizeof(env), "MEMCACHED_PARENT_MONITOR=%lu", (unsigned long)getpid());
518    putenv(env);
519
520    snprintf(environment, sizeof(environment),
521             "MEMCACHED_PORT_FILENAME=/tmp/ports.%lu", (long)getpid());
522    remove(filename);
523
524#ifdef __sun
525    /* I want to name the corefiles differently so that they don't
526       overwrite each other
527    */
528    snprintf(coreadm, sizeof(coreadm),
529             "coreadm -p core.%%f.%%p %lu", (unsigned long)getpid());
530    system(coreadm);
531#endif
532
533    pid = fork();
534    cb_assert(pid != -1);
535
536    if (pid == 0) {
537        /* Child */
538        char *argv[20];
539        int arg = 0;
540        char tmo[24];
541
542        snprintf(tmo, sizeof(tmo), "%u", timeout);
543        putenv(environment);
544
545        argv[arg++] = "./memcached";
546        argv[arg++] = "-C";
547        argv[arg++] = (char*)config_file;
548
549        argv[arg++] = NULL;
550        cb_assert(execv(argv[0], argv) != -1);
551    }
552
553    /* Yeah just let us "busy-wait" for the file to be created ;-) */
554    while (access(filename, F_OK) == -1) {
555        usleep(10);
556    }
557
558    fp = fopen(filename, "r");
559    if (fp == NULL) {
560        fprintf(stderr, "Failed to open the file containing port numbers: %s\n",
561                strerror(errno));
562        cb_assert(false);
563    }
564
565    *port_out = (in_port_t)-1;
566    *ssl_port_out = (in_port_t)-1;
567
568    while ((fgets(buffer, sizeof(buffer), fp)) != NULL) {
569        if (strncmp(buffer, "TCP INET: ", 10) == 0) {
570            int32_t val;
571            cb_assert(safe_strtol(buffer + 10, &val));
572            if (*port_out == (in_port_t)-1) {
573                *port_out = (in_port_t)val;
574            } else {
575                *ssl_port_out = (in_port_t)val;
576            }
577        }
578    }
579    fclose(fp);
580    cb_assert(remove(filename) == 0);
581
582    return pid;
583}
584#endif
585
586static struct addrinfo *lookuphost(const char *hostname, in_port_t port)
587{
588    struct addrinfo *ai = 0;
589    struct addrinfo hints;
590    char service[NI_MAXSERV];
591    int error;
592
593    memset(&hints, 0, sizeof(hints));
594    hints.ai_family = AF_UNSPEC;
595    hints.ai_protocol = IPPROTO_TCP;
596    hints.ai_socktype = SOCK_STREAM;
597
598    (void)snprintf(service, NI_MAXSERV, "%d", port);
599    if ((error = getaddrinfo(hostname, service, &hints, &ai)) != 0) {
600#ifdef WIN32
601        log_network_error("getaddrinfo(): %s\r\n");
602#else
603       if (error != EAI_SYSTEM) {
604          fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
605       } else {
606          perror("getaddrinfo()");
607       }
608#endif
609    }
610
611    return ai;
612}
613
614
615
616static SOCKET create_connect_plain_socket(const char *hostname, in_port_t port, bool nonblock)
617{
618    struct addrinfo *ai = lookuphost(hostname, port);
619    SOCKET sock = INVALID_SOCKET;
620    if (ai != NULL) {
621       if ((sock = socket(ai->ai_family, ai->ai_socktype,
622                          ai->ai_protocol)) != INVALID_SOCKET) {
623          if (connect(sock, ai->ai_addr, (socklen_t)ai->ai_addrlen) == SOCKET_ERROR) {
624             log_network_error("Failed to connect socket: %s\n");
625             closesocket(sock);
626             sock = INVALID_SOCKET;
627          }
628       } else {
629          fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
630       }
631
632       freeaddrinfo(ai);
633    }
634    return sock;
635}
636
637static SOCKET create_connect_ssl_socket(const char *hostname, in_port_t port, bool nonblocking) {
638    char port_str[32];
639    int sfd = 0;
640    BIO* temp_bio = NULL;
641
642    snprintf(port_str, 32, "%d", port);
643    create_ssl_connection(&ssl_ctx, &temp_bio, hostname, port_str, NULL, NULL, 1);
644
645    if (ssl_bio_r) {
646        BIO_free(ssl_bio_r);
647    }
648    if (ssl_bio_w) {
649        BIO_free(ssl_bio_w);
650    }
651
652    /* SSL "trickery". To ensure we have full control over send/receive of data.
653       create_ssl_connection will have negotiated the SSL connection, now:
654       1. steal the underlying FD
655       2. Switch out the BIO_ssl_connect BIO for a plain memory BIO
656
657       Now send/receive is done under our control. byte by byte, large chunks etc...
658    */
659    sfd = BIO_get_fd(temp_bio, NULL);
660    BIO_get_ssl(temp_bio, &ssl);
661    ssl_bio_r = BIO_new(BIO_s_mem());
662    ssl_bio_w = BIO_new(BIO_s_mem());
663    SSL_set_bio(ssl, ssl_bio_r, ssl_bio_w);
664    return sfd;
665}
666
667static void connect_to_server(const char *hostname, in_port_t port, in_port_t ssl_port, bool nonblocking) {
668    sock = create_connect_plain_socket("127.0.0.1", port, nonblocking);
669    sock_ssl = create_connect_ssl_socket("127.0.0.1", ssl_port, nonblocking);
670
671    if (nonblocking) {
672        if (evutil_make_socket_nonblocking(sock) == -1 ||
673            evutil_make_socket_nonblocking(sock_ssl) == -1) {
674            fprintf(stderr, "evutil_make_socket_nonblocking failed\n");
675            abort();
676        }
677    }
678}
679
680/*
681    re-connect to server on hostname.
682    Uses global port and ssl_port values.
683    New socket-fd written to global "sock" and "ssl_bio"
684*/
685static void reconnect_to_server(const char *hostname, bool nonblocking) {
686#ifdef WIN32
687    closesocket(sock);
688    closesocket(sock_ssl);
689#else
690    close(sock);
691    close(sock_ssl);
692#endif
693    connect_to_server(hostname, port, ssl_port, nonblocking);
694}
695
696static enum test_return test_vperror(void) {
697#ifdef WIN32
698    return TEST_SKIP;
699#else
700    int rv = 0;
701    int oldstderr = dup(STDERR_FILENO);
702    char tmpl[sizeof(TMP_TEMPLATE)+1];
703    int newfile;
704    char buf[80] = {0};
705    FILE *efile;
706    char *prv;
707    char expected[80] = {0};
708
709    strncpy(tmpl, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
710
711    newfile = mkstemp(tmpl);
712    cb_assert(newfile > 0);
713    rv = dup2(newfile, STDERR_FILENO);
714    cb_assert(rv == STDERR_FILENO);
715    rv = close(newfile);
716    cb_assert(rv == 0);
717
718    errno = EIO;
719    vperror("Old McDonald had a farm.  %s", "EI EIO");
720
721    /* Restore stderr */
722    rv = dup2(oldstderr, STDERR_FILENO);
723    cb_assert(rv == STDERR_FILENO);
724
725
726    /* Go read the file */
727    efile = fopen(tmpl, "r");
728    cb_assert(efile);
729    prv = fgets(buf, sizeof(buf), efile);
730    cb_assert(prv);
731    fclose(efile);
732
733    unlink(tmpl);
734
735    snprintf(expected, sizeof(expected),
736             "Old McDonald had a farm.  EI EIO: %s\n", strerror(EIO));
737
738    /*
739    fprintf(stderr,
740            "\nExpected:  ``%s''"
741            "\nGot:       ``%s''\n", expected, buf);
742    */
743
744    return strcmp(expected, buf) == 0 ? TEST_PASS : TEST_FAIL;
745#endif
746}
747
748static char* trim(char* ptr) {
749    char *start = ptr;
750    char *end;
751
752    while (isspace(*start)) {
753        ++start;
754    }
755    end = start + strlen(start) - 1;
756    if (end != start) {
757        while (isspace(*end)) {
758            *end = '\0';
759            --end;
760        }
761    }
762    return start;
763}
764
765static enum test_return test_config_parser(void) {
766#ifndef WIN32
767    bool bool_val = false;
768    size_t size_val = 0;
769    ssize_t ssize_val = 0;
770    float float_val = 0;
771    char *string_val = 0;
772    int ii;
773    char buffer[1024];
774    FILE *cfg;
775    char outfile[sizeof(TMP_TEMPLATE)+1];
776    char cfgfile[sizeof(TMP_TEMPLATE)+1];
777    int newfile;
778    FILE *error;
779
780    /* Set up the different items I can handle */
781    struct config_item items[7];
782    memset(&items, 0, sizeof(items));
783    ii = 0;
784    items[ii].key = "bool";
785    items[ii].datatype = DT_BOOL;
786    items[ii].value.dt_bool = &bool_val;
787    ++ii;
788
789    items[ii].key = "size_t";
790    items[ii].datatype = DT_SIZE;
791    items[ii].value.dt_size = &size_val;
792    ++ii;
793
794    items[ii].key = "ssize_t";
795    items[ii].datatype = DT_SSIZE;
796    items[ii].value.dt_ssize = &ssize_val;
797    ++ii;
798
799    items[ii].key = "float";
800    items[ii].datatype = DT_FLOAT;
801    items[ii].value.dt_float = &float_val;
802    ++ii;
803
804    items[ii].key = "string";
805    items[ii].datatype = DT_STRING;
806    items[ii].value.dt_string = &string_val;
807    ++ii;
808
809    items[ii].key = "config_file";
810    items[ii].datatype = DT_CONFIGFILE;
811    ++ii;
812
813    items[ii].key = NULL;
814    ++ii;
815
816    cb_assert(ii == 7);
817    strncpy(outfile, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
818    strncpy(cfgfile, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
819
820    newfile = mkstemp(outfile);
821    cb_assert(newfile > 0);
822    error = fdopen(newfile, "w");
823
824    cb_assert(error != NULL);
825    cb_assert(parse_config("", items, error) == 0);
826    /* Nothing should be found */
827    for (ii = 0; ii < 5; ++ii) {
828        cb_assert(!items[0].found);
829    }
830
831    cb_assert(parse_config("bool=true", items, error) == 0);
832    cb_assert(bool_val);
833    /* only bool should be found */
834    cb_assert(items[0].found);
835    items[0].found = false;
836    for (ii = 0; ii < 5; ++ii) {
837        cb_assert(!items[0].found);
838    }
839
840    /* It should allow illegal keywords */
841    cb_assert(parse_config("pacman=dead", items, error) == 1);
842    /* and illegal values */
843    cb_assert(parse_config("bool=12", items, error) == -1);
844    cb_assert(!items[0].found);
845    /* and multiple occurences of the same value */
846    cb_assert(parse_config("size_t=1; size_t=1024", items, error) == 0);
847    cb_assert(items[1].found);
848    cb_assert(size_val == 1024);
849    items[1].found = false;
850
851    /* Empty string */
852    /* XXX:  This test fails on Linux, but works on OS X.
853    cb_assert(parse_config("string=", items, error) == 0);
854    cb_assert(items[4].found);
855    cb_assert(strcmp(string_val, "") == 0);
856    items[4].found = false;
857    */
858    /* Plain string */
859    cb_assert(parse_config("string=sval", items, error) == 0);
860    cb_assert(items[4].found);
861    cb_assert(strcmp(string_val, "sval") == 0);
862    items[4].found = false;
863    /* Leading space */
864    cb_assert(parse_config("string= sval", items, error) == 0);
865    cb_assert(items[4].found);
866    cb_assert(strcmp(string_val, "sval") == 0);
867    items[4].found = false;
868    /* Escaped leading space */
869    cb_assert(parse_config("string=\\ sval", items, error) == 0);
870    cb_assert(items[4].found);
871    cb_assert(strcmp(string_val, " sval") == 0);
872    items[4].found = false;
873    /* trailing space */
874    cb_assert(parse_config("string=sval ", items, error) == 0);
875    cb_assert(items[4].found);
876    cb_assert(strcmp(string_val, "sval") == 0);
877    items[4].found = false;
878    /* escaped trailing space */
879    cb_assert(parse_config("string=sval\\ ", items, error) == 0);
880    cb_assert(items[4].found);
881    cb_assert(strcmp(string_val, "sval ") == 0);
882    items[4].found = false;
883    /* escaped stop char */
884    cb_assert(parse_config("string=sval\\;blah=x", items, error) == 0);
885    cb_assert(items[4].found);
886    cb_assert(strcmp(string_val, "sval;blah=x") == 0);
887    items[4].found = false;
888    /* middle space */
889    cb_assert(parse_config("string=s val", items, error) == 0);
890    cb_assert(items[4].found);
891    cb_assert(strcmp(string_val, "s val") == 0);
892    items[4].found = false;
893
894    /* And all of the variables */
895    cb_assert(parse_config("bool=true;size_t=1024;float=12.5;string=somestr",
896                        items, error) == 0);
897    cb_assert(bool_val);
898    cb_assert(size_val == 1024);
899    cb_assert(float_val == 12.5f);
900    cb_assert(strcmp(string_val, "somestr") == 0);
901    for (ii = 0; ii < 5; ++ii) {
902        items[ii].found = false;
903    }
904
905    cb_assert(parse_config("size_t=1k", items, error) == 0);
906    cb_assert(items[1].found);
907    cb_assert(size_val == 1024);
908    items[1].found = false;
909    cb_assert(parse_config("size_t=1m", items, error) == 0);
910    cb_assert(items[1].found);
911    cb_assert(size_val == 1024*1024);
912    items[1].found = false;
913    cb_assert(parse_config("size_t=1g", items, error) == 0);
914    cb_assert(items[1].found);
915    cb_assert(size_val == 1024*1024*1024);
916    items[1].found = false;
917    cb_assert(parse_config("size_t=1K", items, error) == 0);
918    cb_assert(items[1].found);
919    cb_assert(size_val == 1024);
920    items[1].found = false;
921    cb_assert(parse_config("size_t=1M", items, error) == 0);
922    cb_assert(items[1].found);
923    cb_assert(size_val == 1024*1024);
924    items[1].found = false;
925    cb_assert(parse_config("size_t=1G", items, error) == 0);
926    cb_assert(items[1].found);
927    cb_assert(size_val == 1024*1024*1024);
928    items[1].found = false;
929
930    newfile = mkstemp(cfgfile);
931    cb_assert(newfile > 0);
932    cfg = fdopen(newfile, "w");
933    cb_assert(cfg != NULL);
934    fprintf(cfg, "# This is a config file\nbool=true\nsize_t=1023\nfloat=12.4\n");
935    fclose(cfg);
936    sprintf(buffer, "config_file=%s", cfgfile);
937    cb_assert(parse_config(buffer, items, error) == 0);
938    cb_assert(bool_val);
939    cb_assert(size_val == 1023);
940    cb_assert(float_val == 12.4f);
941    fclose(error);
942
943    remove(cfgfile);
944    /* Verify that I received the error messages ;-) */
945    error = fopen(outfile, "r");
946    cb_assert(error);
947
948    cb_assert(fgets(buffer, sizeof(buffer), error));
949    cb_assert(strcmp("Unsupported key: <pacman>", trim(buffer)) == 0);
950    cb_assert(fgets(buffer, sizeof(buffer), error));
951    cb_assert(strcmp("Invalid entry, Key: <bool> Value: <12>", trim(buffer)) == 0);
952    cb_assert(fgets(buffer, sizeof(buffer), error));
953    cb_assert(strcmp("WARNING: Found duplicate entry for \"size_t\"", trim(buffer)) == 0);
954    cb_assert(fgets(buffer, sizeof(buffer), error) == NULL);
955
956    remove(outfile);
957    return TEST_PASS;
958#else
959    return TEST_SKIP;
960#endif
961}
962
963static enum test_return start_memcached_server(void) {
964    if (generate_config(config_file) == -1) {
965        return TEST_FAIL;
966    }
967
968    server_start_time = time(0);
969    server_pid = start_server(&port, &ssl_port, false, 600);
970    connect_to_server("127.0.0.1", port, ssl_port, false);
971    return TEST_PASS;
972}
973
974static enum test_return stop_memcached_server(void) {
975    closesocket(sock);
976    sock = INVALID_SOCKET;
977#ifdef WIN32
978    TerminateProcess(server_pid, 0);
979#else
980    if (kill(server_pid, SIGTERM) == 0) {
981        /* Wait for the process to be gone... */
982        while (kill(server_pid, 0) == 0) {
983            sleep(1);
984            waitpid(server_pid, NULL, WNOHANG);
985        }
986    }
987#endif
988
989    remove(config_file);
990    return TEST_PASS;
991}
992
993static ssize_t phase_send(const void *buf, size_t len) {
994    ssize_t rv = 0, send_rv = 0;
995    if (current_phase == phase_ssl) {
996        long send_len = 0;
997        char *send_buf = NULL;
998        /* push the data through SSL into the BIO */
999        rv = (ssize_t)SSL_write(ssl, (const char*)buf, len);
1000        send_len = BIO_get_mem_data(ssl_bio_w, &send_buf);
1001
1002#ifdef WIN32
1003        send_rv = send(sock_ssl, send_buf, (int)send_len, 0);
1004#else
1005        send_rv = send(sock_ssl, send_buf, send_len, 0);
1006#endif
1007
1008        if (send_rv > 0) {
1009            cb_assert(send_len == send_rv);
1010            (void)BIO_reset(ssl_bio_w);
1011        } else {
1012            /* flag failure to user */
1013            rv = send_rv;
1014        }
1015    } else {
1016#ifdef WIN32
1017        rv = send(sock, buf, (int)len, 0);
1018#else
1019        rv = send(sock, buf, len, 0);
1020#endif
1021    }
1022    return rv;
1023}
1024
1025static ssize_t phase_recv(void *buf, size_t len) {
1026
1027    ssize_t rv = 0;
1028    if (current_phase == phase_ssl) {
1029        /* can we read some data? */
1030        while((rv = SSL_peek(ssl, buf, len)) == -1)
1031        {
1032            /* nope, keep feeding SSL until we can */
1033#ifdef WIN32
1034            rv = recv(sock_ssl, buf, (int)len, 0);
1035#else
1036            rv = recv(sock_ssl, buf, len, 0);
1037#endif
1038
1039            if(rv > 0) {
1040                /* write into the BIO what came off the network */
1041                BIO_write(ssl_bio_r, buf, rv);
1042            } else if(rv == 0) {
1043                return rv; /* peer closed */
1044            }
1045        }
1046        /* now pull the data out and return */
1047        rv = SSL_read(ssl, buf, len);
1048    }
1049    else {
1050#ifdef WIN32
1051        rv = recv(sock, buf, (int)len, 0);
1052#else
1053        rv = recv(sock, buf, len, 0);
1054#endif
1055    }
1056    return rv;
1057}
1058
1059char ssl_error_string[256];
1060int ssl_error_string_len = 256;
1061
1062static char* phase_get_errno() {
1063    char * rv = 0;
1064    if (current_phase == phase_ssl) {
1065        /* could do with more work here, but so far this has sufficed */
1066        snprintf(ssl_error_string, ssl_error_string_len, "SSL error\n");
1067        rv = ssl_error_string;
1068    } else {
1069        rv = strerror(errno);
1070    }
1071    return rv;
1072}
1073
1074static void safe_send(const void* buf, size_t len, bool hickup)
1075{
1076    off_t offset = 0;
1077    const char* ptr = buf;
1078    do {
1079        size_t num_bytes = len - offset;
1080        ssize_t nw;
1081        if (hickup) {
1082            if (num_bytes > 1024) {
1083                num_bytes = (rand() % 1023) + 1;
1084            }
1085        }
1086
1087        nw = phase_send(ptr + offset, num_bytes);
1088
1089        if (nw == -1) {
1090            if (errno != EINTR) {
1091                fprintf(stderr, "Failed to write: %s\n", phase_get_errno());
1092                abort();
1093            }
1094        } else {
1095            if (hickup) {
1096#ifndef WIN32
1097                usleep(100);
1098#endif
1099            }
1100            offset += nw;
1101        }
1102    } while (offset < len);
1103}
1104
1105static bool safe_recv(void *buf, size_t len) {
1106    off_t offset = 0;
1107    if (len == 0) {
1108        return true;
1109    }
1110    do {
1111
1112        ssize_t nr = phase_recv(((char*)buf) + offset, len - offset);
1113
1114        if (nr == -1) {
1115            if (errno != EINTR) {
1116                fprintf(stderr, "Failed to read: %s\n", phase_get_errno());
1117                abort();
1118            }
1119        } else {
1120            if (nr == 0 && allow_closed_read) {
1121                return false;
1122            }
1123            cb_assert(nr != 0);
1124            offset += nr;
1125        }
1126    } while (offset < len);
1127
1128    return true;
1129}
1130
1131static bool safe_recv_packet(void *buf, size_t size) {
1132    protocol_binary_response_no_extras *response = buf;
1133    char *ptr;
1134    size_t len;
1135
1136    cb_assert(size >= sizeof(*response));
1137    if (!safe_recv(response, sizeof(*response))) {
1138        return false;
1139    }
1140    response->message.header.response.keylen = ntohs(response->message.header.response.keylen);
1141    response->message.header.response.status = ntohs(response->message.header.response.status);
1142    response->message.header.response.bodylen = ntohl(response->message.header.response.bodylen);
1143
1144    len = sizeof(*response);
1145    ptr = buf;
1146    ptr += len;
1147    cb_assert(size >= (sizeof(*response) + response->message.header.response.bodylen));
1148    if (!safe_recv(ptr, response->message.header.response.bodylen)) {
1149        return false;
1150    }
1151
1152    return true;
1153}
1154
1155static off_t storage_command(char*buf,
1156                             size_t bufsz,
1157                             uint8_t cmd,
1158                             const void* key,
1159                             size_t keylen,
1160                             const void* dta,
1161                             size_t dtalen,
1162                             uint32_t flags,
1163                             uint32_t exp) {
1164    /* all of the storage commands use the same command layout */
1165    off_t key_offset;
1166    protocol_binary_request_set *request = (void*)buf;
1167    cb_assert(bufsz >= sizeof(*request) + keylen + dtalen);
1168
1169    memset(request, 0, sizeof(*request));
1170    request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1171    request->message.header.request.opcode = cmd;
1172    request->message.header.request.keylen = htons((uint16_t)keylen);
1173    request->message.header.request.extlen = 8;
1174    request->message.header.request.bodylen = htonl((uint32_t)(keylen + 8 + dtalen));
1175    request->message.header.request.opaque = 0xdeadbeef;
1176    request->message.body.flags = htonl(flags);
1177    request->message.body.expiration = htonl(exp);
1178
1179    key_offset = sizeof(protocol_binary_request_no_extras) + 8;
1180
1181    memcpy(buf + key_offset, key, keylen);
1182    if (dta != NULL) {
1183        memcpy(buf + key_offset + keylen, dta, dtalen);
1184    }
1185
1186    return (off_t)(key_offset + keylen + dtalen);
1187}
1188
1189static off_t raw_command(char* buf,
1190                         size_t bufsz,
1191                         uint8_t cmd,
1192                         const void* key,
1193                         size_t keylen,
1194                         const void* dta,
1195                         size_t dtalen) {
1196    /* all of the storage commands use the same command layout */
1197    off_t key_offset;
1198    protocol_binary_request_no_extras *request = (void*)buf;
1199    cb_assert(bufsz >= sizeof(*request) + keylen + dtalen);
1200
1201    memset(request, 0, sizeof(*request));
1202    if (cmd == read_command || cmd == write_command) {
1203        request->message.header.request.extlen = 8;
1204    }
1205    request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1206    request->message.header.request.opcode = cmd;
1207    request->message.header.request.keylen = htons((uint16_t)keylen);
1208    request->message.header.request.bodylen = htonl((uint32_t)(keylen + dtalen + request->message.header.request.extlen));
1209    request->message.header.request.opaque = 0xdeadbeef;
1210
1211    key_offset = sizeof(protocol_binary_request_no_extras) +
1212        request->message.header.request.extlen;
1213
1214    if (key != NULL) {
1215        memcpy(buf + key_offset, key, keylen);
1216    }
1217    if (dta != NULL) {
1218        memcpy(buf + key_offset + keylen, dta, dtalen);
1219    }
1220
1221    return (off_t)(sizeof(*request) + keylen + dtalen + request->message.header.request.extlen);
1222}
1223
1224static off_t flush_command(char* buf, size_t bufsz, uint8_t cmd, uint32_t exptime, bool use_extra) {
1225    off_t size;
1226    protocol_binary_request_flush *request = (void*)buf;
1227    cb_assert(bufsz > sizeof(*request));
1228
1229    memset(request, 0, sizeof(*request));
1230    request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1231    request->message.header.request.opcode = cmd;
1232
1233    size = sizeof(protocol_binary_request_no_extras);
1234    if (use_extra) {
1235        request->message.header.request.extlen = 4;
1236        request->message.body.expiration = htonl(exptime);
1237        request->message.header.request.bodylen = htonl(4);
1238        size += 4;
1239    }
1240
1241    request->message.header.request.opaque = 0xdeadbeef;
1242
1243    return size;
1244}
1245
1246static off_t arithmetic_command(char* buf,
1247                                size_t bufsz,
1248                                uint8_t cmd,
1249                                const void* key,
1250                                size_t keylen,
1251                                uint64_t delta,
1252                                uint64_t initial,
1253                                uint32_t exp) {
1254    off_t key_offset;
1255    protocol_binary_request_incr *request = (void*)buf;
1256    cb_assert(bufsz > sizeof(*request) + keylen);
1257
1258    memset(request, 0, sizeof(*request));
1259    request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1260    request->message.header.request.opcode = cmd;
1261    request->message.header.request.keylen = htons((uint16_t)keylen);
1262    request->message.header.request.extlen = 20;
1263    request->message.header.request.bodylen = htonl((uint32_t)(keylen + 20));
1264    request->message.header.request.opaque = 0xdeadbeef;
1265    request->message.body.delta = htonll(delta);
1266    request->message.body.initial = htonll(initial);
1267    request->message.body.expiration = htonl(exp);
1268
1269    key_offset = sizeof(protocol_binary_request_no_extras) + 20;
1270
1271    memcpy(buf + key_offset, key, keylen);
1272    return (off_t)(key_offset + keylen);
1273}
1274
1275static void validate_response_header(protocol_binary_response_no_extras *response,
1276                                     uint8_t cmd, uint16_t status)
1277{
1278    cb_assert(response->message.header.response.magic == PROTOCOL_BINARY_RES);
1279    cb_assert(response->message.header.response.opcode == cmd);
1280    cb_assert(response->message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
1281    if (status == PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND) {
1282        if (response->message.header.response.status == PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED) {
1283            response->message.header.response.status = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
1284        }
1285    }
1286    cb_assert(response->message.header.response.status == status);
1287    cb_assert(response->message.header.response.opaque == 0xdeadbeef);
1288
1289    if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
1290        switch (cmd) {
1291        case PROTOCOL_BINARY_CMD_ADDQ:
1292        case PROTOCOL_BINARY_CMD_APPENDQ:
1293        case PROTOCOL_BINARY_CMD_DECREMENTQ:
1294        case PROTOCOL_BINARY_CMD_DELETEQ:
1295        case PROTOCOL_BINARY_CMD_FLUSHQ:
1296        case PROTOCOL_BINARY_CMD_INCREMENTQ:
1297        case PROTOCOL_BINARY_CMD_PREPENDQ:
1298        case PROTOCOL_BINARY_CMD_QUITQ:
1299        case PROTOCOL_BINARY_CMD_REPLACEQ:
1300        case PROTOCOL_BINARY_CMD_SETQ:
1301            cb_assert("Quiet command shouldn't return on success" == NULL);
1302        default:
1303            break;
1304        }
1305
1306        switch (cmd) {
1307        case PROTOCOL_BINARY_CMD_ADD:
1308        case PROTOCOL_BINARY_CMD_REPLACE:
1309        case PROTOCOL_BINARY_CMD_SET:
1310        case PROTOCOL_BINARY_CMD_APPEND:
1311        case PROTOCOL_BINARY_CMD_PREPEND:
1312            cb_assert(response->message.header.response.keylen == 0);
1313            cb_assert(response->message.header.response.extlen == 0);
1314            cb_assert(response->message.header.response.bodylen == 0);
1315            cb_assert(response->message.header.response.cas != 0);
1316            break;
1317        case PROTOCOL_BINARY_CMD_FLUSH:
1318        case PROTOCOL_BINARY_CMD_NOOP:
1319        case PROTOCOL_BINARY_CMD_QUIT:
1320        case PROTOCOL_BINARY_CMD_DELETE:
1321            cb_assert(response->message.header.response.keylen == 0);
1322            cb_assert(response->message.header.response.extlen == 0);
1323            cb_assert(response->message.header.response.bodylen == 0);
1324            break;
1325
1326        case PROTOCOL_BINARY_CMD_DECREMENT:
1327        case PROTOCOL_BINARY_CMD_INCREMENT:
1328            cb_assert(response->message.header.response.keylen == 0);
1329            cb_assert(response->message.header.response.extlen == 0);
1330            cb_assert(response->message.header.response.bodylen == 8);
1331            cb_assert(response->message.header.response.cas != 0);
1332            break;
1333
1334        case PROTOCOL_BINARY_CMD_STAT:
1335            cb_assert(response->message.header.response.extlen == 0);
1336            /* key and value exists in all packets except in the terminating */
1337            cb_assert(response->message.header.response.cas == 0);
1338            break;
1339
1340        case PROTOCOL_BINARY_CMD_VERSION:
1341            cb_assert(response->message.header.response.keylen == 0);
1342            cb_assert(response->message.header.response.extlen == 0);
1343            cb_assert(response->message.header.response.bodylen != 0);
1344            cb_assert(response->message.header.response.cas == 0);
1345            break;
1346
1347        case PROTOCOL_BINARY_CMD_GET:
1348        case PROTOCOL_BINARY_CMD_GETQ:
1349            cb_assert(response->message.header.response.keylen == 0);
1350            cb_assert(response->message.header.response.extlen == 4);
1351            cb_assert(response->message.header.response.cas != 0);
1352            break;
1353
1354        case PROTOCOL_BINARY_CMD_GETK:
1355        case PROTOCOL_BINARY_CMD_GETKQ:
1356            cb_assert(response->message.header.response.keylen != 0);
1357            cb_assert(response->message.header.response.extlen == 4);
1358            cb_assert(response->message.header.response.cas != 0);
1359            break;
1360
1361        default:
1362            /* Undefined command code */
1363            break;
1364        }
1365    } else {
1366        cb_assert(response->message.header.response.cas == 0);
1367        cb_assert(response->message.header.response.extlen == 0);
1368        if (cmd != PROTOCOL_BINARY_CMD_GETK) {
1369            cb_assert(response->message.header.response.keylen == 0);
1370        }
1371    }
1372}
1373
1374static enum test_return test_binary_noop(void) {
1375    union {
1376        protocol_binary_request_no_extras request;
1377        protocol_binary_response_no_extras response;
1378        char bytes[1024];
1379    } buffer;
1380
1381    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1382                             PROTOCOL_BINARY_CMD_NOOP,
1383                             NULL, 0, NULL, 0);
1384
1385    safe_send(buffer.bytes, len, false);
1386    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1387    validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_NOOP,
1388                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1389
1390    return TEST_PASS;
1391}
1392
1393static enum test_return test_binary_quit_impl(uint8_t cmd) {
1394    union {
1395        protocol_binary_request_no_extras request;
1396        protocol_binary_response_no_extras response;
1397        char bytes[1024];
1398    } buffer;
1399    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1400                             cmd, NULL, 0, NULL, 0);
1401
1402    safe_send(buffer.bytes, len, false);
1403    if (cmd == PROTOCOL_BINARY_CMD_QUIT) {
1404        safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1405        validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_QUIT,
1406                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1407    }
1408
1409    /* Socket should be closed now, read should return 0 */
1410    cb_assert(phase_recv(buffer.bytes, sizeof(buffer.bytes)) == 0);
1411
1412    reconnect_to_server("127.0.0.1", false);
1413
1414    return TEST_PASS;
1415}
1416
1417static enum test_return test_binary_quit(void) {
1418    return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT);
1419}
1420
1421static enum test_return test_binary_quitq(void) {
1422    return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ);
1423}
1424
1425static enum test_return test_binary_set_impl(const char *key, uint8_t cmd) {
1426    union {
1427        protocol_binary_request_no_extras request;
1428        protocol_binary_response_no_extras response;
1429        char bytes[1024];
1430    } send, receive;
1431    uint64_t value = 0xdeadbeefdeadcafe;
1432    size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1433                                 key, strlen(key), &value, sizeof(value),
1434                                 0, 0);
1435
1436    /* Set should work over and over again */
1437    int ii;
1438    for (ii = 0; ii < 10; ++ii) {
1439        safe_send(send.bytes, len, false);
1440        if (cmd == PROTOCOL_BINARY_CMD_SET) {
1441            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1442            validate_response_header(&receive.response, cmd,
1443                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
1444        }
1445    }
1446
1447    if (cmd == PROTOCOL_BINARY_CMD_SETQ) {
1448        return test_binary_noop();
1449    }
1450
1451    send.request.message.header.request.cas = receive.response.message.header.response.cas;
1452    safe_send(send.bytes, len, false);
1453    if (cmd == PROTOCOL_BINARY_CMD_SET) {
1454        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1455        validate_response_header(&receive.response, cmd,
1456                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1457        cb_assert(receive.response.message.header.response.cas != send.request.message.header.request.cas);
1458    } else {
1459        return test_binary_noop();
1460    }
1461
1462    return TEST_PASS;
1463}
1464
1465static enum test_return test_binary_set(void) {
1466    return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET);
1467}
1468
1469static enum test_return test_binary_setq(void) {
1470    return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ);
1471}
1472
1473static enum test_return test_binary_add_impl(const char *key, uint8_t cmd) {
1474    uint64_t value = 0xdeadbeefdeadcafe;
1475    union {
1476        protocol_binary_request_no_extras request;
1477        protocol_binary_response_no_extras response;
1478        char bytes[1024];
1479    } send, receive;
1480    size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd, key,
1481                                 strlen(key), &value, sizeof(value),
1482                                 0, 0);
1483
1484    /* Add should only work the first time */
1485    int ii;
1486    for (ii = 0; ii < 10; ++ii) {
1487        safe_send(send.bytes, len, false);
1488        if (ii == 0) {
1489            if (cmd == PROTOCOL_BINARY_CMD_ADD) {
1490                safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1491                validate_response_header(&receive.response, cmd,
1492                                         PROTOCOL_BINARY_RESPONSE_SUCCESS);
1493            }
1494        } else {
1495            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1496            validate_response_header(&receive.response, cmd,
1497                                     PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
1498        }
1499    }
1500
1501    /* And verify that it doesn't work with the "correct" CAS */
1502    /* value */
1503    send.request.message.header.request.cas = receive.response.message.header.response.cas;
1504    safe_send(send.bytes, len, false);
1505    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1506    validate_response_header(&receive.response, cmd,
1507                             PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
1508    return TEST_PASS;
1509}
1510
1511static enum test_return test_binary_add(void) {
1512    return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD);
1513}
1514
1515static enum test_return test_binary_addq(void) {
1516    return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ);
1517}
1518
1519static enum test_return test_binary_replace_impl(const char* key, uint8_t cmd) {
1520    uint64_t value = 0xdeadbeefdeadcafe;
1521    union {
1522        protocol_binary_request_no_extras request;
1523        protocol_binary_response_no_extras response;
1524        char bytes[1024];
1525    } send, receive;
1526    int ii;
1527    size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1528                                 key, strlen(key), &value, sizeof(value),
1529                                 0, 0);
1530    safe_send(send.bytes, len, false);
1531    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1532    validate_response_header(&receive.response, cmd,
1533                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1534    len = storage_command(send.bytes, sizeof(send.bytes),
1535                          PROTOCOL_BINARY_CMD_ADD,
1536                          key, strlen(key), &value, sizeof(value), 0, 0);
1537    safe_send(send.bytes, len, false);
1538    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1539    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1540                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1541
1542    len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1543                          key, strlen(key), &value, sizeof(value), 0, 0);
1544    for (ii = 0; ii < 10; ++ii) {
1545        safe_send(send.bytes, len, false);
1546        if (cmd == PROTOCOL_BINARY_CMD_REPLACE) {
1547            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1548            validate_response_header(&receive.response,
1549                                     PROTOCOL_BINARY_CMD_REPLACE,
1550                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
1551        }
1552    }
1553
1554    if (cmd == PROTOCOL_BINARY_CMD_REPLACEQ) {
1555        test_binary_noop();
1556    }
1557
1558    return TEST_PASS;
1559}
1560
1561static enum test_return test_binary_replace(void) {
1562    return test_binary_replace_impl("test_binary_replace",
1563                                    PROTOCOL_BINARY_CMD_REPLACE);
1564}
1565
1566static enum test_return test_binary_replaceq(void) {
1567    return test_binary_replace_impl("test_binary_replaceq",
1568                                    PROTOCOL_BINARY_CMD_REPLACEQ);
1569}
1570
1571static enum test_return test_binary_delete_impl(const char *key, uint8_t cmd) {
1572    union {
1573        protocol_binary_request_no_extras request;
1574        protocol_binary_response_no_extras response;
1575        char bytes[1024];
1576    } send, receive;
1577    size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1578                             key, strlen(key), NULL, 0);
1579
1580    safe_send(send.bytes, len, false);
1581    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1582    validate_response_header(&receive.response, cmd,
1583                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1584    len = storage_command(send.bytes, sizeof(send.bytes),
1585                          PROTOCOL_BINARY_CMD_ADD,
1586                          key, strlen(key), NULL, 0, 0, 0);
1587    safe_send(send.bytes, len, false);
1588    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1589    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1590                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1591
1592    len = raw_command(send.bytes, sizeof(send.bytes),
1593                      cmd, key, strlen(key), NULL, 0);
1594    safe_send(send.bytes, len, false);
1595
1596    if (cmd == PROTOCOL_BINARY_CMD_DELETE) {
1597        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1598        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE,
1599                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1600    }
1601
1602    safe_send(send.bytes, len, false);
1603    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1604    validate_response_header(&receive.response, cmd,
1605                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1606
1607    return TEST_PASS;
1608}
1609
1610static enum test_return test_binary_delete(void) {
1611    return test_binary_delete_impl("test_binary_delete",
1612                                   PROTOCOL_BINARY_CMD_DELETE);
1613}
1614
1615static enum test_return test_binary_deleteq(void) {
1616    return test_binary_delete_impl("test_binary_deleteq",
1617                                   PROTOCOL_BINARY_CMD_DELETEQ);
1618}
1619
1620static enum test_return test_binary_delete_cas_impl(const char *key, bool bad) {
1621    union {
1622        protocol_binary_request_no_extras request;
1623        protocol_binary_response_no_extras response;
1624        char bytes[1024];
1625    } send, receive;
1626    size_t len;
1627    len = storage_command(send.bytes, sizeof(send.bytes),
1628                          PROTOCOL_BINARY_CMD_SET,
1629                          key, strlen(key), NULL, 0, 0, 0);
1630    safe_send(send.bytes, len, false);
1631    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1632    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1633                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1634    len = raw_command(send.bytes, sizeof(send.bytes),
1635                       PROTOCOL_BINARY_CMD_DELETE, key, strlen(key), NULL, 0);
1636
1637    send.request.message.header.request.cas = receive.response.message.header.response.cas;
1638    if (bad) {
1639        ++send.request.message.header.request.cas;
1640    }
1641    safe_send(send.bytes, len, false);
1642    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1643    if (bad) {
1644        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE,
1645                                 PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
1646    } else {
1647        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE,
1648                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1649    }
1650
1651    return TEST_PASS;
1652}
1653
1654
1655static enum test_return test_binary_delete_cas(void) {
1656    return test_binary_delete_cas_impl("test_binary_delete_cas", false);
1657}
1658
1659static enum test_return test_binary_delete_bad_cas(void) {
1660    return test_binary_delete_cas_impl("test_binary_delete_bad_cas", true);
1661}
1662
1663static enum test_return test_binary_get_impl(const char *key, uint8_t cmd) {
1664    union {
1665        protocol_binary_request_no_extras request;
1666        protocol_binary_response_no_extras response;
1667        char bytes[1024];
1668    } send, receive;
1669    int ii;
1670    size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1671                             key, strlen(key), NULL, 0);
1672
1673    safe_send(send.bytes, len, false);
1674    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1675    validate_response_header(&receive.response, cmd,
1676                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1677
1678    len = storage_command(send.bytes, sizeof(send.bytes),
1679                          PROTOCOL_BINARY_CMD_ADD,
1680                          key, strlen(key), NULL, 0,
1681                          0, 0);
1682    safe_send(send.bytes, len, false);
1683    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1684    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1685                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1686
1687    /* run a little pipeline test ;-) */
1688    len = 0;
1689    for (ii = 0; ii < 10; ++ii) {
1690        union {
1691            protocol_binary_request_no_extras request;
1692            char bytes[1024];
1693        } temp;
1694        size_t l = raw_command(temp.bytes, sizeof(temp.bytes),
1695                               cmd, key, strlen(key), NULL, 0);
1696        memcpy(send.bytes + len, temp.bytes, l);
1697        len += l;
1698    }
1699
1700    safe_send(send.bytes, len, false);
1701    for (ii = 0; ii < 10; ++ii) {
1702        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1703        validate_response_header(&receive.response, cmd,
1704                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1705    }
1706
1707    return TEST_PASS;
1708}
1709
1710static enum test_return test_binary_get(void) {
1711    return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET);
1712}
1713
1714static enum test_return test_binary_getk(void) {
1715    return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK);
1716}
1717
1718static enum test_return test_binary_getq_impl(const char *key, uint8_t cmd) {
1719    const char *missing = "test_binary_getq_missing";
1720    union {
1721        protocol_binary_request_no_extras request;
1722        protocol_binary_response_no_extras response;
1723        char bytes[1024];
1724    } send, temp, receive;
1725    size_t len = storage_command(send.bytes, sizeof(send.bytes),
1726                                 PROTOCOL_BINARY_CMD_ADD,
1727                                 key, strlen(key), NULL, 0,
1728                                 0, 0);
1729    size_t len2 = raw_command(temp.bytes, sizeof(temp.bytes), cmd,
1730                             missing, strlen(missing), NULL, 0);
1731    /* I need to change the first opaque so that I can separate the two
1732     * return packets */
1733    temp.request.message.header.request.opaque = 0xfeedface;
1734    memcpy(send.bytes + len, temp.bytes, len2);
1735    len += len2;
1736
1737    len2 = raw_command(temp.bytes, sizeof(temp.bytes), cmd,
1738                       key, strlen(key), NULL, 0);
1739    memcpy(send.bytes + len, temp.bytes, len2);
1740    len += len2;
1741
1742    safe_send(send.bytes, len, false);
1743    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1744    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1745                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1746    /* The first GETQ shouldn't return anything */
1747    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1748    validate_response_header(&receive.response, cmd,
1749                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1750
1751    return TEST_PASS;
1752}
1753
1754static enum test_return test_binary_getq(void) {
1755    return test_binary_getq_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ);
1756}
1757
1758static enum test_return test_binary_getkq(void) {
1759    return test_binary_getq_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ);
1760}
1761
1762static enum test_return test_binary_incr_impl(const char* key, uint8_t cmd) {
1763    union {
1764        protocol_binary_request_no_extras request;
1765        protocol_binary_response_no_extras response_header;
1766        protocol_binary_response_incr response;
1767        char bytes[1024];
1768    } send, receive;
1769    size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
1770                                    key, strlen(key), 1, 0, 0);
1771
1772    int ii;
1773    for (ii = 0; ii < 10; ++ii) {
1774        safe_send(send.bytes, len, false);
1775        if (cmd == PROTOCOL_BINARY_CMD_INCREMENT) {
1776            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1777            validate_response_header(&receive.response_header, cmd,
1778                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
1779            cb_assert(ntohll(receive.response.message.body.value) == ii);
1780        }
1781    }
1782
1783    if (cmd == PROTOCOL_BINARY_CMD_INCREMENTQ) {
1784        test_binary_noop();
1785    }
1786    return TEST_PASS;
1787}
1788
1789static enum test_return test_binary_incr(void) {
1790    return test_binary_incr_impl("test_binary_incr",
1791                                 PROTOCOL_BINARY_CMD_INCREMENT);
1792}
1793
1794static enum test_return test_binary_incrq(void) {
1795    return test_binary_incr_impl("test_binary_incrq",
1796                                 PROTOCOL_BINARY_CMD_INCREMENTQ);
1797}
1798
1799static enum test_return test_binary_incr_invalid_cas_impl(const char* key, uint8_t cmd) {
1800    union {
1801        protocol_binary_request_no_extras request;
1802        protocol_binary_response_no_extras response_header;
1803        protocol_binary_response_incr response;
1804        char bytes[1024];
1805    } send, receive;
1806    size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
1807                                    key, strlen(key), 1, 0, 0);
1808
1809    send.request.message.header.request.cas = 5;
1810    safe_send(send.bytes, len, false);
1811    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1812    validate_response_header(&receive.response_header, cmd,
1813                             PROTOCOL_BINARY_RESPONSE_EINVAL);
1814    return TEST_PASS;
1815}
1816
1817static enum test_return test_binary_invalid_cas_incr(void) {
1818    return test_binary_incr_invalid_cas_impl("test_binary_incr",
1819                                             PROTOCOL_BINARY_CMD_INCREMENT);
1820}
1821
1822static enum test_return test_binary_invalid_cas_incrq(void) {
1823    return test_binary_incr_invalid_cas_impl("test_binary_incrq",
1824                                             PROTOCOL_BINARY_CMD_INCREMENTQ);
1825}
1826
1827static enum test_return test_binary_invalid_cas_decr(void) {
1828    return test_binary_incr_invalid_cas_impl("test_binary_incr",
1829                                             PROTOCOL_BINARY_CMD_DECREMENT);
1830}
1831
1832static enum test_return test_binary_invalid_cas_decrq(void) {
1833    return test_binary_incr_invalid_cas_impl("test_binary_incrq",
1834                                             PROTOCOL_BINARY_CMD_DECREMENTQ);
1835}
1836
1837static enum test_return test_binary_decr_impl(const char* key, uint8_t cmd) {
1838    union {
1839        protocol_binary_request_no_extras request;
1840        protocol_binary_response_no_extras response_header;
1841        protocol_binary_response_decr response;
1842        char bytes[1024];
1843    } send, receive;
1844    size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
1845                                    key, strlen(key), 1, 9, 0);
1846
1847    int ii;
1848    for (ii = 9; ii >= 0; --ii) {
1849        safe_send(send.bytes, len, false);
1850        if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
1851            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1852            validate_response_header(&receive.response_header, cmd,
1853                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
1854            cb_assert(ntohll(receive.response.message.body.value) == ii);
1855        }
1856    }
1857
1858    /* decr on 0 should not wrap */
1859    safe_send(send.bytes, len, false);
1860    if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
1861        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1862        validate_response_header(&receive.response_header, cmd,
1863                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1864        cb_assert(ntohll(receive.response.message.body.value) == 0);
1865    } else {
1866        test_binary_noop();
1867    }
1868
1869    return TEST_PASS;
1870}
1871
1872static enum test_return test_binary_decr(void) {
1873    return test_binary_decr_impl("test_binary_decr",
1874                                 PROTOCOL_BINARY_CMD_DECREMENT);
1875}
1876
1877static enum test_return test_binary_decrq(void) {
1878    return test_binary_decr_impl("test_binary_decrq",
1879                                 PROTOCOL_BINARY_CMD_DECREMENTQ);
1880}
1881
1882static enum test_return test_binary_version(void) {
1883    union {
1884        protocol_binary_request_no_extras request;
1885        protocol_binary_response_no_extras response;
1886        char bytes[1024];
1887    } buffer;
1888
1889    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1890                             PROTOCOL_BINARY_CMD_VERSION,
1891                             NULL, 0, NULL, 0);
1892
1893    safe_send(buffer.bytes, len, false);
1894    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1895    validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_VERSION,
1896                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1897
1898    return TEST_PASS;
1899}
1900
1901static enum test_return test_binary_flush_impl(const char *key, uint8_t cmd) {
1902    union {
1903        protocol_binary_request_no_extras request;
1904        protocol_binary_response_no_extras response;
1905        char bytes[1024];
1906    } send, receive;
1907    int ii;
1908
1909    size_t len = storage_command(send.bytes, sizeof(send.bytes),
1910                                 PROTOCOL_BINARY_CMD_ADD,
1911                                 key, strlen(key), NULL, 0, 0, 0);
1912    safe_send(send.bytes, len, false);
1913    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1914    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1915                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1916
1917    len = flush_command(send.bytes, sizeof(send.bytes), cmd, 2, true);
1918    safe_send(send.bytes, len, false);
1919    if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
1920        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1921        validate_response_header(&receive.response, cmd,
1922                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1923    }
1924
1925    len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GET,
1926                      key, strlen(key), NULL, 0);
1927    safe_send(send.bytes, len, false);
1928    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1929    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1930                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1931
1932#ifdef WIN32
1933    Sleep(2000);
1934#else
1935    sleep(2);
1936#endif
1937    safe_send(send.bytes, len, false);
1938    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1939    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1940                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1941
1942    for (ii = 0; ii < 2; ++ii) {
1943        len = storage_command(send.bytes, sizeof(send.bytes),
1944                              PROTOCOL_BINARY_CMD_ADD,
1945                              key, strlen(key), NULL, 0, 0, 0);
1946        safe_send(send.bytes, len, false);
1947        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1948        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1949                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1950
1951        len = flush_command(send.bytes, sizeof(send.bytes), cmd, 0, ii == 0);
1952        safe_send(send.bytes, len, false);
1953        if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
1954            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1955            validate_response_header(&receive.response, cmd,
1956                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
1957        }
1958
1959        len = raw_command(send.bytes, sizeof(send.bytes),
1960                          PROTOCOL_BINARY_CMD_GET,
1961                          key, strlen(key), NULL, 0);
1962        safe_send(send.bytes, len, false);
1963        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1964        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1965                                 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1966    }
1967
1968    return TEST_PASS;
1969}
1970
1971static enum test_return test_binary_flush(void) {
1972    return test_binary_flush_impl("test_binary_flush",
1973                                  PROTOCOL_BINARY_CMD_FLUSH);
1974}
1975
1976static enum test_return test_binary_flushq(void) {
1977    return test_binary_flush_impl("test_binary_flushq",
1978                                  PROTOCOL_BINARY_CMD_FLUSHQ);
1979}
1980
1981static enum test_return test_binary_cas(void) {
1982    union {
1983        protocol_binary_request_no_extras request;
1984        protocol_binary_response_no_extras response;
1985        char bytes[1024];
1986    } send, receive;
1987    uint64_t value = 0xdeadbeefdeadcafe;
1988    size_t len = flush_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_FLUSH,
1989                               0, false);
1990    safe_send(send.bytes, len, false);
1991    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1992    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_FLUSH,
1993                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1994
1995    len = storage_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_SET,
1996                          "FOO", 3, &value, sizeof(value), 0, 0);
1997
1998    send.request.message.header.request.cas = 0x7ffffff;
1999    safe_send(send.bytes, len, false);
2000    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2001    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
2002                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
2003
2004    send.request.message.header.request.cas = 0x0;
2005    safe_send(send.bytes, len, false);
2006    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2007    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
2008                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2009
2010    send.request.message.header.request.cas = receive.response.message.header.response.cas;
2011    safe_send(send.bytes, len, false);
2012    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2013    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
2014                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2015
2016    send.request.message.header.request.cas = receive.response.message.header.response.cas - 1;
2017    safe_send(send.bytes, len, false);
2018    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2019    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
2020                             PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
2021    return TEST_PASS;
2022}
2023
2024static enum test_return test_binary_concat_impl(const char *key, uint8_t cmd) {
2025    union {
2026        protocol_binary_request_no_extras request;
2027        protocol_binary_response_no_extras response;
2028        char bytes[1024];
2029    } send, receive;
2030    const char *value = "world";
2031    char *ptr;
2032    size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
2033                              key, strlen(key), value, strlen(value));
2034
2035
2036    safe_send(send.bytes, len, false);
2037    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2038    validate_response_header(&receive.response, cmd,
2039                             PROTOCOL_BINARY_RESPONSE_NOT_STORED);
2040
2041    len = storage_command(send.bytes, sizeof(send.bytes),
2042                          PROTOCOL_BINARY_CMD_ADD,
2043                          key, strlen(key), value, strlen(value), 0, 0);
2044    safe_send(send.bytes, len, false);
2045    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2046    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
2047                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2048
2049    len = raw_command(send.bytes, sizeof(send.bytes), cmd,
2050                      key, strlen(key), value, strlen(value));
2051    safe_send(send.bytes, len, false);
2052
2053    if (cmd == PROTOCOL_BINARY_CMD_APPEND || cmd == PROTOCOL_BINARY_CMD_PREPEND) {
2054        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2055        validate_response_header(&receive.response, cmd,
2056                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
2057    } else {
2058        len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_NOOP,
2059                          NULL, 0, NULL, 0);
2060        safe_send(send.bytes, len, false);
2061        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2062        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_NOOP,
2063                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
2064    }
2065
2066    len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GETK,
2067                      key, strlen(key), NULL, 0);
2068
2069    safe_send(send.bytes, len, false);
2070    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2071    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GETK,
2072                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2073
2074    cb_assert(receive.response.message.header.response.keylen == strlen(key));
2075    cb_assert(receive.response.message.header.response.bodylen == (strlen(key) + 2*strlen(value) + 4));
2076
2077    ptr = receive.bytes;
2078    ptr += sizeof(receive.response);
2079    ptr += 4;
2080
2081    cb_assert(memcmp(ptr, key, strlen(key)) == 0);
2082    ptr += strlen(key);
2083    cb_assert(memcmp(ptr, value, strlen(value)) == 0);
2084    ptr += strlen(value);
2085    cb_assert(memcmp(ptr, value, strlen(value)) == 0);
2086
2087    return TEST_PASS;
2088}
2089
2090static enum test_return test_binary_append(void) {
2091    return test_binary_concat_impl("test_binary_append",
2092                                   PROTOCOL_BINARY_CMD_APPEND);
2093}
2094
2095static enum test_return test_binary_prepend(void) {
2096    return test_binary_concat_impl("test_binary_prepend",
2097                                   PROTOCOL_BINARY_CMD_PREPEND);
2098}
2099
2100static enum test_return test_binary_appendq(void) {
2101    return test_binary_concat_impl("test_binary_appendq",
2102                                   PROTOCOL_BINARY_CMD_APPENDQ);
2103}
2104
2105static enum test_return test_binary_prependq(void) {
2106    return test_binary_concat_impl("test_binary_prependq",
2107                                   PROTOCOL_BINARY_CMD_PREPENDQ);
2108}
2109
2110static enum test_return test_binary_stat(void) {
2111    union {
2112        protocol_binary_request_no_extras request;
2113        protocol_binary_response_no_extras response;
2114        char bytes[1024];
2115    } buffer;
2116
2117    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2118                             PROTOCOL_BINARY_CMD_STAT,
2119                             NULL, 0, NULL, 0);
2120
2121    safe_send(buffer.bytes, len, false);
2122    do {
2123        safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2124        validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_STAT,
2125                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
2126    } while (buffer.response.message.header.response.keylen != 0);
2127
2128    return TEST_PASS;
2129}
2130
2131static enum test_return test_binary_scrub(void) {
2132    union {
2133        protocol_binary_request_no_extras request;
2134        protocol_binary_response_no_extras response;
2135        char bytes[1024];
2136    } buffer;
2137
2138    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2139                             PROTOCOL_BINARY_CMD_SCRUB,
2140                             NULL, 0, NULL, 0);
2141
2142    safe_send(buffer.bytes, len, false);
2143    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2144    validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_SCRUB,
2145                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2146
2147    return TEST_PASS;
2148}
2149
2150
2151volatile bool hickup_thread_running;
2152
2153static void binary_hickup_recv_verification_thread(void *arg) {
2154    protocol_binary_response_no_extras *response = malloc(65*1024);
2155    if (response != NULL) {
2156        while (safe_recv_packet(response, 65*1024)) {
2157            /* Just validate the packet format */
2158            validate_response_header(response,
2159                                     response->message.header.response.opcode,
2160                                     response->message.header.response.status);
2161        }
2162        free(response);
2163    }
2164    hickup_thread_running = false;
2165    allow_closed_read = false;
2166}
2167
2168static enum test_return test_binary_pipeline_hickup_chunk(void *buffer, size_t buffersize) {
2169    off_t offset = 0;
2170    char *key[256];
2171    uint64_t value = 0xfeedfacedeadbeef;
2172
2173    while (hickup_thread_running &&
2174           offset + sizeof(protocol_binary_request_no_extras) < buffersize) {
2175        union {
2176            protocol_binary_request_no_extras request;
2177            char bytes[65 * 1024];
2178        } command;
2179        uint8_t cmd = (uint8_t)(rand() & 0xff);
2180        size_t len;
2181        size_t keylen = (rand() % 250) + 1;
2182
2183        switch (cmd) {
2184        case PROTOCOL_BINARY_CMD_ADD:
2185        case PROTOCOL_BINARY_CMD_ADDQ:
2186        case PROTOCOL_BINARY_CMD_REPLACE:
2187        case PROTOCOL_BINARY_CMD_REPLACEQ:
2188        case PROTOCOL_BINARY_CMD_SET:
2189        case PROTOCOL_BINARY_CMD_SETQ:
2190            len = storage_command(command.bytes, sizeof(command.bytes), cmd,
2191                                  key, keylen , &value, sizeof(value),
2192                                  0, 0);
2193            break;
2194        case PROTOCOL_BINARY_CMD_APPEND:
2195        case PROTOCOL_BINARY_CMD_APPENDQ:
2196        case PROTOCOL_BINARY_CMD_PREPEND:
2197        case PROTOCOL_BINARY_CMD_PREPENDQ:
2198            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
2199                              key, keylen, &value, sizeof(value));
2200            break;
2201        case PROTOCOL_BINARY_CMD_FLUSH:
2202        case PROTOCOL_BINARY_CMD_FLUSHQ:
2203            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
2204                              NULL, 0, NULL, 0);
2205            break;
2206        case PROTOCOL_BINARY_CMD_NOOP:
2207            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
2208                              NULL, 0, NULL, 0);
2209            break;
2210        case PROTOCOL_BINARY_CMD_DELETE:
2211        case PROTOCOL_BINARY_CMD_DELETEQ:
2212            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
2213                             key, keylen, NULL, 0);
2214            break;
2215        case PROTOCOL_BINARY_CMD_DECREMENT:
2216        case PROTOCOL_BINARY_CMD_DECREMENTQ:
2217        case PROTOCOL_BINARY_CMD_INCREMENT:
2218        case PROTOCOL_BINARY_CMD_INCREMENTQ:
2219            len = arithmetic_command(command.bytes, sizeof(command.bytes), cmd,
2220                                     key, keylen, 1, 0, 0);
2221            break;
2222        case PROTOCOL_BINARY_CMD_VERSION:
2223            len = raw_command(command.bytes, sizeof(command.bytes),
2224                             PROTOCOL_BINARY_CMD_VERSION,
2225                             NULL, 0, NULL, 0);
2226            break;
2227        case PROTOCOL_BINARY_CMD_GET:
2228        case PROTOCOL_BINARY_CMD_GETK:
2229        case PROTOCOL_BINARY_CMD_GETKQ:
2230        case PROTOCOL_BINARY_CMD_GETQ:
2231            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
2232                             key, keylen, NULL, 0);
2233            break;
2234
2235        case PROTOCOL_BINARY_CMD_STAT:
2236            len = raw_command(command.bytes, sizeof(command.bytes),
2237                              PROTOCOL_BINARY_CMD_STAT,
2238                              NULL, 0, NULL, 0);
2239            break;
2240
2241        default:
2242            /* don't run commands we don't know */
2243            continue;
2244        }
2245
2246        if ((len + offset) < buffersize) {
2247            memcpy(((char*)buffer) + offset, command.bytes, len);
2248            offset += (off_t)len;
2249        } else {
2250            break;
2251        }
2252    }
2253    safe_send(buffer, offset, true);
2254
2255    return TEST_PASS;
2256}
2257
2258static enum test_return test_binary_pipeline_hickup(void)
2259{
2260    size_t buffersize = 65 * 1024;
2261    void *buffer = malloc(buffersize);
2262    int ii;
2263    cb_thread_t tid;
2264    int ret;
2265    size_t len;
2266
2267    allow_closed_read = true;
2268    hickup_thread_running = true;
2269    if ((ret = cb_create_thread(&tid, binary_hickup_recv_verification_thread, NULL, 0)) != 0) {
2270        fprintf(stderr, "Can't create thread: %s\n", strerror(ret));
2271        free(buffer);
2272        return TEST_FAIL;
2273    }
2274
2275    /* Allow the thread to start */
2276#ifdef WIN32
2277    Sleep(1);
2278#else
2279    usleep(250);
2280#endif
2281
2282    srand((int)time(NULL));
2283    for (ii = 0; ii < 2; ++ii) {
2284        test_binary_pipeline_hickup_chunk(buffer, buffersize);
2285    }
2286
2287    /* send quitq to shut down the read thread ;-) */
2288    len = raw_command(buffer, buffersize, PROTOCOL_BINARY_CMD_QUITQ,
2289                      NULL, 0, NULL, 0);
2290    safe_send(buffer, len, false);
2291
2292    cb_join_thread(tid);
2293    free(buffer);
2294
2295    reconnect_to_server("127.0.0.1", false);
2296    return TEST_PASS;
2297}
2298
2299static enum test_return test_binary_ioctl(void) {
2300    union {
2301        protocol_binary_request_no_extras request;
2302        protocol_binary_response_no_extras response;
2303        char bytes[1024];
2304    } buffer;
2305
2306    /* NULL key is invalid. */
2307    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2308                             PROTOCOL_BINARY_CMD_IOCTL_SET, NULL, 0, NULL, 0);
2309
2310    safe_send(buffer.bytes, len, false);
2311    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2312    validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_IOCTL_SET,
2313                             PROTOCOL_BINARY_RESPONSE_EINVAL);
2314
2315    /* release_free_memory always returns OK, regardless of how much was freed.*/
2316    {
2317        char cmd[] = "release_free_memory";
2318        len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2319                          PROTOCOL_BINARY_CMD_IOCTL_SET, cmd, strlen(cmd),
2320                          NULL, 0);
2321
2322        safe_send(buffer.bytes, len, false);
2323        safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2324        validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_IOCTL_SET,
2325                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
2326    }
2327
2328    return TEST_PASS;
2329}
2330
2331static enum test_return test_binary_verbosity(void) {
2332    union {
2333        protocol_binary_request_verbosity request;
2334        protocol_binary_response_no_extras response;
2335        char bytes[1024];
2336    } buffer;
2337
2338    int ii;
2339    for (ii = 10; ii > -1; --ii) {
2340        size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2341                                 PROTOCOL_BINARY_CMD_VERBOSITY,
2342                                 NULL, 0, NULL, 0);
2343        buffer.request.message.header.request.extlen = 4;
2344        buffer.request.message.header.request.bodylen = ntohl(4);
2345        buffer.request.message.body.level = (uint32_t)ntohl(ii);
2346        safe_send(buffer.bytes, len + sizeof(4), false);
2347        safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2348        validate_response_header(&buffer.response,
2349                                 PROTOCOL_BINARY_CMD_VERBOSITY,
2350                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
2351    }
2352
2353    return TEST_PASS;
2354}
2355
2356static enum test_return validate_object(const char *key, const char *value) {
2357    union {
2358        protocol_binary_request_no_extras request;
2359        protocol_binary_response_no_extras response;
2360        char bytes[1024];
2361    } send, receive;
2362    char *ptr;
2363    size_t len = raw_command(send.bytes, sizeof(send.bytes),
2364                             PROTOCOL_BINARY_CMD_GET,
2365                             key, strlen(key), NULL, 0);
2366    safe_send(send.bytes, len, false);
2367    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2368    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
2369                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2370    cb_assert(receive.response.message.header.response.bodylen - 4 == strlen(value));
2371    ptr = receive.bytes + sizeof(receive.response) + 4;
2372    cb_assert(memcmp(value, ptr, strlen(value)) == 0);
2373
2374    return TEST_PASS;
2375}
2376
2377static enum test_return store_object(const char *key, char *value) {
2378    union {
2379        protocol_binary_request_no_extras request;
2380        protocol_binary_response_no_extras response;
2381        char bytes[1024];
2382    } send, receive;
2383    size_t len = storage_command(send.bytes, sizeof(send.bytes),
2384                                 PROTOCOL_BINARY_CMD_SET,
2385                                 key, strlen(key), value, strlen(value),
2386                                 0, 0);
2387
2388    safe_send(send.bytes, len, false);
2389    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2390    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
2391                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2392
2393    validate_object(key, value);
2394    return TEST_PASS;
2395}
2396
2397static enum test_return test_binary_read(void) {
2398    union {
2399        protocol_binary_request_read request;
2400        protocol_binary_response_read response;
2401        char bytes[1024];
2402    } buffer;
2403    size_t len;
2404    char *ptr;
2405
2406    store_object("hello", "world");
2407
2408    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2409                      read_command, "hello",
2410                      strlen("hello"), NULL, 0);
2411    buffer.request.message.body.offset = htonl(1);
2412    buffer.request.message.body.length = htonl(3);
2413
2414    safe_send(buffer.bytes, len, false);
2415    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2416    validate_response_header(&buffer.response, read_command,
2417                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2418    cb_assert(buffer.response.message.header.response.bodylen == 3);
2419    ptr = buffer.bytes + sizeof(buffer.response);
2420    cb_assert(memcmp(ptr, "orl", 3) == 0);
2421
2422
2423    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2424                      read_command, "hello",
2425                      strlen("hello"), NULL, 0);
2426    buffer.request.message.body.offset = htonl(7);
2427    buffer.request.message.body.length = htonl(2);
2428    safe_send(buffer.bytes, len, false);
2429    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2430    validate_response_header(&buffer.response, read_command,
2431                             PROTOCOL_BINARY_RESPONSE_ERANGE);
2432
2433    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2434                      read_command, "myhello",
2435                      strlen("myhello"), NULL, 0);
2436    buffer.request.message.body.offset = htonl(0);
2437    buffer.request.message.body.length = htonl(5);
2438
2439    safe_send(buffer.bytes, len, false);
2440    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2441    validate_response_header(&buffer.response, read_command,
2442                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
2443    return TEST_PASS;
2444}
2445
2446static enum test_return test_binary_write(void) {
2447    union {
2448        protocol_binary_request_read request;
2449        protocol_binary_response_read response;
2450        char bytes[1024];
2451    } buffer;
2452    size_t len;
2453
2454    store_object("hello", "world");
2455
2456    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2457                             write_command, "hello",
2458                             strlen("hello"), "bubba", 5);
2459    buffer.request.message.body.offset = htonl(0);
2460    buffer.request.message.body.length = htonl(5);
2461
2462    safe_send(buffer.bytes, len, false);
2463    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2464    validate_response_header(&buffer.response, write_command,
2465                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2466    validate_object("hello", "bubba");
2467
2468    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2469                             write_command, "hello",
2470                             strlen("hello"), "zz", 2);
2471    buffer.request.message.body.offset = htonl(2);
2472    buffer.request.message.body.length = htonl(2);
2473
2474    safe_send(buffer.bytes, len, false);
2475    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2476    validate_response_header(&buffer.response, write_command,
2477                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2478    validate_object("hello", "buzza");
2479
2480    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2481                             write_command, "hello",
2482                             strlen("hello"), "zz", 2);
2483    buffer.request.message.body.offset = htonl(7);
2484    buffer.request.message.body.length = htonl(2);
2485
2486    safe_send(buffer.bytes, len, false);
2487    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2488    validate_response_header(&buffer.response, write_command,
2489                             PROTOCOL_BINARY_RESPONSE_ERANGE);
2490
2491    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2492                             write_command, "hello",
2493                             strlen("hello"), "bb", 2);
2494    buffer.request.message.body.offset = htonl(2);
2495    buffer.request.message.body.length = htonl(2);
2496    buffer.request.message.header.request.cas = 1;
2497
2498    safe_send(buffer.bytes, len, false);
2499    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2500    validate_response_header(&buffer.response, write_command,
2501                             PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
2502
2503    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2504                      write_command, "myhello",
2505                      strlen("myhello"), "bubba", 5);
2506    buffer.request.message.body.offset = htonl(0);
2507    buffer.request.message.body.length = htonl(5);
2508
2509    safe_send(buffer.bytes, len, false);
2510    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2511    validate_response_header(&buffer.response, write_command,
2512                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
2513    return TEST_PASS;
2514}
2515
2516static enum test_return test_binary_bad_tap_ttl(void) {
2517    union {
2518        protocol_binary_request_tap_flush request;
2519        protocol_binary_response_no_extras response;
2520        char bytes[1024];
2521    } buffer;
2522
2523    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2524                             PROTOCOL_BINARY_CMD_TAP_FLUSH,
2525                             NULL, 0, NULL, 0);
2526
2527    buffer.request.message.header.request.extlen = 8;
2528    buffer.request.message.header.request.bodylen = ntohl(8);
2529    buffer.request.message.body.tap.enginespecific_length = 0;
2530    buffer.request.message.body.tap.flags = 0;
2531    buffer.request.message.body.tap.ttl = 0;
2532    buffer.request.message.body.tap.res1 = 0;
2533    buffer.request.message.body.tap.res2 = 0;
2534    buffer.request.message.body.tap.res3 = 0;
2535    len += 8;
2536
2537    safe_send(buffer.bytes, len, false);
2538    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2539    validate_response_header(&buffer.response,
2540                             PROTOCOL_BINARY_CMD_TAP_FLUSH,
2541                             PROTOCOL_BINARY_RESPONSE_EINVAL);
2542    return TEST_PASS;
2543}
2544
2545static enum test_return test_binary_hello(void) {
2546    union {
2547        protocol_binary_request_hello request;
2548        protocol_binary_response_hello response;
2549        char bytes[1024];
2550    } buffer;
2551    const char *useragent = "hello world";
2552    uint16_t feature = htons(PROTOCOL_BINARY_FEATURE_DATATYPE);
2553    uint16_t *ptr;
2554    size_t len;
2555
2556    memset(buffer.bytes, 0, sizeof(buffer.bytes));
2557
2558    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2559                      PROTOCOL_BINARY_CMD_HELLO,
2560                      useragent, strlen(useragent), &feature,
2561                      sizeof(feature));
2562
2563    safe_send(buffer.bytes, len, false);
2564    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2565    validate_response_header(&buffer.response,
2566                             PROTOCOL_BINARY_CMD_HELLO,
2567                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2568
2569    cb_assert(buffer.response.message.header.response.bodylen == 2);
2570    ptr = (uint16_t*)(buffer.bytes + sizeof(buffer.response));
2571    cb_assert(ntohs(*ptr) == PROTOCOL_BINARY_FEATURE_DATATYPE);
2572
2573    feature = 0xffff;
2574    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2575                             PROTOCOL_BINARY_CMD_HELLO,
2576                             useragent, strlen(useragent), &feature,
2577                             sizeof(feature));
2578
2579    safe_send(buffer.bytes, len, false);
2580    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2581    validate_response_header(&buffer.response,
2582                             PROTOCOL_BINARY_CMD_HELLO,
2583                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2584    cb_assert(buffer.response.message.header.response.bodylen == 0);
2585
2586
2587    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2588                             PROTOCOL_BINARY_CMD_HELLO,
2589                             useragent, strlen(useragent), &feature,
2590                             sizeof(feature) - 1);
2591
2592    safe_send(buffer.bytes, len, false);
2593    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2594    validate_response_header(&buffer.response,
2595                             PROTOCOL_BINARY_CMD_HELLO,
2596                             PROTOCOL_BINARY_RESPONSE_EINVAL);
2597
2598    return TEST_PASS;
2599}
2600
2601static void set_datatype_feature(bool enable) {
2602    union {
2603        protocol_binary_request_hello request;
2604        protocol_binary_response_hello response;
2605        char bytes[1024];
2606    } buffer;
2607    const char *useragent = "testapp";
2608    uint16_t feature = htons(PROTOCOL_BINARY_FEATURE_DATATYPE);
2609    size_t len = strlen(useragent);
2610
2611    memset(buffer.bytes, 0, sizeof(buffer));
2612    buffer.request.message.header.request.magic = PROTOCOL_BINARY_REQ;
2613    buffer.request.message.header.request.opcode = PROTOCOL_BINARY_CMD_HELLO;
2614    buffer.request.message.header.request.keylen = htons((uint16_t)len);
2615    if (enable) {
2616        buffer.request.message.header.request.bodylen = htonl((uint32_t)len + 2);
2617    } else {
2618        buffer.request.message.header.request.bodylen = htonl((uint32_t)len);
2619    }
2620    memcpy(buffer.bytes + 24, useragent, len);
2621    memcpy(buffer.bytes + 24 + len, &feature, 2);
2622
2623    safe_send(buffer.bytes,
2624              sizeof(buffer.request) + ntohl(buffer.request.message.header.request.bodylen), false);
2625
2626    safe_recv(&buffer.response, sizeof(buffer.response));
2627    len = ntohl(buffer.response.message.header.response.bodylen);
2628    if (enable) {
2629        cb_assert(len == 2);
2630        safe_recv(&feature, sizeof(feature));
2631        cb_assert(feature == htons(PROTOCOL_BINARY_FEATURE_DATATYPE));
2632    } else {
2633        cb_assert(len == 0);
2634    }
2635}
2636
2637static void store_object_w_datatype(const char *key,
2638                                    const void *data, size_t datalen,
2639                                    bool deflate, bool json)
2640{
2641    protocol_binary_request_no_extras request;
2642    int keylen = (int)strlen(key);
2643    char extra[8] = { 0 };
2644    uint8_t datatype = PROTOCOL_BINARY_RAW_BYTES;
2645    if (deflate) {
2646        datatype |= PROTOCOL_BINARY_DATATYPE_COMPRESSED;
2647    }
2648
2649    if (json) {
2650        datatype |= PROTOCOL_BINARY_DATATYPE_JSON;
2651    }
2652
2653    memset(request.bytes, 0, sizeof(request));
2654    request.message.header.request.magic = PROTOCOL_BINARY_REQ;
2655    request.message.header.request.opcode = PROTOCOL_BINARY_CMD_SETQ;
2656    request.message.header.request.datatype = datatype;
2657    request.message.header.request.extlen = 8;
2658    request.message.header.request.keylen = htons((uint16_t)keylen);
2659    request.message.header.request.bodylen = htonl((uint32_t)(keylen + datalen + 8));
2660
2661    safe_send(&request.bytes, sizeof(request.bytes), false);
2662    safe_send(extra, sizeof(extra), false);
2663    safe_send(key, strlen(key), false);
2664    safe_send(data, datalen, false);
2665}
2666
2667static void get_object_w_datatype(const char *key,
2668                                  const void *data, size_t datalen,
2669                                  bool deflate, bool json,
2670                                  bool conversion)
2671{
2672    protocol_binary_response_no_extras response;
2673    protocol_binary_request_no_extras request;
2674    char *body;
2675    int keylen = (int)strlen(key);
2676    uint32_t flags;
2677    uint8_t datatype = PROTOCOL_BINARY_RAW_BYTES;
2678    uint32_t len;
2679
2680    if (deflate) {
2681        datatype |= PROTOCOL_BINARY_DATATYPE_COMPRESSED;
2682    }
2683
2684    if (json) {
2685        datatype |= PROTOCOL_BINARY_DATATYPE_JSON;
2686    }
2687
2688    memset(request.bytes, 0, sizeof(request));
2689    request.message.header.request.magic = PROTOCOL_BINARY_REQ;
2690    request.message.header.request.opcode = PROTOCOL_BINARY_CMD_GET;
2691    request.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
2692    request.message.header.request.keylen = htons((uint16_t)keylen);
2693    request.message.header.request.bodylen = htonl(keylen);
2694
2695    safe_send(&request.bytes, sizeof(request.bytes), false);
2696    safe_send(key, strlen(key), false);
2697
2698    safe_recv(&response.bytes, sizeof(response.bytes));
2699    if (ntohs(response.message.header.response.status != PROTOCOL_BINARY_RESPONSE_SUCCESS)) {
2700        fprintf(stderr, "Failed to retrieve object!: %d\n",
2701                (int)ntohs(response.message.header.response.status));
2702        abort();
2703    }
2704
2705    len = ntohl(response.message.header.response.bodylen);
2706    cb_assert(len > 4);
2707    safe_recv(&flags, sizeof(flags));
2708    len -= 4;
2709    cb_assert((body = malloc(len)) != NULL);
2710    safe_recv(body, len);
2711
2712    if (conversion) {
2713        cb_assert(response.message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
2714    } else {
2715        cb_assert(response.message.header.response.datatype == datatype);
2716    }
2717
2718    cb_assert(len == datalen);
2719    cb_assert(memcmp(data, body, len) == 0);
2720    free(body);
2721}
2722
2723static enum test_return test_binary_datatype_json(void) {
2724    const char body[] = "{ \"value\" : 1234123412 }";
2725    set_datatype_feature(true);
2726    store_object_w_datatype("myjson", body, strlen(body), false, true);
2727
2728    get_object_w_datatype("myjson", body, strlen(body), false, true, false);
2729
2730    set_datatype_feature(false);
2731    get_object_w_datatype("myjson", body, strlen(body), false, true, true);
2732
2733    return TEST_PASS;
2734}
2735
2736static enum test_return test_binary_datatype_json_without_support(void) {
2737    const char body[] = "{ \"value\" : 1234123412 }";
2738    set_datatype_feature(false);
2739    store_object_w_datatype("myjson", body, strlen(body), false, false);
2740
2741    get_object_w_datatype("myjson", body, strlen(body), false, false, false);
2742
2743    set_datatype_feature(true);
2744    get_object_w_datatype("myjson", body, strlen(body), false, true, false);
2745
2746    return TEST_PASS;
2747}
2748
2749static enum test_return test_binary_datatype_compressed(void) {
2750    const char inflated[] = "aaaaaaaaabbbbbbbccccccdddddd";
2751    size_t inflated_len = strlen(inflated);
2752    char deflated[256];
2753    size_t deflated_len = 256;
2754    snappy_status status;
2755
2756    status = snappy_compress(inflated, inflated_len,
2757                             deflated, &deflated_len);
2758
2759    if (status != SNAPPY_OK) {
2760        fprintf(stderr, "Failed to compress data\n");
2761        abort();
2762    }
2763
2764    set_datatype_feature(true);
2765    store_object_w_datatype("mycompressed", deflated, deflated_len,
2766                            true, false);
2767
2768    get_object_w_datatype("mycompressed", deflated, deflated_len,
2769                          true, false, false);
2770
2771    set_datatype_feature(false);
2772    get_object_w_datatype("mycompressed", inflated, inflated_len,
2773                          true, false, true);
2774
2775    return TEST_PASS;
2776}
2777
2778static enum test_return test_binary_datatype_compressed_json(void) {
2779    const char inflated[] = "{ \"value\" : \"aaaaaaaaabbbbbbbccccccdddddd\" }";
2780    size_t inflated_len = strlen(inflated);
2781    char deflated[256];
2782    size_t deflated_len = 256;
2783    snappy_status status;
2784
2785    status = snappy_compress(inflated, inflated_len,
2786                             deflated, &deflated_len);
2787
2788    if (status != SNAPPY_OK) {
2789        fprintf(stderr, "Failed to compress data\n");
2790        abort();
2791    }
2792
2793    set_datatype_feature(true);
2794    store_object_w_datatype("mycompressedjson", deflated, deflated_len,
2795                            true, true);
2796
2797    get_object_w_datatype("mycompressedjson", deflated, deflated_len,
2798                          true, true, false);
2799
2800    set_datatype_feature(false);
2801    get_object_w_datatype("mycompressedjson", inflated, inflated_len,
2802                          true, true, true);
2803
2804    return TEST_PASS;
2805}
2806
2807static enum test_return test_binary_invalid_datatype(void) {
2808    protocol_binary_request_no_extras request;
2809    union {
2810        protocol_binary_response_no_extras response;
2811        char buffer[1024];
2812    } res;
2813    uint16_t code;
2814
2815    set_datatype_feature(false);
2816
2817    memset(request.bytes, 0, sizeof(request));
2818    request.message.header.request.magic = PROTOCOL_BINARY_REQ;
2819    request.message.header.request.opcode = PROTOCOL_BINARY_CMD_NOOP;
2820    request.message.header.request.datatype = 1;
2821
2822    safe_send(&request.bytes, sizeof(request.bytes), false);
2823    safe_recv_packet(res.buffer, sizeof(res.buffer));
2824
2825    code = res.response.message.header.response.status;
2826    cb_assert(code == PROTOCOL_BINARY_RESPONSE_EINVAL);
2827
2828    reconnect_to_server("127.0.0.1", false);
2829
2830    set_datatype_feature(false);
2831    request.message.header.request.datatype = 4;
2832    safe_send(&request.bytes, sizeof(request.bytes), false);
2833    safe_recv_packet(res.buffer, sizeof(res.buffer));
2834    code = res.response.message.header.response.status;
2835    cb_assert(code == PROTOCOL_BINARY_RESPONSE_EINVAL);
2836
2837    reconnect_to_server("127.0.0.1", false);
2838
2839    return TEST_PASS;
2840}
2841
2842static uint64_t get_session_ctrl_token(void) {
2843    union {
2844        protocol_binary_request_get_ctrl_token request;
2845        protocol_binary_response_get_ctrl_token response;
2846        char bytes[1024];
2847    } buffer;
2848    uint64_t ret;
2849
2850    memset(buffer.bytes, 0, sizeof(buffer));
2851    buffer.request.message.header.request.magic = PROTOCOL_BINARY_REQ;
2852    buffer.request.message.header.request.opcode = PROTOCOL_BINARY_CMD_GET_CTRL_TOKEN;
2853
2854    safe_send(buffer.bytes, sizeof(buffer.request), false);
2855    safe_recv_packet(&buffer.response, sizeof(buffer.bytes));
2856
2857    cb_assert(htons(buffer.response.message.header.response.status) ==
2858                PROTOCOL_BINARY_RESPONSE_SUCCESS);
2859
2860    ret = ntohll(buffer.response.message.header.response.cas);
2861    cb_assert(ret != 0);
2862
2863    return ret;
2864}
2865
2866static void prepare_set_session_ctrl_token(protocol_binary_request_set_ctrl_token *req,
2867                                           uint64_t old, uint64_t new)
2868{
2869    memset(req, 0, sizeof(*req));
2870    req->message.header.request.magic = PROTOCOL_BINARY_REQ;
2871    req->message.header.request.opcode = PROTOCOL_BINARY_CMD_SET_CTRL_TOKEN;
2872    req->message.header.request.extlen = sizeof(uint64_t);
2873    req->message.header.request.bodylen = htonl(sizeof(uint64_t));
2874    req->message.header.request.cas = htonll(old);
2875    req->message.body.new_cas = htonll(new);
2876}
2877
2878static enum test_return test_session_ctrl_token(void) {
2879    union {
2880        protocol_binary_request_set_ctrl_token request;
2881        protocol_binary_response_set_ctrl_token response;
2882        char bytes[1024];
2883    } buffer;
2884
2885    uint64_t old_token = get_session_ctrl_token();
2886    uint64_t new_token = 0x0102030405060708;
2887
2888    /* Validate that you may successfully set the token to a legal value */
2889    prepare_set_session_ctrl_token(&buffer.request, old_token, new_token);
2890    safe_send(buffer.bytes, sizeof(buffer.request), false);
2891    cb_assert(safe_recv_packet(&buffer.response, sizeof(buffer.bytes)));
2892
2893    cb_assert(buffer.response.message.header.response.status ==
2894              PROTOCOL_BINARY_RESPONSE_SUCCESS);
2895    cb_assert(new_token == ntohll(buffer.response.message.header.response.cas));
2896    old_token = new_token;
2897
2898    /* Validate that you can't set it to 0 */
2899    prepare_set_session_ctrl_token(&buffer.request, old_token, 0);
2900    safe_send(buffer.bytes, sizeof(buffer.request), false);
2901    cb_assert(safe_recv_packet(&buffer.response, sizeof(buffer.bytes)));
2902    cb_assert(buffer.response.message.header.response.status ==
2903              PROTOCOL_BINARY_RESPONSE_EINVAL);
2904    cb_assert(old_token == get_session_ctrl_token());
2905
2906    /* Validate that you can't set it by providing an incorrect cas */
2907    prepare_set_session_ctrl_token(&buffer.request, old_token + 1, new_token - 1);
2908    safe_send(buffer.bytes, sizeof(buffer.request), false);
2909    cb_assert(safe_recv_packet(&buffer.response, sizeof(buffer.bytes)));
2910
2911    cb_assert(buffer.response.message.header.response.status ==
2912              PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
2913    cb_assert(new_token == ntohll(buffer.response.message.header.response.cas));
2914    cb_assert(new_token == get_session_ctrl_token());
2915
2916    /* Validate that you may set it by overriding the cas with 0 */
2917    prepare_set_session_ctrl_token(&buffer.request, 0, 0xdeadbeef);
2918    safe_send(buffer.bytes, sizeof(buffer.request), false);
2919    cb_assert(safe_recv_packet(&buffer.response, sizeof(buffer.bytes)));
2920    cb_assert(buffer.response.message.header.response.status ==
2921              PROTOCOL_BINARY_RESPONSE_SUCCESS);
2922    cb_assert(0xdeadbeef == ntohll(buffer.response.message.header.response.cas));
2923    cb_assert(0xdeadbeef == get_session_ctrl_token());
2924
2925    return TEST_PASS;
2926}
2927
2928static enum test_return test_mb_10114(void) {
2929    char buffer[512];
2930    const char *key = "mb-10114";
2931    union {
2932        protocol_binary_request_no_extras request&#