xref: /3.0.2-MP2/memcached/tests/testapp.c (revision 91febbbe)
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;
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        rv = send(sock_ssl, send_buf, (int)send_len, 0);
1004#else
1005        rv = send(sock_ssl, send_buf, send_len, 0);
1006#endif
1007        (void)BIO_reset(ssl_bio_w);
1008    } else {
1009#ifdef WIN32
1010        rv = send(sock, buf, (int)len, 0);
1011#else
1012        rv = send(sock, buf, len, 0);
1013#endif
1014    }
1015    return rv;
1016}
1017
1018static ssize_t phase_recv(void *buf, size_t len) {
1019
1020    ssize_t rv = 0;
1021    if (current_phase == phase_ssl) {
1022        /* can we read some data? */
1023        while((rv = SSL_peek(ssl, buf, len)) == -1)
1024        {
1025            /* nope, keep feeding SSL until we can */
1026#ifdef WIN32
1027            rv = recv(sock_ssl, buf, (int)len, 0);
1028#else
1029            rv = recv(sock_ssl, buf, len, 0);
1030#endif
1031
1032            if(rv > 0) {
1033                /* write into the BIO what came off the network */
1034                BIO_write(ssl_bio_r, buf, rv);
1035            } else if(rv == 0) {
1036                return rv; /* peer closed */
1037            }
1038        }
1039        /* now pull the data out and return */
1040        rv = SSL_read(ssl, buf, len);
1041    }
1042    else {
1043#ifdef WIN32
1044        rv = recv(sock, buf, (int)len, 0);
1045#else
1046        rv = recv(sock, buf, len, 0);
1047#endif
1048    }
1049    return rv;
1050}
1051
1052char ssl_error_string[256];
1053int ssl_error_string_len = 256;
1054
1055static char* phase_get_errno() {
1056    char * rv = 0;
1057    if (current_phase == phase_ssl) {
1058        /* could do with more work here, but so far this has sufficed */
1059        snprintf(ssl_error_string, ssl_error_string_len, "SSL error\n");
1060        rv = ssl_error_string;
1061    } else {
1062        rv = strerror(errno);
1063    }
1064    return rv;
1065}
1066
1067static void safe_send(const void* buf, size_t len, bool hickup)
1068{
1069    off_t offset = 0;
1070    const char* ptr = buf;
1071    do {
1072        size_t num_bytes = len - offset;
1073        ssize_t nw;
1074        if (hickup) {
1075            if (num_bytes > 1024) {
1076                num_bytes = (rand() % 1023) + 1;
1077            }
1078        }
1079
1080        nw = phase_send(ptr + offset, num_bytes);
1081
1082        if (nw == -1) {
1083            if (errno != EINTR) {
1084                fprintf(stderr, "Failed to write: %s\n", phase_get_errno());
1085                abort();
1086            }
1087        } else {
1088            if (hickup) {
1089#ifndef WIN32
1090                usleep(100);
1091#endif
1092            }
1093            offset += nw;
1094        }
1095    } while (offset < len);
1096}
1097
1098static bool safe_recv(void *buf, size_t len) {
1099    off_t offset = 0;
1100    if (len == 0) {
1101        return true;
1102    }
1103    do {
1104
1105        ssize_t nr = phase_recv(((char*)buf) + offset, len - offset);
1106
1107        if (nr == -1) {
1108            if (errno != EINTR) {
1109                fprintf(stderr, "Failed to read: %s\n", phase_get_errno());
1110                abort();
1111            }
1112        } else {
1113            if (nr == 0 && allow_closed_read) {
1114                return false;
1115            }
1116            cb_assert(nr != 0);
1117            offset += nr;
1118        }
1119    } while (offset < len);
1120
1121    return true;
1122}
1123
1124static bool safe_recv_packet(void *buf, size_t size) {
1125    protocol_binary_response_no_extras *response = buf;
1126    char *ptr;
1127    size_t len;
1128
1129    cb_assert(size >= sizeof(*response));
1130    if (!safe_recv(response, sizeof(*response))) {
1131        return false;
1132    }
1133    response->message.header.response.keylen = ntohs(response->message.header.response.keylen);
1134    response->message.header.response.status = ntohs(response->message.header.response.status);
1135    response->message.header.response.bodylen = ntohl(response->message.header.response.bodylen);
1136
1137    len = sizeof(*response);
1138    ptr = buf;
1139    ptr += len;
1140    cb_assert(size >= (sizeof(*response) + response->message.header.response.bodylen));
1141    if (!safe_recv(ptr, response->message.header.response.bodylen)) {
1142        return false;
1143    }
1144
1145    return true;
1146}
1147
1148static off_t storage_command(char*buf,
1149                             size_t bufsz,
1150                             uint8_t cmd,
1151                             const void* key,
1152                             size_t keylen,
1153                             const void* dta,
1154                             size_t dtalen,
1155                             uint32_t flags,
1156                             uint32_t exp) {
1157    /* all of the storage commands use the same command layout */
1158    off_t key_offset;
1159    protocol_binary_request_set *request = (void*)buf;
1160    cb_assert(bufsz >= sizeof(*request) + keylen + dtalen);
1161
1162    memset(request, 0, sizeof(*request));
1163    request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1164    request->message.header.request.opcode = cmd;
1165    request->message.header.request.keylen = htons((uint16_t)keylen);
1166    request->message.header.request.extlen = 8;
1167    request->message.header.request.bodylen = htonl((uint32_t)(keylen + 8 + dtalen));
1168    request->message.header.request.opaque = 0xdeadbeef;
1169    request->message.body.flags = htonl(flags);
1170    request->message.body.expiration = htonl(exp);
1171
1172    key_offset = sizeof(protocol_binary_request_no_extras) + 8;
1173
1174    memcpy(buf + key_offset, key, keylen);
1175    if (dta != NULL) {
1176        memcpy(buf + key_offset + keylen, dta, dtalen);
1177    }
1178
1179    return (off_t)(key_offset + keylen + dtalen);
1180}
1181
1182static off_t raw_command(char* buf,
1183                         size_t bufsz,
1184                         uint8_t cmd,
1185                         const void* key,
1186                         size_t keylen,
1187                         const void* dta,
1188                         size_t dtalen) {
1189    /* all of the storage commands use the same command layout */
1190    off_t key_offset;
1191    protocol_binary_request_no_extras *request = (void*)buf;
1192    cb_assert(bufsz >= sizeof(*request) + keylen + dtalen);
1193
1194    memset(request, 0, sizeof(*request));
1195    if (cmd == read_command || cmd == write_command) {
1196        request->message.header.request.extlen = 8;
1197    }
1198    request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1199    request->message.header.request.opcode = cmd;
1200    request->message.header.request.keylen = htons((uint16_t)keylen);
1201    request->message.header.request.bodylen = htonl((uint32_t)(keylen + dtalen + request->message.header.request.extlen));
1202    request->message.header.request.opaque = 0xdeadbeef;
1203
1204    key_offset = sizeof(protocol_binary_request_no_extras) +
1205        request->message.header.request.extlen;
1206
1207    if (key != NULL) {
1208        memcpy(buf + key_offset, key, keylen);
1209    }
1210    if (dta != NULL) {
1211        memcpy(buf + key_offset + keylen, dta, dtalen);
1212    }
1213
1214    return (off_t)(sizeof(*request) + keylen + dtalen + request->message.header.request.extlen);
1215}
1216
1217static off_t flush_command(char* buf, size_t bufsz, uint8_t cmd, uint32_t exptime, bool use_extra) {
1218    off_t size;
1219    protocol_binary_request_flush *request = (void*)buf;
1220    cb_assert(bufsz > sizeof(*request));
1221
1222    memset(request, 0, sizeof(*request));
1223    request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1224    request->message.header.request.opcode = cmd;
1225
1226    size = sizeof(protocol_binary_request_no_extras);
1227    if (use_extra) {
1228        request->message.header.request.extlen = 4;
1229        request->message.body.expiration = htonl(exptime);
1230        request->message.header.request.bodylen = htonl(4);
1231        size += 4;
1232    }
1233
1234    request->message.header.request.opaque = 0xdeadbeef;
1235
1236    return size;
1237}
1238
1239static off_t arithmetic_command(char* buf,
1240                                size_t bufsz,
1241                                uint8_t cmd,
1242                                const void* key,
1243                                size_t keylen,
1244                                uint64_t delta,
1245                                uint64_t initial,
1246                                uint32_t exp) {
1247    off_t key_offset;
1248    protocol_binary_request_incr *request = (void*)buf;
1249    cb_assert(bufsz > sizeof(*request) + keylen);
1250
1251    memset(request, 0, sizeof(*request));
1252    request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1253    request->message.header.request.opcode = cmd;
1254    request->message.header.request.keylen = htons((uint16_t)keylen);
1255    request->message.header.request.extlen = 20;
1256    request->message.header.request.bodylen = htonl((uint32_t)(keylen + 20));
1257    request->message.header.request.opaque = 0xdeadbeef;
1258    request->message.body.delta = htonll(delta);
1259    request->message.body.initial = htonll(initial);
1260    request->message.body.expiration = htonl(exp);
1261
1262    key_offset = sizeof(protocol_binary_request_no_extras) + 20;
1263
1264    memcpy(buf + key_offset, key, keylen);
1265    return (off_t)(key_offset + keylen);
1266}
1267
1268static void validate_response_header(protocol_binary_response_no_extras *response,
1269                                     uint8_t cmd, uint16_t status)
1270{
1271    cb_assert(response->message.header.response.magic == PROTOCOL_BINARY_RES);
1272    cb_assert(response->message.header.response.opcode == cmd);
1273    cb_assert(response->message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
1274    if (status == PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND) {
1275        if (response->message.header.response.status == PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED) {
1276            response->message.header.response.status = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
1277        }
1278    }
1279    cb_assert(response->message.header.response.status == status);
1280    cb_assert(response->message.header.response.opaque == 0xdeadbeef);
1281
1282    if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
1283        switch (cmd) {
1284        case PROTOCOL_BINARY_CMD_ADDQ:
1285        case PROTOCOL_BINARY_CMD_APPENDQ:
1286        case PROTOCOL_BINARY_CMD_DECREMENTQ:
1287        case PROTOCOL_BINARY_CMD_DELETEQ:
1288        case PROTOCOL_BINARY_CMD_FLUSHQ:
1289        case PROTOCOL_BINARY_CMD_INCREMENTQ:
1290        case PROTOCOL_BINARY_CMD_PREPENDQ:
1291        case PROTOCOL_BINARY_CMD_QUITQ:
1292        case PROTOCOL_BINARY_CMD_REPLACEQ:
1293        case PROTOCOL_BINARY_CMD_SETQ:
1294            cb_assert("Quiet command shouldn't return on success" == NULL);
1295        default:
1296            break;
1297        }
1298
1299        switch (cmd) {
1300        case PROTOCOL_BINARY_CMD_ADD:
1301        case PROTOCOL_BINARY_CMD_REPLACE:
1302        case PROTOCOL_BINARY_CMD_SET:
1303        case PROTOCOL_BINARY_CMD_APPEND:
1304        case PROTOCOL_BINARY_CMD_PREPEND:
1305            cb_assert(response->message.header.response.keylen == 0);
1306            cb_assert(response->message.header.response.extlen == 0);
1307            cb_assert(response->message.header.response.bodylen == 0);
1308            cb_assert(response->message.header.response.cas != 0);
1309            break;
1310        case PROTOCOL_BINARY_CMD_FLUSH:
1311        case PROTOCOL_BINARY_CMD_NOOP:
1312        case PROTOCOL_BINARY_CMD_QUIT:
1313        case PROTOCOL_BINARY_CMD_DELETE:
1314            cb_assert(response->message.header.response.keylen == 0);
1315            cb_assert(response->message.header.response.extlen == 0);
1316            cb_assert(response->message.header.response.bodylen == 0);
1317            break;
1318
1319        case PROTOCOL_BINARY_CMD_DECREMENT:
1320        case PROTOCOL_BINARY_CMD_INCREMENT:
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 == 8);
1324            cb_assert(response->message.header.response.cas != 0);
1325            break;
1326
1327        case PROTOCOL_BINARY_CMD_STAT:
1328            cb_assert(response->message.header.response.extlen == 0);
1329            /* key and value exists in all packets except in the terminating */
1330            cb_assert(response->message.header.response.cas == 0);
1331            break;
1332
1333        case PROTOCOL_BINARY_CMD_VERSION:
1334            cb_assert(response->message.header.response.keylen == 0);
1335            cb_assert(response->message.header.response.extlen == 0);
1336            cb_assert(response->message.header.response.bodylen != 0);
1337            cb_assert(response->message.header.response.cas == 0);
1338            break;
1339
1340        case PROTOCOL_BINARY_CMD_GET:
1341        case PROTOCOL_BINARY_CMD_GETQ:
1342            cb_assert(response->message.header.response.keylen == 0);
1343            cb_assert(response->message.header.response.extlen == 4);
1344            cb_assert(response->message.header.response.cas != 0);
1345            break;
1346
1347        case PROTOCOL_BINARY_CMD_GETK:
1348        case PROTOCOL_BINARY_CMD_GETKQ:
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        default:
1355            /* Undefined command code */
1356            break;
1357        }
1358    } else {
1359        cb_assert(response->message.header.response.cas == 0);
1360        cb_assert(response->message.header.response.extlen == 0);
1361        if (cmd != PROTOCOL_BINARY_CMD_GETK) {
1362            cb_assert(response->message.header.response.keylen == 0);
1363        }
1364    }
1365}
1366
1367static enum test_return test_binary_noop(void) {
1368    union {
1369        protocol_binary_request_no_extras request;
1370        protocol_binary_response_no_extras response;
1371        char bytes[1024];
1372    } buffer;
1373
1374    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1375                             PROTOCOL_BINARY_CMD_NOOP,
1376                             NULL, 0, NULL, 0);
1377
1378    safe_send(buffer.bytes, len, false);
1379    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1380    validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_NOOP,
1381                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1382
1383    return TEST_PASS;
1384}
1385
1386static enum test_return test_binary_quit_impl(uint8_t cmd) {
1387    union {
1388        protocol_binary_request_no_extras request;
1389        protocol_binary_response_no_extras response;
1390        char bytes[1024];
1391    } buffer;
1392    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1393                             cmd, NULL, 0, NULL, 0);
1394
1395    safe_send(buffer.bytes, len, false);
1396    if (cmd == PROTOCOL_BINARY_CMD_QUIT) {
1397        safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1398        validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_QUIT,
1399                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1400    }
1401
1402    /* Socket should be closed now, read should return 0 */
1403    cb_assert(phase_recv(buffer.bytes, sizeof(buffer.bytes)) == 0);
1404
1405    reconnect_to_server("127.0.0.1", false);
1406
1407    return TEST_PASS;
1408}
1409
1410static enum test_return test_binary_quit(void) {
1411    return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT);
1412}
1413
1414static enum test_return test_binary_quitq(void) {
1415    return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ);
1416}
1417
1418static enum test_return test_binary_set_impl(const char *key, uint8_t cmd) {
1419    union {
1420        protocol_binary_request_no_extras request;
1421        protocol_binary_response_no_extras response;
1422        char bytes[1024];
1423    } send, receive;
1424    uint64_t value = 0xdeadbeefdeadcafe;
1425    size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1426                                 key, strlen(key), &value, sizeof(value),
1427                                 0, 0);
1428
1429    /* Set should work over and over again */
1430    int ii;
1431    for (ii = 0; ii < 10; ++ii) {
1432        safe_send(send.bytes, len, false);
1433        if (cmd == PROTOCOL_BINARY_CMD_SET) {
1434            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1435            validate_response_header(&receive.response, cmd,
1436                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
1437        }
1438    }
1439
1440    if (cmd == PROTOCOL_BINARY_CMD_SETQ) {
1441        return test_binary_noop();
1442    }
1443
1444    send.request.message.header.request.cas = receive.response.message.header.response.cas;
1445    safe_send(send.bytes, len, false);
1446    if (cmd == PROTOCOL_BINARY_CMD_SET) {
1447        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1448        validate_response_header(&receive.response, cmd,
1449                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1450        cb_assert(receive.response.message.header.response.cas != send.request.message.header.request.cas);
1451    } else {
1452        return test_binary_noop();
1453    }
1454
1455    return TEST_PASS;
1456}
1457
1458static enum test_return test_binary_set(void) {
1459    return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET);
1460}
1461
1462static enum test_return test_binary_setq(void) {
1463    return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ);
1464}
1465
1466static enum test_return test_binary_add_impl(const char *key, uint8_t cmd) {
1467    uint64_t value = 0xdeadbeefdeadcafe;
1468    union {
1469        protocol_binary_request_no_extras request;
1470        protocol_binary_response_no_extras response;
1471        char bytes[1024];
1472    } send, receive;
1473    size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd, key,
1474                                 strlen(key), &value, sizeof(value),
1475                                 0, 0);
1476
1477    /* Add should only work the first time */
1478    int ii;
1479    for (ii = 0; ii < 10; ++ii) {
1480        safe_send(send.bytes, len, false);
1481        if (ii == 0) {
1482            if (cmd == PROTOCOL_BINARY_CMD_ADD) {
1483                safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1484                validate_response_header(&receive.response, cmd,
1485                                         PROTOCOL_BINARY_RESPONSE_SUCCESS);
1486            }
1487        } else {
1488            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1489            validate_response_header(&receive.response, cmd,
1490                                     PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
1491        }
1492    }
1493
1494    /* And verify that it doesn't work with the "correct" CAS */
1495    /* value */
1496    send.request.message.header.request.cas = receive.response.message.header.response.cas;
1497    safe_send(send.bytes, len, false);
1498    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1499    validate_response_header(&receive.response, cmd,
1500                             PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
1501    return TEST_PASS;
1502}
1503
1504static enum test_return test_binary_add(void) {
1505    return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD);
1506}
1507
1508static enum test_return test_binary_addq(void) {
1509    return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ);
1510}
1511
1512static enum test_return test_binary_replace_impl(const char* key, uint8_t cmd) {
1513    uint64_t value = 0xdeadbeefdeadcafe;
1514    union {
1515        protocol_binary_request_no_extras request;
1516        protocol_binary_response_no_extras response;
1517        char bytes[1024];
1518    } send, receive;
1519    int ii;
1520    size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1521                                 key, strlen(key), &value, sizeof(value),
1522                                 0, 0);
1523    safe_send(send.bytes, len, false);
1524    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1525    validate_response_header(&receive.response, cmd,
1526                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1527    len = storage_command(send.bytes, sizeof(send.bytes),
1528                          PROTOCOL_BINARY_CMD_ADD,
1529                          key, strlen(key), &value, sizeof(value), 0, 0);
1530    safe_send(send.bytes, len, false);
1531    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1532    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1533                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1534
1535    len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1536                          key, strlen(key), &value, sizeof(value), 0, 0);
1537    for (ii = 0; ii < 10; ++ii) {
1538        safe_send(send.bytes, len, false);
1539        if (cmd == PROTOCOL_BINARY_CMD_REPLACE) {
1540            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1541            validate_response_header(&receive.response,
1542                                     PROTOCOL_BINARY_CMD_REPLACE,
1543                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
1544        }
1545    }
1546
1547    if (cmd == PROTOCOL_BINARY_CMD_REPLACEQ) {
1548        test_binary_noop();
1549    }
1550
1551    return TEST_PASS;
1552}
1553
1554static enum test_return test_binary_replace(void) {
1555    return test_binary_replace_impl("test_binary_replace",
1556                                    PROTOCOL_BINARY_CMD_REPLACE);
1557}
1558
1559static enum test_return test_binary_replaceq(void) {
1560    return test_binary_replace_impl("test_binary_replaceq",
1561                                    PROTOCOL_BINARY_CMD_REPLACEQ);
1562}
1563
1564static enum test_return test_binary_delete_impl(const char *key, uint8_t cmd) {
1565    union {
1566        protocol_binary_request_no_extras request;
1567        protocol_binary_response_no_extras response;
1568        char bytes[1024];
1569    } send, receive;
1570    size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1571                             key, strlen(key), NULL, 0);
1572
1573    safe_send(send.bytes, len, false);
1574    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1575    validate_response_header(&receive.response, cmd,
1576                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1577    len = storage_command(send.bytes, sizeof(send.bytes),
1578                          PROTOCOL_BINARY_CMD_ADD,
1579                          key, strlen(key), NULL, 0, 0, 0);
1580    safe_send(send.bytes, len, false);
1581    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1582    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1583                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1584
1585    len = raw_command(send.bytes, sizeof(send.bytes),
1586                      cmd, key, strlen(key), NULL, 0);
1587    safe_send(send.bytes, len, false);
1588
1589    if (cmd == PROTOCOL_BINARY_CMD_DELETE) {
1590        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1591        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE,
1592                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1593    }
1594
1595    safe_send(send.bytes, len, false);
1596    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1597    validate_response_header(&receive.response, cmd,
1598                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1599
1600    return TEST_PASS;
1601}
1602
1603static enum test_return test_binary_delete(void) {
1604    return test_binary_delete_impl("test_binary_delete",
1605                                   PROTOCOL_BINARY_CMD_DELETE);
1606}
1607
1608static enum test_return test_binary_deleteq(void) {
1609    return test_binary_delete_impl("test_binary_deleteq",
1610                                   PROTOCOL_BINARY_CMD_DELETEQ);
1611}
1612
1613static enum test_return test_binary_delete_cas_impl(const char *key, bool bad) {
1614    union {
1615        protocol_binary_request_no_extras request;
1616        protocol_binary_response_no_extras response;
1617        char bytes[1024];
1618    } send, receive;
1619    size_t len;
1620    len = storage_command(send.bytes, sizeof(send.bytes),
1621                          PROTOCOL_BINARY_CMD_SET,
1622                          key, strlen(key), NULL, 0, 0, 0);
1623    safe_send(send.bytes, len, false);
1624    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1625    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1626                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1627    len = raw_command(send.bytes, sizeof(send.bytes),
1628                       PROTOCOL_BINARY_CMD_DELETE, key, strlen(key), NULL, 0);
1629
1630    send.request.message.header.request.cas = receive.response.message.header.response.cas;
1631    if (bad) {
1632        ++send.request.message.header.request.cas;
1633    }
1634    safe_send(send.bytes, len, false);
1635    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1636    if (bad) {
1637        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE,
1638                                 PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
1639    } else {
1640        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE,
1641                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1642    }
1643
1644    return TEST_PASS;
1645}
1646
1647
1648static enum test_return test_binary_delete_cas(void) {
1649    return test_binary_delete_cas_impl("test_binary_delete_cas", false);
1650}
1651
1652static enum test_return test_binary_delete_bad_cas(void) {
1653    return test_binary_delete_cas_impl("test_binary_delete_bad_cas", true);
1654}
1655
1656static enum test_return test_binary_get_impl(const char *key, uint8_t cmd) {
1657    union {
1658        protocol_binary_request_no_extras request;
1659        protocol_binary_response_no_extras response;
1660        char bytes[1024];
1661    } send, receive;
1662    int ii;
1663    size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1664                             key, strlen(key), NULL, 0);
1665
1666    safe_send(send.bytes, len, false);
1667    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1668    validate_response_header(&receive.response, cmd,
1669                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1670
1671    len = storage_command(send.bytes, sizeof(send.bytes),
1672                          PROTOCOL_BINARY_CMD_ADD,
1673                          key, strlen(key), NULL, 0,
1674                          0, 0);
1675    safe_send(send.bytes, len, false);
1676    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1677    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1678                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1679
1680    /* run a little pipeline test ;-) */
1681    len = 0;
1682    for (ii = 0; ii < 10; ++ii) {
1683        union {
1684            protocol_binary_request_no_extras request;
1685            char bytes[1024];
1686        } temp;
1687        size_t l = raw_command(temp.bytes, sizeof(temp.bytes),
1688                               cmd, key, strlen(key), NULL, 0);
1689        memcpy(send.bytes + len, temp.bytes, l);
1690        len += l;
1691    }
1692
1693    safe_send(send.bytes, len, false);
1694    for (ii = 0; ii < 10; ++ii) {
1695        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1696        validate_response_header(&receive.response, cmd,
1697                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1698    }
1699
1700    return TEST_PASS;
1701}
1702
1703static enum test_return test_binary_get(void) {
1704    return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET);
1705}
1706
1707static enum test_return test_binary_getk(void) {
1708    return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK);
1709}
1710
1711static enum test_return test_binary_getq_impl(const char *key, uint8_t cmd) {
1712    const char *missing = "test_binary_getq_missing";
1713    union {
1714        protocol_binary_request_no_extras request;
1715        protocol_binary_response_no_extras response;
1716        char bytes[1024];
1717    } send, temp, receive;
1718    size_t len = storage_command(send.bytes, sizeof(send.bytes),
1719                                 PROTOCOL_BINARY_CMD_ADD,
1720                                 key, strlen(key), NULL, 0,
1721                                 0, 0);
1722    size_t len2 = raw_command(temp.bytes, sizeof(temp.bytes), cmd,
1723                             missing, strlen(missing), NULL, 0);
1724    /* I need to change the first opaque so that I can separate the two
1725     * return packets */
1726    temp.request.message.header.request.opaque = 0xfeedface;
1727    memcpy(send.bytes + len, temp.bytes, len2);
1728    len += len2;
1729
1730    len2 = raw_command(temp.bytes, sizeof(temp.bytes), cmd,
1731                       key, strlen(key), NULL, 0);
1732    memcpy(send.bytes + len, temp.bytes, len2);
1733    len += len2;
1734
1735    safe_send(send.bytes, len, false);
1736    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1737    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1738                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1739    /* The first GETQ shouldn't return anything */
1740    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1741    validate_response_header(&receive.response, cmd,
1742                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1743
1744    return TEST_PASS;
1745}
1746
1747static enum test_return test_binary_getq(void) {
1748    return test_binary_getq_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ);
1749}
1750
1751static enum test_return test_binary_getkq(void) {
1752    return test_binary_getq_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ);
1753}
1754
1755static enum test_return test_binary_incr_impl(const char* key, uint8_t cmd) {
1756    union {
1757        protocol_binary_request_no_extras request;
1758        protocol_binary_response_no_extras response_header;
1759        protocol_binary_response_incr response;
1760        char bytes[1024];
1761    } send, receive;
1762    size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
1763                                    key, strlen(key), 1, 0, 0);
1764
1765    int ii;
1766    for (ii = 0; ii < 10; ++ii) {
1767        safe_send(send.bytes, len, false);
1768        if (cmd == PROTOCOL_BINARY_CMD_INCREMENT) {
1769            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1770            validate_response_header(&receive.response_header, cmd,
1771                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
1772            cb_assert(ntohll(receive.response.message.body.value) == ii);
1773        }
1774    }
1775
1776    if (cmd == PROTOCOL_BINARY_CMD_INCREMENTQ) {
1777        test_binary_noop();
1778    }
1779    return TEST_PASS;
1780}
1781
1782static enum test_return test_binary_incr(void) {
1783    return test_binary_incr_impl("test_binary_incr",
1784                                 PROTOCOL_BINARY_CMD_INCREMENT);
1785}
1786
1787static enum test_return test_binary_incrq(void) {
1788    return test_binary_incr_impl("test_binary_incrq",
1789                                 PROTOCOL_BINARY_CMD_INCREMENTQ);
1790}
1791
1792static enum test_return test_binary_incr_invalid_cas_impl(const char* key, uint8_t cmd) {
1793    union {
1794        protocol_binary_request_no_extras request;
1795        protocol_binary_response_no_extras response_header;
1796        protocol_binary_response_incr response;
1797        char bytes[1024];
1798    } send, receive;
1799    size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
1800                                    key, strlen(key), 1, 0, 0);
1801
1802    send.request.message.header.request.cas = 5;
1803    safe_send(send.bytes, len, false);
1804    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1805    validate_response_header(&receive.response_header, cmd,
1806                             PROTOCOL_BINARY_RESPONSE_EINVAL);
1807    return TEST_PASS;
1808}
1809
1810static enum test_return test_binary_invalid_cas_incr(void) {
1811    return test_binary_incr_invalid_cas_impl("test_binary_incr",
1812                                             PROTOCOL_BINARY_CMD_INCREMENT);
1813}
1814
1815static enum test_return test_binary_invalid_cas_incrq(void) {
1816    return test_binary_incr_invalid_cas_impl("test_binary_incrq",
1817                                             PROTOCOL_BINARY_CMD_INCREMENTQ);
1818}
1819
1820static enum test_return test_binary_invalid_cas_decr(void) {
1821    return test_binary_incr_invalid_cas_impl("test_binary_incr",
1822                                             PROTOCOL_BINARY_CMD_DECREMENT);
1823}
1824
1825static enum test_return test_binary_invalid_cas_decrq(void) {
1826    return test_binary_incr_invalid_cas_impl("test_binary_incrq",
1827                                             PROTOCOL_BINARY_CMD_DECREMENTQ);
1828}
1829
1830static enum test_return test_binary_decr_impl(const char* key, uint8_t cmd) {
1831    union {
1832        protocol_binary_request_no_extras request;
1833        protocol_binary_response_no_extras response_header;
1834        protocol_binary_response_decr response;
1835        char bytes[1024];
1836    } send, receive;
1837    size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
1838                                    key, strlen(key), 1, 9, 0);
1839
1840    int ii;
1841    for (ii = 9; ii >= 0; --ii) {
1842        safe_send(send.bytes, len, false);
1843        if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
1844            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1845            validate_response_header(&receive.response_header, cmd,
1846                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
1847            cb_assert(ntohll(receive.response.message.body.value) == ii);
1848        }
1849    }
1850
1851    /* decr on 0 should not wrap */
1852    safe_send(send.bytes, len, false);
1853    if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
1854        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1855        validate_response_header(&receive.response_header, cmd,
1856                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1857        cb_assert(ntohll(receive.response.message.body.value) == 0);
1858    } else {
1859        test_binary_noop();
1860    }
1861
1862    return TEST_PASS;
1863}
1864
1865static enum test_return test_binary_decr(void) {
1866    return test_binary_decr_impl("test_binary_decr",
1867                                 PROTOCOL_BINARY_CMD_DECREMENT);
1868}
1869
1870static enum test_return test_binary_decrq(void) {
1871    return test_binary_decr_impl("test_binary_decrq",
1872                                 PROTOCOL_BINARY_CMD_DECREMENTQ);
1873}
1874
1875static enum test_return test_binary_version(void) {
1876    union {
1877        protocol_binary_request_no_extras request;
1878        protocol_binary_response_no_extras response;
1879        char bytes[1024];
1880    } buffer;
1881
1882    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1883                             PROTOCOL_BINARY_CMD_VERSION,
1884                             NULL, 0, NULL, 0);
1885
1886    safe_send(buffer.bytes, len, false);
1887    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1888    validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_VERSION,
1889                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1890
1891    return TEST_PASS;
1892}
1893
1894static enum test_return test_binary_flush_impl(const char *key, uint8_t cmd) {
1895    union {
1896        protocol_binary_request_no_extras request;
1897        protocol_binary_response_no_extras response;
1898        char bytes[1024];
1899    } send, receive;
1900    int ii;
1901
1902    size_t len = storage_command(send.bytes, sizeof(send.bytes),
1903                                 PROTOCOL_BINARY_CMD_ADD,
1904                                 key, strlen(key), NULL, 0, 0, 0);
1905    safe_send(send.bytes, len, false);
1906    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1907    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1908                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1909
1910    len = flush_command(send.bytes, sizeof(send.bytes), cmd, 2, true);
1911    safe_send(send.bytes, len, false);
1912    if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
1913        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1914        validate_response_header(&receive.response, cmd,
1915                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1916    }
1917
1918    len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GET,
1919                      key, strlen(key), NULL, 0);
1920    safe_send(send.bytes, len, false);
1921    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1922    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1923                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1924
1925#ifdef WIN32
1926    Sleep(2000);
1927#else
1928    sleep(2);
1929#endif
1930    safe_send(send.bytes, len, false);
1931    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1932    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1933                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1934
1935    for (ii = 0; ii < 2; ++ii) {
1936        len = storage_command(send.bytes, sizeof(send.bytes),
1937                              PROTOCOL_BINARY_CMD_ADD,
1938                              key, strlen(key), NULL, 0, 0, 0);
1939        safe_send(send.bytes, len, false);
1940        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1941        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1942                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
1943
1944        len = flush_command(send.bytes, sizeof(send.bytes), cmd, 0, ii == 0);
1945        safe_send(send.bytes, len, false);
1946        if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
1947            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1948            validate_response_header(&receive.response, cmd,
1949                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
1950        }
1951
1952        len = raw_command(send.bytes, sizeof(send.bytes),
1953                          PROTOCOL_BINARY_CMD_GET,
1954                          key, strlen(key), NULL, 0);
1955        safe_send(send.bytes, len, false);
1956        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1957        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1958                                 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1959    }
1960
1961    return TEST_PASS;
1962}
1963
1964static enum test_return test_binary_flush(void) {
1965    return test_binary_flush_impl("test_binary_flush",
1966                                  PROTOCOL_BINARY_CMD_FLUSH);
1967}
1968
1969static enum test_return test_binary_flushq(void) {
1970    return test_binary_flush_impl("test_binary_flushq",
1971                                  PROTOCOL_BINARY_CMD_FLUSHQ);
1972}
1973
1974static enum test_return test_binary_cas(void) {
1975    union {
1976        protocol_binary_request_no_extras request;
1977        protocol_binary_response_no_extras response;
1978        char bytes[1024];
1979    } send, receive;
1980    uint64_t value = 0xdeadbeefdeadcafe;
1981    size_t len = flush_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_FLUSH,
1982                               0, false);
1983    safe_send(send.bytes, len, false);
1984    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1985    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_FLUSH,
1986                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
1987
1988    len = storage_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_SET,
1989                          "FOO", 3, &value, sizeof(value), 0, 0);
1990
1991    send.request.message.header.request.cas = 0x7ffffff;
1992    safe_send(send.bytes, len, false);
1993    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1994    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1995                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1996
1997    send.request.message.header.request.cas = 0x0;
1998    safe_send(send.bytes, len, false);
1999    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2000    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
2001                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2002
2003    send.request.message.header.request.cas = receive.response.message.header.response.cas;
2004    safe_send(send.bytes, len, false);
2005    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2006    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
2007                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2008
2009    send.request.message.header.request.cas = receive.response.message.header.response.cas - 1;
2010    safe_send(send.bytes, len, false);
2011    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2012    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
2013                             PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
2014    return TEST_PASS;
2015}
2016
2017static enum test_return test_binary_concat_impl(const char *key, uint8_t cmd) {
2018    union {
2019        protocol_binary_request_no_extras request;
2020        protocol_binary_response_no_extras response;
2021        char bytes[1024];
2022    } send, receive;
2023    const char *value = "world";
2024    char *ptr;
2025    size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
2026                              key, strlen(key), value, strlen(value));
2027
2028
2029    safe_send(send.bytes, len, false);
2030    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2031    validate_response_header(&receive.response, cmd,
2032                             PROTOCOL_BINARY_RESPONSE_NOT_STORED);
2033
2034    len = storage_command(send.bytes, sizeof(send.bytes),
2035                          PROTOCOL_BINARY_CMD_ADD,
2036                          key, strlen(key), value, strlen(value), 0, 0);
2037    safe_send(send.bytes, len, false);
2038    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2039    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
2040                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2041
2042    len = raw_command(send.bytes, sizeof(send.bytes), cmd,
2043                      key, strlen(key), value, strlen(value));
2044    safe_send(send.bytes, len, false);
2045
2046    if (cmd == PROTOCOL_BINARY_CMD_APPEND || cmd == PROTOCOL_BINARY_CMD_PREPEND) {
2047        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2048        validate_response_header(&receive.response, cmd,
2049                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
2050    } else {
2051        len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_NOOP,
2052                          NULL, 0, NULL, 0);
2053        safe_send(send.bytes, len, false);
2054        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2055        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_NOOP,
2056                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
2057    }
2058
2059    len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GETK,
2060                      key, strlen(key), NULL, 0);
2061
2062    safe_send(send.bytes, len, false);
2063    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2064    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GETK,
2065                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2066
2067    cb_assert(receive.response.message.header.response.keylen == strlen(key));
2068    cb_assert(receive.response.message.header.response.bodylen == (strlen(key) + 2*strlen(value) + 4));
2069
2070    ptr = receive.bytes;
2071    ptr += sizeof(receive.response);
2072    ptr += 4;
2073
2074    cb_assert(memcmp(ptr, key, strlen(key)) == 0);
2075    ptr += strlen(key);
2076    cb_assert(memcmp(ptr, value, strlen(value)) == 0);
2077    ptr += strlen(value);
2078    cb_assert(memcmp(ptr, value, strlen(value)) == 0);
2079
2080    return TEST_PASS;
2081}
2082
2083static enum test_return test_binary_append(void) {
2084    return test_binary_concat_impl("test_binary_append",
2085                                   PROTOCOL_BINARY_CMD_APPEND);
2086}
2087
2088static enum test_return test_binary_prepend(void) {
2089    return test_binary_concat_impl("test_binary_prepend",
2090                                   PROTOCOL_BINARY_CMD_PREPEND);
2091}
2092
2093static enum test_return test_binary_appendq(void) {
2094    return test_binary_concat_impl("test_binary_appendq",
2095                                   PROTOCOL_BINARY_CMD_APPENDQ);
2096}
2097
2098static enum test_return test_binary_prependq(void) {
2099    return test_binary_concat_impl("test_binary_prependq",
2100                                   PROTOCOL_BINARY_CMD_PREPENDQ);
2101}
2102
2103static enum test_return test_binary_stat(void) {
2104    union {
2105        protocol_binary_request_no_extras request;
2106        protocol_binary_response_no_extras response;
2107        char bytes[1024];
2108    } buffer;
2109
2110    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2111                             PROTOCOL_BINARY_CMD_STAT,
2112                             NULL, 0, NULL, 0);
2113
2114    safe_send(buffer.bytes, len, false);
2115    do {
2116        safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2117        validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_STAT,
2118                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
2119    } while (buffer.response.message.header.response.keylen != 0);
2120
2121    return TEST_PASS;
2122}
2123
2124static enum test_return test_binary_scrub(void) {
2125    union {
2126        protocol_binary_request_no_extras request;
2127        protocol_binary_response_no_extras response;
2128        char bytes[1024];
2129    } buffer;
2130
2131    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2132                             PROTOCOL_BINARY_CMD_SCRUB,
2133                             NULL, 0, NULL, 0);
2134
2135    safe_send(buffer.bytes, len, false);
2136    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2137    validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_SCRUB,
2138                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2139
2140    return TEST_PASS;
2141}
2142
2143
2144volatile bool hickup_thread_running;
2145
2146static void binary_hickup_recv_verification_thread(void *arg) {
2147    protocol_binary_response_no_extras *response = malloc(65*1024);
2148    if (response != NULL) {
2149        while (safe_recv_packet(response, 65*1024)) {
2150            /* Just validate the packet format */
2151            validate_response_header(response,
2152                                     response->message.header.response.opcode,
2153                                     response->message.header.response.status);
2154        }
2155        free(response);
2156    }
2157    hickup_thread_running = false;
2158    allow_closed_read = false;
2159}
2160
2161static enum test_return test_binary_pipeline_hickup_chunk(void *buffer, size_t buffersize) {
2162    off_t offset = 0;
2163    char *key[256];
2164    uint64_t value = 0xfeedfacedeadbeef;
2165
2166    while (hickup_thread_running &&
2167           offset + sizeof(protocol_binary_request_no_extras) < buffersize) {
2168        union {
2169            protocol_binary_request_no_extras request;
2170            char bytes[65 * 1024];
2171        } command;
2172        uint8_t cmd = (uint8_t)(rand() & 0xff);
2173        size_t len;
2174        size_t keylen = (rand() % 250) + 1;
2175
2176        switch (cmd) {
2177        case PROTOCOL_BINARY_CMD_ADD:
2178        case PROTOCOL_BINARY_CMD_ADDQ:
2179        case PROTOCOL_BINARY_CMD_REPLACE:
2180        case PROTOCOL_BINARY_CMD_REPLACEQ:
2181        case PROTOCOL_BINARY_CMD_SET:
2182        case PROTOCOL_BINARY_CMD_SETQ:
2183            len = storage_command(command.bytes, sizeof(command.bytes), cmd,
2184                                  key, keylen , &value, sizeof(value),
2185                                  0, 0);
2186            break;
2187        case PROTOCOL_BINARY_CMD_APPEND:
2188        case PROTOCOL_BINARY_CMD_APPENDQ:
2189        case PROTOCOL_BINARY_CMD_PREPEND:
2190        case PROTOCOL_BINARY_CMD_PREPENDQ:
2191            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
2192                              key, keylen, &value, sizeof(value));
2193            break;
2194        case PROTOCOL_BINARY_CMD_FLUSH:
2195        case PROTOCOL_BINARY_CMD_FLUSHQ:
2196            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
2197                              NULL, 0, NULL, 0);
2198            break;
2199        case PROTOCOL_BINARY_CMD_NOOP:
2200            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
2201                              NULL, 0, NULL, 0);
2202            break;
2203        case PROTOCOL_BINARY_CMD_DELETE:
2204        case PROTOCOL_BINARY_CMD_DELETEQ:
2205            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
2206                             key, keylen, NULL, 0);
2207            break;
2208        case PROTOCOL_BINARY_CMD_DECREMENT:
2209        case PROTOCOL_BINARY_CMD_DECREMENTQ:
2210        case PROTOCOL_BINARY_CMD_INCREMENT:
2211        case PROTOCOL_BINARY_CMD_INCREMENTQ:
2212            len = arithmetic_command(command.bytes, sizeof(command.bytes), cmd,
2213                                     key, keylen, 1, 0, 0);
2214            break;
2215        case PROTOCOL_BINARY_CMD_VERSION:
2216            len = raw_command(command.bytes, sizeof(command.bytes),
2217                             PROTOCOL_BINARY_CMD_VERSION,
2218                             NULL, 0, NULL, 0);
2219            break;
2220        case PROTOCOL_BINARY_CMD_GET:
2221        case PROTOCOL_BINARY_CMD_GETK:
2222        case PROTOCOL_BINARY_CMD_GETKQ:
2223        case PROTOCOL_BINARY_CMD_GETQ:
2224            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
2225                             key, keylen, NULL, 0);
2226            break;
2227
2228        case PROTOCOL_BINARY_CMD_STAT:
2229            len = raw_command(command.bytes, sizeof(command.bytes),
2230                              PROTOCOL_BINARY_CMD_STAT,
2231                              NULL, 0, NULL, 0);
2232            break;
2233
2234        default:
2235            /* don't run commands we don't know */
2236            continue;
2237        }
2238
2239        if ((len + offset) < buffersize) {
2240            memcpy(((char*)buffer) + offset, command.bytes, len);
2241            offset += (off_t)len;
2242        } else {
2243            break;
2244        }
2245    }
2246    safe_send(buffer, offset, true);
2247
2248    return TEST_PASS;
2249}
2250
2251static enum test_return test_binary_pipeline_hickup(void)
2252{
2253    size_t buffersize = 65 * 1024;
2254    void *buffer = malloc(buffersize);
2255    int ii;
2256    cb_thread_t tid;
2257    int ret;
2258    size_t len;
2259
2260    allow_closed_read = true;
2261    hickup_thread_running = true;
2262    if ((ret = cb_create_thread(&tid, binary_hickup_recv_verification_thread, NULL, 0)) != 0) {
2263        fprintf(stderr, "Can't create thread: %s\n", strerror(ret));
2264        free(buffer);
2265        return TEST_FAIL;
2266    }
2267
2268    /* Allow the thread to start */
2269#ifdef WIN32
2270    Sleep(1);
2271#else
2272    usleep(250);
2273#endif
2274
2275    srand((int)time(NULL));
2276    for (ii = 0; ii < 2; ++ii) {
2277        test_binary_pipeline_hickup_chunk(buffer, buffersize);
2278    }
2279
2280    /* send quitq to shut down the read thread ;-) */
2281    len = raw_command(buffer, buffersize, PROTOCOL_BINARY_CMD_QUITQ,
2282                      NULL, 0, NULL, 0);
2283    safe_send(buffer, len, false);
2284
2285    cb_join_thread(tid);
2286    free(buffer);
2287
2288    reconnect_to_server("127.0.0.1", false);
2289    return TEST_PASS;
2290}
2291
2292static enum test_return test_binary_ioctl(void) {
2293    union {
2294        protocol_binary_request_no_extras request;
2295        protocol_binary_response_no_extras response;
2296        char bytes[1024];
2297    } buffer;
2298
2299    /* NULL key is invalid. */
2300    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2301                             PROTOCOL_BINARY_CMD_IOCTL_SET, NULL, 0, NULL, 0);
2302
2303    safe_send(buffer.bytes, len, false);
2304    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2305    validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_IOCTL_SET,
2306                             PROTOCOL_BINARY_RESPONSE_EINVAL);
2307
2308    /* release_free_memory always returns OK, regardless of how much was freed.*/
2309    {
2310        char cmd[] = "release_free_memory";
2311        len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2312                          PROTOCOL_BINARY_CMD_IOCTL_SET, cmd, strlen(cmd),
2313                          NULL, 0);
2314
2315        safe_send(buffer.bytes, len, false);
2316        safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2317        validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_IOCTL_SET,
2318                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
2319    }
2320
2321    return TEST_PASS;
2322}
2323
2324static enum test_return test_binary_verbosity(void) {
2325    union {
2326        protocol_binary_request_verbosity request;
2327        protocol_binary_response_no_extras response;
2328        char bytes[1024];
2329    } buffer;
2330
2331    int ii;
2332    for (ii = 10; ii > -1; --ii) {
2333        size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2334                                 PROTOCOL_BINARY_CMD_VERBOSITY,
2335                                 NULL, 0, NULL, 0);
2336        buffer.request.message.header.request.extlen = 4;
2337        buffer.request.message.header.request.bodylen = ntohl(4);
2338        buffer.request.message.body.level = (uint32_t)ntohl(ii);
2339        safe_send(buffer.bytes, len + sizeof(4), false);
2340        safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2341        validate_response_header(&buffer.response,
2342                                 PROTOCOL_BINARY_CMD_VERBOSITY,
2343                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
2344    }
2345
2346    return TEST_PASS;
2347}
2348
2349static enum test_return validate_object(const char *key, const char *value) {
2350    union {
2351        protocol_binary_request_no_extras request;
2352        protocol_binary_response_no_extras response;
2353        char bytes[1024];
2354    } send, receive;
2355    char *ptr;
2356    size_t len = raw_command(send.bytes, sizeof(send.bytes),
2357                             PROTOCOL_BINARY_CMD_GET,
2358                             key, strlen(key), NULL, 0);
2359    safe_send(send.bytes, len, false);
2360    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2361    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
2362                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2363    cb_assert(receive.response.message.header.response.bodylen - 4 == strlen(value));
2364    ptr = receive.bytes + sizeof(receive.response) + 4;
2365    cb_assert(memcmp(value, ptr, strlen(value)) == 0);
2366
2367    return TEST_PASS;
2368}
2369
2370static enum test_return store_object(const char *key, char *value) {
2371    union {
2372        protocol_binary_request_no_extras request;
2373        protocol_binary_response_no_extras response;
2374        char bytes[1024];
2375    } send, receive;
2376    size_t len = storage_command(send.bytes, sizeof(send.bytes),
2377                                 PROTOCOL_BINARY_CMD_SET,
2378                                 key, strlen(key), value, strlen(value),
2379                                 0, 0);
2380
2381    safe_send(send.bytes, len, false);
2382    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
2383    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
2384                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2385
2386    validate_object(key, value);
2387    return TEST_PASS;
2388}
2389
2390static enum test_return test_binary_read(void) {
2391    union {
2392        protocol_binary_request_read request;
2393        protocol_binary_response_read response;
2394        char bytes[1024];
2395    } buffer;
2396    size_t len;
2397    char *ptr;
2398
2399    store_object("hello", "world");
2400
2401    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2402                      read_command, "hello",
2403                      strlen("hello"), NULL, 0);
2404    buffer.request.message.body.offset = htonl(1);
2405    buffer.request.message.body.length = htonl(3);
2406
2407    safe_send(buffer.bytes, len, false);
2408    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2409    validate_response_header(&buffer.response, read_command,
2410                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2411    cb_assert(buffer.response.message.header.response.bodylen == 3);
2412    ptr = buffer.bytes + sizeof(buffer.response);
2413    cb_assert(memcmp(ptr, "orl", 3) == 0);
2414
2415
2416    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2417                      read_command, "hello",
2418                      strlen("hello"), NULL, 0);
2419    buffer.request.message.body.offset = htonl(7);
2420    buffer.request.message.body.length = htonl(2);
2421    safe_send(buffer.bytes, len, false);
2422    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2423    validate_response_header(&buffer.response, read_command,
2424                             PROTOCOL_BINARY_RESPONSE_ERANGE);
2425
2426    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2427                      read_command, "myhello",
2428                      strlen("myhello"), NULL, 0);
2429    buffer.request.message.body.offset = htonl(0);
2430    buffer.request.message.body.length = htonl(5);
2431
2432    safe_send(buffer.bytes, len, false);
2433    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2434    validate_response_header(&buffer.response, read_command,
2435                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
2436    return TEST_PASS;
2437}
2438
2439static enum test_return test_binary_write(void) {
2440    union {
2441        protocol_binary_request_read request;
2442        protocol_binary_response_read response;
2443        char bytes[1024];
2444    } buffer;
2445    size_t len;
2446
2447    store_object("hello", "world");
2448
2449    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2450                             write_command, "hello",
2451                             strlen("hello"), "bubba", 5);
2452    buffer.request.message.body.offset = htonl(0);
2453    buffer.request.message.body.length = htonl(5);
2454
2455    safe_send(buffer.bytes, len, false);
2456    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2457    validate_response_header(&buffer.response, write_command,
2458                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2459    validate_object("hello", "bubba");
2460
2461    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2462                             write_command, "hello",
2463                             strlen("hello"), "zz", 2);
2464    buffer.request.message.body.offset = htonl(2);
2465    buffer.request.message.body.length = htonl(2);
2466
2467    safe_send(buffer.bytes, len, false);
2468    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2469    validate_response_header(&buffer.response, write_command,
2470                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2471    validate_object("hello", "buzza");
2472
2473    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2474                             write_command, "hello",
2475                             strlen("hello"), "zz", 2);
2476    buffer.request.message.body.offset = htonl(7);
2477    buffer.request.message.body.length = htonl(2);
2478
2479    safe_send(buffer.bytes, len, false);
2480    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2481    validate_response_header(&buffer.response, write_command,
2482                             PROTOCOL_BINARY_RESPONSE_ERANGE);
2483
2484    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2485                             write_command, "hello",
2486                             strlen("hello"), "bb", 2);
2487    buffer.request.message.body.offset = htonl(2);
2488    buffer.request.message.body.length = htonl(2);
2489    buffer.request.message.header.request.cas = 1;
2490
2491    safe_send(buffer.bytes, len, false);
2492    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2493    validate_response_header(&buffer.response, write_command,
2494                             PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
2495
2496    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2497                      write_command, "myhello",
2498                      strlen("myhello"), "bubba", 5);
2499    buffer.request.message.body.offset = htonl(0);
2500    buffer.request.message.body.length = htonl(5);
2501
2502    safe_send(buffer.bytes, len, false);
2503    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2504    validate_response_header(&buffer.response, write_command,
2505                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
2506    return TEST_PASS;
2507}
2508
2509static enum test_return test_binary_bad_tap_ttl(void) {
2510    union {
2511        protocol_binary_request_tap_flush request;
2512        protocol_binary_response_no_extras response;
2513        char bytes[1024];
2514    } buffer;
2515
2516    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2517                             PROTOCOL_BINARY_CMD_TAP_FLUSH,
2518                             NULL, 0, NULL, 0);
2519
2520    buffer.request.message.header.request.extlen = 8;
2521    buffer.request.message.header.request.bodylen = ntohl(8);
2522    buffer.request.message.body.tap.enginespecific_length = 0;
2523    buffer.request.message.body.tap.flags = 0;
2524    buffer.request.message.body.tap.ttl = 0;
2525    buffer.request.message.body.tap.res1 = 0;
2526    buffer.request.message.body.tap.res2 = 0;
2527    buffer.request.message.body.tap.res3 = 0;
2528    len += 8;
2529
2530    safe_send(buffer.bytes, len, false);
2531    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2532    validate_response_header(&buffer.response,
2533                             PROTOCOL_BINARY_CMD_TAP_FLUSH,
2534                             PROTOCOL_BINARY_RESPONSE_EINVAL);
2535    return TEST_PASS;
2536}
2537
2538static enum test_return test_binary_hello(void) {
2539    union {
2540        protocol_binary_request_hello request;
2541        protocol_binary_response_hello response;
2542        char bytes[1024];
2543    } buffer;
2544    const char *useragent = "hello world";
2545    uint16_t feature = htons(PROTOCOL_BINARY_FEATURE_DATATYPE);
2546    uint16_t *ptr;
2547    size_t len;
2548
2549    memset(buffer.bytes, 0, sizeof(buffer.bytes));
2550
2551    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2552                      PROTOCOL_BINARY_CMD_HELLO,
2553                      useragent, strlen(useragent), &feature,
2554                      sizeof(feature));
2555
2556    safe_send(buffer.bytes, len, false);
2557    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2558    validate_response_header(&buffer.response,
2559                             PROTOCOL_BINARY_CMD_HELLO,
2560                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2561
2562    cb_assert(buffer.response.message.header.response.bodylen == 2);
2563    ptr = (uint16_t*)(buffer.bytes + sizeof(buffer.response));
2564    cb_assert(ntohs(*ptr) == PROTOCOL_BINARY_FEATURE_DATATYPE);
2565
2566    feature = 0xffff;
2567    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2568                             PROTOCOL_BINARY_CMD_HELLO,
2569                             useragent, strlen(useragent), &feature,
2570                             sizeof(feature));
2571
2572    safe_send(buffer.bytes, len, false);
2573    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2574    validate_response_header(&buffer.response,
2575                             PROTOCOL_BINARY_CMD_HELLO,
2576                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
2577    cb_assert(buffer.response.message.header.response.bodylen == 0);
2578
2579
2580    len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2581                             PROTOCOL_BINARY_CMD_HELLO,
2582                             useragent, strlen(useragent), &feature,
2583                             sizeof(feature) - 1);
2584
2585    safe_send(buffer.bytes, len, false);
2586    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2587    validate_response_header(&buffer.response,
2588                             PROTOCOL_BINARY_CMD_HELLO,
2589                             PROTOCOL_BINARY_RESPONSE_EINVAL);
2590
2591    return TEST_PASS;
2592}
2593
2594static void set_datatype_feature(bool enable) {
2595    union {
2596        protocol_binary_request_hello request;
2597        protocol_binary_response_hello response;
2598        char bytes[1024];
2599    } buffer;
2600    const char *useragent = "testapp";
2601    uint16_t feature = htons(PROTOCOL_BINARY_FEATURE_DATATYPE);
2602    size_t len = strlen(useragent);
2603
2604    memset(buffer.bytes, 0, sizeof(buffer));
2605    buffer.request.message.header.request.magic = PROTOCOL_BINARY_REQ;
2606    buffer.request.message.header.request.opcode = PROTOCOL_BINARY_CMD_HELLO;
2607    buffer.request.message.header.request.keylen = htons((uint16_t)len);
2608    if (enable) {
2609        buffer.request.message.header.request.bodylen = htonl((uint32_t)len + 2);
2610    } else {
2611        buffer.request.message.header.request.bodylen = htonl((uint32_t)len);
2612    }
2613    memcpy(buffer.bytes + 24, useragent, len);
2614    memcpy(buffer.bytes + 24 + len, &feature, 2);
2615
2616    safe_send(buffer.bytes,
2617              sizeof(buffer.request) + ntohl(buffer.request.message.header.request.bodylen), false);
2618
2619    safe_recv(&buffer.response, sizeof(buffer.response));
2620    len = ntohl(buffer.response.message.header.response.bodylen);
2621    if (enable) {
2622        cb_assert(len == 2);
2623        safe_recv(&feature, sizeof(feature));
2624        cb_assert(feature == htons(PROTOCOL_BINARY_FEATURE_DATATYPE));
2625    } else {
2626        cb_assert(len == 0);
2627    }
2628}
2629
2630static void store_object_w_datatype(const char *key,
2631                                    const void *data, size_t datalen,
2632                                    bool deflate, bool json)
2633{
2634    protocol_binary_request_no_extras request;
2635    int keylen = (int)strlen(key);
2636    char extra[8] = { 0 };
2637    uint8_t datatype = PROTOCOL_BINARY_RAW_BYTES;
2638    if (deflate) {
2639        datatype |= PROTOCOL_BINARY_DATATYPE_COMPRESSED;
2640    }
2641
2642    if (json) {
2643        datatype |= PROTOCOL_BINARY_DATATYPE_JSON;
2644    }
2645
2646    memset(request.bytes, 0, sizeof(request));
2647    request.message.header.request.magic = PROTOCOL_BINARY_REQ;
2648    request.message.header.request.opcode = PROTOCOL_BINARY_CMD_SETQ;
2649    request.message.header.request.datatype = datatype;
2650    request.message.header.request.extlen = 8;
2651    request.message.header.request.keylen = htons((uint16_t)keylen);
2652    request.message.header.request.bodylen = htonl((uint32_t)(keylen + datalen + 8));
2653
2654    safe_send(&request.bytes, sizeof(request.bytes), false);
2655    safe_send(extra, sizeof(extra), false);
2656    safe_send(key, strlen(key), false);
2657    safe_send(data, datalen, false);
2658}
2659
2660static void get_object_w_datatype(const char *key,
2661                                  const void *data, size_t datalen,
2662                                  bool deflate, bool json,
2663                                  bool conversion)
2664{
2665    protocol_binary_response_no_extras response;
2666    protocol_binary_request_no_extras request;
2667    char *body;
2668    int keylen = (int)strlen(key);
2669    uint32_t flags;
2670    uint8_t datatype = PROTOCOL_BINARY_RAW_BYTES;
2671    uint32_t len;
2672
2673    if (deflate) {
2674        datatype |= PROTOCOL_BINARY_DATATYPE_COMPRESSED;
2675    }
2676
2677    if (json) {
2678        datatype |= PROTOCOL_BINARY_DATATYPE_JSON;
2679    }
2680
2681    memset(request.bytes, 0, sizeof(request));
2682    request.message.header.request.magic = PROTOCOL_BINARY_REQ;
2683    request.message.header.request.opcode = PROTOCOL_BINARY_CMD_GET;
2684    request.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
2685    request.message.header.request.keylen = htons((uint16_t)keylen);
2686    request.message.header.request.bodylen = htonl(keylen);
2687
2688    safe_send(&request.bytes, sizeof(request.bytes), false);
2689    safe_send(key, strlen(key), false);
2690
2691    safe_recv(&response.bytes, sizeof(response.bytes));
2692    if (ntohs(response.message.header.response.status != PROTOCOL_BINARY_RESPONSE_SUCCESS)) {
2693        fprintf(stderr, "Failed to retrieve object!: %d\n",
2694                (int)ntohs(response.message.header.response.status));
2695        abort();
2696    }
2697
2698    len = ntohl(response.message.header.response.bodylen);
2699    cb_assert(len > 4);
2700    safe_recv(&flags, sizeof(flags));
2701    len -= 4;
2702    cb_assert((body = malloc(len)) != NULL);
2703    safe_recv(body, len);
2704
2705    if (conversion) {
2706        cb_assert(response.message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
2707    } else {
2708        cb_assert(response.message.header.response.datatype == datatype);
2709    }
2710
2711    cb_assert(len == datalen);
2712    cb_assert(memcmp(data, body, len) == 0);
2713    free(body);
2714}
2715
2716static enum test_return test_binary_datatype_json(void) {
2717    const char body[] = "{ \"value\" : 1234123412 }";
2718    set_datatype_feature(true);
2719    store_object_w_datatype("myjson", body, strlen(body), false, true);
2720
2721    get_object_w_datatype("myjson", body, strlen(body), false, true, false);
2722
2723    set_datatype_feature(false);
2724    get_object_w_datatype("myjson", body, strlen(body), false, true, true);
2725
2726    return TEST_PASS;
2727}
2728
2729static enum test_return test_binary_datatype_json_without_support(void) {
2730    const char body[] = "{ \"value\" : 1234123412 }";
2731    set_datatype_feature(false);
2732    store_object_w_datatype("myjson", body, strlen(body), false, false);
2733
2734    get_object_w_datatype("myjson", body, strlen(body), false, false, false);
2735
2736    set_datatype_feature(true);
2737    get_object_w_datatype("myjson", body, strlen(body), false, true, false);
2738
2739    return TEST_PASS;
2740}
2741
2742static enum test_return test_binary_datatype_compressed(void) {
2743    const char inflated[] = "aaaaaaaaabbbbbbbccccccdddddd";
2744    size_t inflated_len = strlen(inflated);
2745    char deflated[256];
2746    size_t deflated_len = 256;
2747    snappy_status status;
2748
2749    status = snappy_compress(inflated, inflated_len,
2750                             deflated, &deflated_len);
2751
2752    if (status != SNAPPY_OK) {
2753        fprintf(stderr, "Failed to compress data\n");
2754        abort();
2755    }
2756
2757    set_datatype_feature(true);
2758    store_object_w_datatype("mycompressed", deflated, deflated_len,
2759                            true, false);
2760
2761    get_object_w_datatype("mycompressed", deflated, deflated_len,
2762                          true, false, false);
2763
2764    set_datatype_feature(false);
2765    get_object_w_datatype("mycompressed", inflated, inflated_len,
2766                          true, false, true);
2767
2768    return TEST_PASS;
2769}
2770
2771static enum test_return test_binary_datatype_compressed_json(void) {
2772    const char inflated[] = "{ \"value\" : \"aaaaaaaaabbbbbbbccccccdddddd\" }";
2773    size_t inflated_len = strlen(inflated);
2774    char deflated[256];
2775    size_t deflated_len = 256;
2776    snappy_status status;
2777
2778    status = snappy_compress(inflated, inflated_len,
2779                             deflated, &deflated_len);
2780
2781    if (status != SNAPPY_OK) {
2782        fprintf(stderr, "Failed to compress data\n");
2783        abort();
2784    }
2785
2786    set_datatype_feature(true);
2787    store_object_w_datatype("mycompressedjson", deflated, deflated_len,
2788                            true, true);
2789
2790    get_object_w_datatype("mycompressedjson", deflated, deflated_len,
2791                          true, true, false);
2792
2793    set_datatype_feature(false);
2794    get_object_w_datatype("mycompressedjson", inflated, inflated_len,
2795                          true, true, true);
2796
2797    return TEST_PASS;
2798}
2799
2800static enum test_return test_binary_invalid_datatype(void) {
2801    protocol_binary_request_no_extras request;
2802    union {
2803        protocol_binary_response_no_extras response;
2804        char buffer[1024];
2805    } res;
2806    uint16_t code;
2807
2808    set_datatype_feature(false);
2809
2810    memset(request.bytes, 0, sizeof(request));
2811    request.message.header.request.magic = PROTOCOL_BINARY_REQ;
2812    request.message.header.request.opcode = PROTOCOL_BINARY_CMD_NOOP;
2813    request.message.header.request.datatype = 1;
2814
2815    safe_send(&request.bytes, sizeof(request.bytes), false);
2816    safe_recv_packet(res.buffer, sizeof(res.buffer));
2817
2818    code = res.response.message.header.response.status;
2819    cb_assert(code == PROTOCOL_BINARY_RESPONSE_EINVAL);
2820
2821    reconnect_to_server("127.0.0.1", false);
2822
2823    set_datatype_feature(false);
2824    request.message.header.request.datatype = 4;
2825    safe_send(&request.bytes, sizeof(request.bytes), false);
2826    safe_recv_packet(res.buffer, sizeof(res.buffer));
2827    code = res.response.message.header.response.status;
2828    cb_assert(code == PROTOCOL_BINARY_RESPONSE_EINVAL);
2829
2830    reconnect_to_server("127.0.0.1", false);
2831
2832    return TEST_PASS;
2833}
2834
2835static uint64_t get_session_ctrl_token(void) {
2836    union {
2837        protocol_binary_request_get_ctrl_token request;
2838        protocol_binary_response_get_ctrl_token response;
2839        char bytes[1024];
2840    } buffer;
2841    uint64_t ret;
2842
2843    memset(buffer.bytes, 0, sizeof(buffer));
2844    buffer.request.message.header.request.magic = PROTOCOL_BINARY_REQ;
2845    buffer.request.message.header.request.opcode = PROTOCOL_BINARY_CMD_GET_CTRL_TOKEN;
2846
2847    safe_send(buffer.bytes, sizeof(buffer.request), false);
2848    safe_recv_packet(&buffer.response, sizeof(buffer.bytes));
2849
2850    cb_assert(htons(buffer.response.message.header.response.status) ==
2851                PROTOCOL_BINARY_RESPONSE_SUCCESS);
2852
2853    ret = ntohll(buffer.response.message.header.response.cas);
2854    cb_assert(ret != 0);
2855
2856    return ret;
2857}
2858
2859static void prepare_set_session_ctrl_token(protocol_binary_request_set_ctrl_token *req,
2860                                           uint64_t old, uint64_t new)
2861{
2862    memset(req, 0, sizeof(*req));
2863    req->message.header.request.magic = PROTOCOL_BINARY_REQ;
2864    req->message.header.request.opcode = PROTOCOL_BINARY_CMD_SET_CTRL_TOKEN;
2865    req->message.header.request.extlen = sizeof(uint64_t);
2866    req->message.header.request.bodylen = htonl(sizeof(uint64_t));
2867    req->message.header.request.cas = htonll(old);
2868    req->message.body.new_cas = htonll(new);
2869}
2870
2871static enum test_return test_session_ctrl_token(void) {
2872    union {
2873        protocol_binary_request_set_ctrl_token request;
2874        protocol_binary_response_set_ctrl_token response;
2875        char bytes[1024];
2876    } buffer;
2877
2878    uint64_t old_token = get_session_ctrl_token();
2879    uint64_t new_token = 0x0102030405060708;
2880
2881    /* Validate that you may successfully set the token to a legal value */
2882    prepare_set_session_ctrl_token(&buffer.request, old_token, new_token);
2883    safe_send(buffer.bytes, sizeof(buffer.request), false);
2884    cb_assert(safe_recv_packet(&buffer.response, sizeof(buffer.bytes)));
2885
2886    cb_assert(buffer.response.message.header.response.status ==
2887              PROTOCOL_BINARY_RESPONSE_SUCCESS);
2888    cb_assert(new_token == ntohll(buffer.response.message.header.response.cas));
2889    old_token = new_token;
2890
2891    /* Validate that you can't set it to 0 */
2892    prepare_set_session_ctrl_token(&buffer.request, old_token, 0);
2893    safe_send(buffer.bytes, sizeof(buffer.request), false);
2894    cb_assert(safe_recv_packet(&buffer.response, sizeof(buffer.bytes)));
2895    cb_assert(buffer.response.message.header.response.status ==
2896              PROTOCOL_BINARY_RESPONSE_EINVAL);
2897    cb_assert(old_token == get_session_ctrl_token());
2898
2899    /* Validate that you can't set it by providing an incorrect cas */
2900    prepare_set_session_ctrl_token(&buffer.request, old_token + 1, new_token - 1);
2901    safe_send(buffer.bytes, sizeof(buffer.request), false);
2902    cb_assert(safe_recv_packet(&buffer.response, sizeof(buffer.bytes)));
2903
2904    cb_assert(buffer.response.message.header.response.status ==
2905              PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
2906    cb_assert(new_token == ntohll(buffer.response.message.header.response.cas));
2907    cb_assert(new_token == get_session_ctrl_token());
2908
2909    /* Validate that you may set it by overriding the cas with 0 */
2910    prepare_set_session_ctrl_token(&buffer.request, 0, 0xdeadbeef);
2911    safe_send(buffer.bytes, sizeof(buffer.request), false);
2912    cb_assert(safe_recv_packet(&buffer.response, sizeof(buffer.bytes)));
2913    cb_assert(buffer.response.message.header.response.status ==
2914              PROTOCOL_BINARY_RESPONSE_SUCCESS);
2915    cb_assert(0xdeadbeef == ntohll(buffer.response.message.header.response.cas));
2916    cb_assert(0xdeadbeef == get_session_ctrl_token());
2917
2918    return TEST_PASS;
2919}
2920
2921static enum test_return test_mb_10114(void) {
2922    char buffer[512];
2923    const char *key = "mb-10114";
2924    union {
2925        protocol_binary_request_no_extras request;
2926        protocol_binary_response_no_extras response;
2927        char bytes[1024];
2928    } send, receive;
2929    size_t len;
2930
2931