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