1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 #include "config.h"
3 #undef NDEBUG
4 #include <pthread.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <sys/wait.h>
8 #include <netdb.h>
9 #include <arpa/inet.h>
10 #include <netinet/in.h>
11 #include <netinet/tcp.h>
12 #include <signal.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <assert.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <netinet/in.h>
20 #include <fcntl.h>
21 #include <ctype.h>
22 
23 #include "cache.h"
24 #include <memcached/util.h>
25 #include <memcached/protocol_binary.h>
26 #include <memcached/config_parser.h>
27 
28 #define TMP_TEMPLATE "/tmp/test_file.XXXXXXX"
29 
30 enum test_return { TEST_SKIP, TEST_PASS, TEST_FAIL };
31 
32 static pid_t server_pid;
33 static in_port_t port;
34 static int sock;
35 static bool allow_closed_read = false;
36 
cache_create_test(void)37 static enum test_return cache_create_test(void)
38 {
39     cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
40                                   NULL, NULL);
41     assert(cache != NULL);
42     cache_destroy(cache);
43     return TEST_PASS;
44 }
45 
46 const uint64_t constructor_pattern = 0xdeadcafebabebeef;
47 
cache_constructor(void * buffer,void * notused1,int notused2)48 static int cache_constructor(void *buffer, void *notused1, int notused2) {
49     uint64_t *ptr = buffer;
50     *ptr = constructor_pattern;
51     return 0;
52 }
53 
cache_constructor_test(void)54 static enum test_return cache_constructor_test(void)
55 {
56     cache_t *cache = cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
57                                   cache_constructor, NULL);
58     assert(cache != NULL);
59     uint64_t *ptr = cache_alloc(cache);
60     uint64_t pattern = *ptr;
61     cache_free(cache, ptr);
62     cache_destroy(cache);
63     return (pattern == constructor_pattern) ? TEST_PASS : TEST_FAIL;
64 }
65 
cache_fail_constructor(void * buffer,void * notused1,int notused2)66 static int cache_fail_constructor(void *buffer, void *notused1, int notused2) {
67     return 1;
68 }
69 
cache_fail_constructor_test(void)70 static enum test_return cache_fail_constructor_test(void)
71 {
72     enum test_return ret = TEST_PASS;
73 
74     cache_t *cache = cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
75                                   cache_fail_constructor, NULL);
76     assert(cache != NULL);
77     uint64_t *ptr = cache_alloc(cache);
78     if (ptr != NULL) {
79         ret = TEST_FAIL;
80     }
81     cache_destroy(cache);
82     return ret;
83 }
84 
85 static void *destruct_data = 0;
86 
cache_destructor(void * buffer,void * notused)87 static void cache_destructor(void *buffer, void *notused) {
88     destruct_data = buffer;
89 }
90 
cache_destructor_test(void)91 static enum test_return cache_destructor_test(void)
92 {
93     cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
94                                   NULL, cache_destructor);
95     assert(cache != NULL);
96     char *ptr = cache_alloc(cache);
97     cache_free(cache, ptr);
98     cache_destroy(cache);
99 
100     return (ptr == destruct_data) ? TEST_PASS : TEST_FAIL;
101 }
102 
cache_reuse_test(void)103 static enum test_return cache_reuse_test(void)
104 {
105     int ii;
106     cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
107                                   NULL, NULL);
108     char *ptr = cache_alloc(cache);
109     cache_free(cache, ptr);
110     for (ii = 0; ii < 100; ++ii) {
111         char *p = cache_alloc(cache);
112         assert(p == ptr);
113         cache_free(cache, ptr);
114     }
115     cache_destroy(cache);
116     return TEST_PASS;
117 }
118 
119 
cache_bulkalloc(size_t datasize)120 static enum test_return cache_bulkalloc(size_t datasize)
121 {
122     cache_t *cache = cache_create("test", datasize, sizeof(char*),
123                                   NULL, NULL);
124 #define ITERATIONS 1024
125     void *ptr[ITERATIONS];
126 
127     for (int ii = 0; ii < ITERATIONS; ++ii) {
128         ptr[ii] = cache_alloc(cache);
129         assert(ptr[ii] != 0);
130         memset(ptr[ii], 0xff, datasize);
131     }
132 
133     for (int ii = 0; ii < ITERATIONS; ++ii) {
134         cache_free(cache, ptr[ii]);
135     }
136 
137 #undef ITERATIONS
138     cache_destroy(cache);
139     return TEST_PASS;
140 }
141 
test_issue_161(void)142 static enum test_return test_issue_161(void)
143 {
144     enum test_return ret = cache_bulkalloc(1);
145     if (ret == TEST_PASS) {
146         ret = cache_bulkalloc(512);
147     }
148 
149     return ret;
150 }
151 
cache_redzone_test(void)152 static enum test_return cache_redzone_test(void)
153 {
154 #ifndef HAVE_UMEM_H
155     cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
156                                   NULL, NULL);
157 
158     /* Ignore SIGABORT */
159     struct sigaction old_action;
160     struct sigaction action = { .sa_handler = SIG_IGN, .sa_flags = 0};
161     sigemptyset(&action.sa_mask);
162     sigaction(SIGABRT, &action, &old_action);
163 
164     /* check memory debug.. */
165     char *p = cache_alloc(cache);
166     char old = *(p - 1);
167     *(p - 1) = 0;
168     cache_free(cache, p);
169     assert(cache_error == -1);
170     *(p - 1) = old;
171 
172     p[sizeof(uint32_t)] = 0;
173     cache_free(cache, p);
174     assert(cache_error == 1);
175 
176     /* restore signal handler */
177     sigaction(SIGABRT, &old_action, NULL);
178 
179     cache_destroy(cache);
180 
181     return TEST_PASS;
182 #else
183     return TEST_SKIP;
184 #endif
185 }
186 
test_safe_strtoul(void)187 static enum test_return test_safe_strtoul(void) {
188     uint32_t val;
189     assert(safe_strtoul("123", &val));
190     assert(val == 123);
191     assert(safe_strtoul("+123", &val));
192     assert(val == 123);
193     assert(!safe_strtoul("", &val));  // empty
194     assert(!safe_strtoul("123BOGUS", &val));  // non-numeric
195     /* Not sure what it does, but this works with ICC :/
196        assert(!safe_strtoul("92837498237498237498029383", &val)); // out of range
197     */
198 
199     // extremes:
200     assert(safe_strtoul("4294967295", &val)); // 2**32 - 1
201     assert(val == 4294967295L);
202     /* This actually works on 64-bit ubuntu
203        assert(!safe_strtoul("4294967296", &val)); // 2**32
204     */
205     assert(!safe_strtoul("-1", &val));  // negative
206     return TEST_PASS;
207 }
208 
209 
test_safe_strtoull(void)210 static enum test_return test_safe_strtoull(void) {
211     uint64_t val;
212     assert(safe_strtoull("123", &val));
213     assert(val == 123);
214     assert(safe_strtoull("+123", &val));
215     assert(val == 123);
216     assert(!safe_strtoull("", &val));  // empty
217     assert(!safe_strtoull("123BOGUS", &val));  // non-numeric
218     assert(!safe_strtoull("92837498237498237498029383", &val)); // out of range
219 
220     // extremes:
221     assert(safe_strtoull("18446744073709551615", &val)); // 2**64 - 1
222     assert(val == 18446744073709551615ULL);
223     assert(!safe_strtoull("18446744073709551616", &val)); // 2**64
224     assert(!safe_strtoull("-1", &val));  // negative
225     return TEST_PASS;
226 }
227 
test_safe_strtoll(void)228 static enum test_return test_safe_strtoll(void) {
229     int64_t val;
230     assert(safe_strtoll("123", &val));
231     assert(val == 123);
232     assert(safe_strtoll("+123", &val));
233     assert(val == 123);
234     assert(safe_strtoll("-123", &val));
235     assert(val == -123);
236     assert(!safe_strtoll("", &val));  // empty
237     assert(!safe_strtoll("123BOGUS", &val));  // non-numeric
238     assert(!safe_strtoll("92837498237498237498029383", &val)); // out of range
239 
240     // extremes:
241     assert(!safe_strtoll("18446744073709551615", &val)); // 2**64 - 1
242     assert(safe_strtoll("9223372036854775807", &val)); // 2**63 - 1
243     assert(val == 9223372036854775807LL);
244     /*
245       assert(safe_strtoll("-9223372036854775808", &val)); // -2**63
246       assert(val == -9223372036854775808LL);
247     */
248     assert(!safe_strtoll("-9223372036854775809", &val)); // -2**63 - 1
249 
250     // We'll allow space to terminate the string.  And leading space.
251     assert(safe_strtoll(" 123 foo", &val));
252     assert(val == 123);
253     return TEST_PASS;
254 }
255 
test_safe_strtol(void)256 static enum test_return test_safe_strtol(void) {
257     int32_t val;
258     assert(safe_strtol("123", &val));
259     assert(val == 123);
260     assert(safe_strtol("+123", &val));
261     assert(val == 123);
262     assert(safe_strtol("-123", &val));
263     assert(val == -123);
264     assert(!safe_strtol("", &val));  // empty
265     assert(!safe_strtol("123BOGUS", &val));  // non-numeric
266     assert(!safe_strtol("92837498237498237498029383", &val)); // out of range
267 
268     // extremes:
269     /* This actually works on 64-bit ubuntu
270        assert(!safe_strtol("2147483648", &val)); // (expt 2.0 31.0)
271     */
272     assert(safe_strtol("2147483647", &val)); // (- (expt 2.0 31) 1)
273     assert(val == 2147483647L);
274     /* This actually works on 64-bit ubuntu
275        assert(!safe_strtol("-2147483649", &val)); // (- (expt -2.0 31) 1)
276     */
277 
278     // We'll allow space to terminate the string.  And leading space.
279     assert(safe_strtol(" 123 foo", &val));
280     assert(val == 123);
281     return TEST_PASS;
282 }
283 
test_safe_strtof(void)284 static enum test_return test_safe_strtof(void) {
285     float val;
286     assert(safe_strtof("123", &val));
287     assert(val == 123.00f);
288     assert(safe_strtof("+123", &val));
289     assert(val == 123.00f);
290     assert(safe_strtof("-123", &val));
291     assert(val == -123.00f);
292     assert(!safe_strtof("", &val));  // empty
293     assert(!safe_strtof("123BOGUS", &val));  // non-numeric
294 
295     // We'll allow space to terminate the string.  And leading space.
296     assert(safe_strtof(" 123 foo", &val));
297     assert(val == 123.00f);
298 
299     assert(safe_strtof("123.23", &val));
300     assert(val == 123.23f);
301 
302     assert(safe_strtof("123.00", &val));
303     assert(val == 123.00f);
304 
305     return TEST_PASS;
306 }
307 
308 /**
309  * Function to start the server and let it listen on a random port
310  *
311  * @param port_out where to store the TCP port number the server is
312  *                 listening on
313  * @param daemon set to true if you want to run the memcached server
314  *               as a daemon process
315  * @return the pid of the memcached server
316  */
start_server(in_port_t * port_out,bool daemon,int timeout)317 static pid_t start_server(in_port_t *port_out, bool daemon, int timeout) {
318     char environment[80];
319     snprintf(environment, sizeof(environment),
320              "MEMCACHED_PORT_FILENAME=/tmp/ports.%lu", (long)getpid());
321     char *filename= environment + strlen("MEMCACHED_PORT_FILENAME=");
322     char pid_file[80];
323     snprintf(pid_file, sizeof(pid_file), "/tmp/pid.%lu", (long)getpid());
324 
325     remove(filename);
326     remove(pid_file);
327 
328     char engine[1024];
329     assert(getcwd(engine, sizeof(engine)));
330     strcat(engine, "/.libs/default_engine.so");
331     assert(strlen(engine) < sizeof(engine));
332 
333     char blackhole[1024];
334     assert(getcwd(blackhole, sizeof(blackhole)));
335     strcat(blackhole, "/.libs/blackhole_logger.so");
336 
337 
338 #ifdef __sun
339     /* I want to name the corefiles differently so that they don't
340        overwrite each other
341     */
342     char coreadm[128];
343     snprintf(coreadm, sizeof(coreadm),
344              "coreadm -p core.%%f.%%p %lu", (unsigned long)getpid());
345     system(coreadm);
346 #endif
347 
348     pid_t pid = fork();
349     assert(pid != -1);
350 
351     if (pid == 0) {
352         /* Child */
353         char *argv[20];
354         int arg = 0;
355         char tmo[24];
356         snprintf(tmo, sizeof(tmo), "%u", timeout);
357 
358         putenv(environment);
359 
360         if (!daemon) {
361             argv[arg++] = "./timedrun";
362             argv[arg++] = tmo;
363         }
364         argv[arg++] = "./memcached";
365         argv[arg++] = "-E";
366         argv[arg++] = engine;
367         argv[arg++] = "-X";
368         argv[arg++] = blackhole;
369         argv[arg++] = "-p";
370         argv[arg++] = "-1";
371         argv[arg++] = "-U";
372         argv[arg++] = "0";
373         /* Handle rpmbuild and the like doing this as root */
374         if (getuid() == 0) {
375             argv[arg++] = "-u";
376             argv[arg++] = "root";
377         }
378         if (daemon) {
379             argv[arg++] = "-d";
380             argv[arg++] = "-P";
381             argv[arg++] = pid_file;
382         }
383 #ifdef MESSAGE_DEBUG
384          argv[arg++] = "-vvv";
385 #endif
386         argv[arg++] = NULL;
387         assert(execv(argv[0], argv) != -1);
388     }
389 
390     /* Yeah just let us "busy-wait" for the file to be created ;-) */
391     while (access(filename, F_OK) == -1) {
392         usleep(10);
393     }
394 
395     FILE *fp = fopen(filename, "r");
396     if (fp == NULL) {
397         fprintf(stderr, "Failed to open the file containing port numbers: %s\n",
398                 strerror(errno));
399         assert(false);
400     }
401 
402     *port_out = (in_port_t)-1;
403     char buffer[80];
404     while ((fgets(buffer, sizeof(buffer), fp)) != NULL) {
405         if (strncmp(buffer, "TCP INET: ", 10) == 0) {
406             int32_t val;
407             assert(safe_strtol(buffer + 10, &val));
408             *port_out = (in_port_t)val;
409         }
410     }
411     fclose(fp);
412     assert(remove(filename) == 0);
413 
414     if (daemon) {
415         /* loop and wait for the pid file.. There is a potential race
416          * condition that the server just created the file but isn't
417          * finished writing the content, but I'll take the chance....
418          */
419         while (access(pid_file, F_OK) == -1) {
420             usleep(10);
421         }
422 
423         fp = fopen(pid_file, "r");
424         if (fp == NULL) {
425             fprintf(stderr, "Failed to open pid file: %s\n",
426                     strerror(errno));
427             assert(false);
428         }
429         assert(fgets(buffer, sizeof(buffer), fp) != NULL);
430         fclose(fp);
431 
432         int32_t val;
433         assert(safe_strtol(buffer, &val));
434         pid = (pid_t)val;
435     }
436 
437     return pid;
438 }
439 
test_issue_44(void)440 static enum test_return test_issue_44(void) {
441     in_port_t port;
442     pid_t pid = start_server(&port, true, 15);
443     assert(kill(pid, SIGHUP) == 0);
444     sleep(1);
445     assert(kill(pid, SIGTERM) == 0);
446 
447     return TEST_PASS;
448 }
449 
lookuphost(const char * hostname,in_port_t port)450 static struct addrinfo *lookuphost(const char *hostname, in_port_t port)
451 {
452     struct addrinfo *ai = 0;
453     struct addrinfo hints = { .ai_family = AF_UNSPEC,
454                               .ai_protocol = IPPROTO_TCP,
455                               .ai_socktype = SOCK_STREAM };
456     char service[NI_MAXSERV];
457     int error;
458 
459     (void)snprintf(service, NI_MAXSERV, "%d", port);
460     if ((error = getaddrinfo(hostname, service, &hints, &ai)) != 0) {
461        if (error != EAI_SYSTEM) {
462           fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
463        } else {
464           perror("getaddrinfo()");
465        }
466     }
467 
468     return ai;
469 }
470 
connect_server(const char * hostname,in_port_t port,bool nonblock)471 static int connect_server(const char *hostname, in_port_t port, bool nonblock)
472 {
473     struct addrinfo *ai = lookuphost(hostname, port);
474     int sock = -1;
475     if (ai != NULL) {
476        if ((sock = socket(ai->ai_family, ai->ai_socktype,
477                           ai->ai_protocol)) != -1) {
478           if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
479              fprintf(stderr, "Failed to connect socket: %s\n",
480                      strerror(errno));
481              close(sock);
482              sock = -1;
483           } else if (nonblock) {
484               int flags = fcntl(sock, F_GETFL, 0);
485               if (flags < 0 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {
486                   fprintf(stderr, "Failed to enable nonblocking mode: %s\n",
487                           strerror(errno));
488                   close(sock);
489                   sock = -1;
490               }
491           }
492        } else {
493           fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
494        }
495 
496        freeaddrinfo(ai);
497     }
498     return sock;
499 }
500 
test_vperror(void)501 static enum test_return test_vperror(void) {
502     int rv = 0;
503     int oldstderr = dup(STDERR_FILENO);
504     char tmpl[sizeof(TMP_TEMPLATE)+1];
505     strncpy(tmpl, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
506 
507     int newfile = mkstemp(tmpl);
508     assert(newfile > 0);
509     rv = dup2(newfile, STDERR_FILENO);
510     assert(rv == STDERR_FILENO);
511     rv = close(newfile);
512     assert(rv == 0);
513 
514     errno = EIO;
515     vperror("Old McDonald had a farm.  %s", "EI EIO");
516 
517     /* Restore stderr */
518     rv = dup2(oldstderr, STDERR_FILENO);
519     assert(rv == STDERR_FILENO);
520 
521 
522     /* Go read the file */
523     char buf[80] = { 0 };
524     FILE *efile = fopen(tmpl, "r");
525     assert(efile);
526     char *prv = fgets(buf, sizeof(buf), efile);
527     assert(prv);
528     fclose(efile);
529 
530     unlink(tmpl);
531 
532     char expected[80] = { 0 };
533     snprintf(expected, sizeof(expected),
534              "Old McDonald had a farm.  EI EIO: %s\n", strerror(EIO));
535 
536     /*
537     fprintf(stderr,
538             "\nExpected:  ``%s''"
539             "\nGot:       ``%s''\n", expected, buf);
540     */
541 
542     return strcmp(expected, buf) == 0 ? TEST_PASS : TEST_FAIL;
543 }
544 
trim(char * ptr)545 static char* trim(char* ptr) {
546     char *start = ptr;
547     while (isspace(*start)) {
548         ++start;
549     }
550     char *end = start + strlen(start) - 1;
551     if (end != start) {
552         while (isspace(*end)) {
553             *end = '\0';
554             --end;
555         }
556     }
557     return start;
558 }
559 
test_config_parser(void)560 static enum test_return test_config_parser(void) {
561     bool bool_val = false;
562     size_t size_val = 0;
563     float float_val = 0;
564     char *string_val = 0;
565 
566     /* Set up the different items I can handle */
567     struct config_item items[] = {
568         { .key = "bool",
569           .datatype = DT_BOOL,
570           .value.dt_bool = &bool_val },
571         { .key = "size_t",
572           .datatype = DT_SIZE,
573           .value.dt_size = &size_val },
574         { .key = "float",
575           .datatype = DT_FLOAT,
576           .value.dt_float = &float_val},
577         { .key = "string",
578           .datatype = DT_STRING,
579           .value.dt_string = &string_val},
580         { .key = "config_file",
581           .datatype = DT_CONFIGFILE },
582         { .key = NULL}
583     };
584 
585     char outfile[sizeof(TMP_TEMPLATE)+1];
586     strncpy(outfile, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
587     char cfgfile[sizeof(TMP_TEMPLATE)+1];
588     strncpy(cfgfile, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
589 
590     int newfile = mkstemp(outfile);
591     assert(newfile > 0);
592     FILE *error = fdopen(newfile, "w");
593 
594     assert(error != NULL);
595     assert(parse_config("", items, error) == 0);
596     /* Nothing should be found */
597     for (int ii = 0; ii < 5; ++ii) {
598         assert(!items[0].found);
599     }
600 
601     assert(parse_config("bool=true", items, error) == 0);
602     assert(bool_val);
603     /* only bool should be found */
604     assert(items[0].found);
605     items[0].found = false;
606     for (int ii = 0; ii < 5; ++ii) {
607         assert(!items[0].found);
608     }
609 
610     /* It should allow illegal keywords */
611     assert(parse_config("pacman=dead", items, error) == 1);
612     /* and illegal values */
613     assert(parse_config("bool=12", items, error) == -1);
614     assert(!items[0].found);
615     /* and multiple occurences of the same value */
616     assert(parse_config("size_t=1; size_t=1024", items, error) == 0);
617     assert(items[1].found);
618     assert(size_val == 1024);
619     items[1].found = false;
620 
621     /* Empty string */
622     /* XXX:  This test fails on Linux, but works on OS X.
623     assert(parse_config("string=", items, error) == 0);
624     assert(items[3].found);
625     assert(strcmp(string_val, "") == 0);
626     items[3].found = false;
627     */
628     /* Plain string */
629     assert(parse_config("string=sval", items, error) == 0);
630     assert(items[3].found);
631     assert(strcmp(string_val, "sval") == 0);
632     items[3].found = false;
633     /* Leading space */
634     assert(parse_config("string= sval", items, error) == 0);
635     assert(items[3].found);
636     assert(strcmp(string_val, "sval") == 0);
637     items[3].found = false;
638     /* Escaped leading space */
639     assert(parse_config("string=\\ sval", items, error) == 0);
640     assert(items[3].found);
641     assert(strcmp(string_val, " sval") == 0);
642     items[3].found = false;
643     /* trailing space */
644     assert(parse_config("string=sval ", items, error) == 0);
645     assert(items[3].found);
646     assert(strcmp(string_val, "sval") == 0);
647     items[3].found = false;
648     /* escaped trailing space */
649     assert(parse_config("string=sval\\ ", items, error) == 0);
650     assert(items[3].found);
651     assert(strcmp(string_val, "sval ") == 0);
652     items[3].found = false;
653     /* escaped stop char */
654     assert(parse_config("string=sval\\;blah=x", items, error) == 0);
655     assert(items[3].found);
656     assert(strcmp(string_val, "sval;blah=x") == 0);
657     items[3].found = false;
658     /* middle space */
659     assert(parse_config("string=s val", items, error) == 0);
660     assert(items[3].found);
661     assert(strcmp(string_val, "s val") == 0);
662     items[3].found = false;
663 
664     /* And all of the variables */
665     assert(parse_config("bool=true;size_t=1024;float=12.5;string=somestr",
666                         items, error) == 0);
667     assert(bool_val);
668     assert(size_val == 1024);
669     assert(float_val == 12.5f);
670     assert(strcmp(string_val, "somestr") == 0);
671     for (int ii = 0; ii < 5; ++ii) {
672         items[ii].found = false;
673     }
674 
675     assert(parse_config("size_t=1k", items, error) == 0);
676     assert(items[1].found);
677     assert(size_val == 1024);
678     items[1].found = false;
679     assert(parse_config("size_t=1m", items, error) == 0);
680     assert(items[1].found);
681     assert(size_val == 1024*1024);
682     items[1].found = false;
683     assert(parse_config("size_t=1g", items, error) == 0);
684     assert(items[1].found);
685     assert(size_val == 1024*1024*1024);
686     items[1].found = false;
687     assert(parse_config("size_t=1K", items, error) == 0);
688     assert(items[1].found);
689     assert(size_val == 1024);
690     items[1].found = false;
691     assert(parse_config("size_t=1M", items, error) == 0);
692     assert(items[1].found);
693     assert(size_val == 1024*1024);
694     items[1].found = false;
695     assert(parse_config("size_t=1G", items, error) == 0);
696     assert(items[1].found);
697     assert(size_val == 1024*1024*1024);
698     items[1].found = false;
699 
700     newfile = mkstemp(cfgfile);
701     assert(newfile > 0);
702     FILE *cfg = fdopen(newfile, "w");
703     assert(cfg != NULL);
704     fprintf(cfg, "# This is a config file\nbool=true\nsize_t=1023\nfloat=12.4\n");
705     fclose(cfg);
706     char buffer[1024];
707     sprintf(buffer, "config_file=%s", cfgfile);
708     assert(parse_config(buffer, items, error) == 0);
709     assert(bool_val);
710     assert(size_val == 1023);
711     assert(float_val == 12.4f);
712     fclose(error);
713 
714     remove(cfgfile);
715     /* Verify that I received the error messages ;-) */
716     error = fopen(outfile, "r");
717     assert(error);
718 
719     assert(fgets(buffer, sizeof(buffer), error));
720     assert(strcmp("Unsupported key: <pacman>", trim(buffer)) == 0);
721     assert(fgets(buffer, sizeof(buffer), error));
722     assert(strcmp("Invalid entry, Key: <bool> Value: <12>", trim(buffer)) == 0);
723     assert(fgets(buffer, sizeof(buffer), error));
724     assert(strcmp("WARNING: Found duplicate entry for \"size_t\"", trim(buffer)) == 0);
725     assert(fgets(buffer, sizeof(buffer), error) == NULL);
726 
727     remove(outfile);
728     return TEST_PASS;
729 }
730 
send_ascii_command(const char * buf)731 static void send_ascii_command(const char *buf) {
732     off_t offset = 0;
733     const char* ptr = buf;
734     size_t len = strlen(buf);
735 
736     do {
737         ssize_t nw = send(sock, ptr + offset, len - offset, 0);
738         if (nw == -1) {
739             if (errno != EINTR) {
740                 fprintf(stderr, "Failed to write: %s\n", strerror(errno));
741                 abort();
742             }
743         } else {
744             offset += nw;
745         }
746     } while (offset < len);
747 }
748 
749 /*
750  * This is a dead slow single byte read, but it should only read out
751  * _one_ response and I don't have an input buffer... The current
752  * implementation only supports single-line responses, so if you want to use
753  * it for get commands you need to implement that first ;-)
754  */
read_ascii_response(char * buffer,size_t size)755 static void read_ascii_response(char *buffer, size_t size) {
756     off_t offset = 0;
757     bool need_more = true;
758     do {
759         ssize_t nr = recv(sock, buffer + offset, 1, 0);
760         if (nr == -1) {
761             if (errno != EINTR) {
762                 fprintf(stderr, "Failed to read: %s\n", strerror(errno));
763                 abort();
764             }
765         } else {
766             assert(nr == 1);
767             if (buffer[offset] == '\n') {
768                 need_more = false;
769                 buffer[offset + 1] = '\0';
770             }
771             offset += nr;
772             assert(offset + 1 < size);
773         }
774     } while (need_more);
775 }
776 
test_issue_92(void)777 static enum test_return test_issue_92(void) {
778 #ifdef FUTURE
779     char buffer[1024];
780 
781     close(sock);
782     sock = connect_server("127.0.0.1", port, false);
783 
784     send_ascii_command("stats cachedump 1 0 0\r\n");
785     read_ascii_response(buffer, sizeof(buffer));
786     assert(strncmp(buffer, "END", strlen("END")) == 0);
787 
788     send_ascii_command("stats cachedump 200 0 0\r\n");
789     read_ascii_response(buffer, sizeof(buffer));
790     assert(strncmp(buffer, "CLIENT_ERROR", strlen("CLIENT_ERROR")) == 0);
791 
792     close(sock);
793     sock = connect_server("127.0.0.1", port, false);
794 #endif
795 
796     return TEST_PASS;
797 }
798 
test_issue_102(void)799 static enum test_return test_issue_102(void) {
800     char buffer[4096];
801     memset(buffer, ' ', sizeof(buffer));
802     buffer[sizeof(buffer) - 1] = '\0';
803 
804     close(sock);
805     sock = connect_server("127.0.0.1", port, false);
806 
807     send_ascii_command(buffer);
808     /* verify that the server closed the connection */
809     assert(recv(sock, buffer, sizeof(buffer), 0) == 0);
810     close(sock);
811     sock = connect_server("127.0.0.1", port, false);
812 
813     snprintf(buffer, sizeof(buffer), "gets ");
814     size_t offset = 5;
815     while (offset < 4000) {
816         offset += snprintf(buffer + offset, sizeof(buffer) - offset,
817                            "%010u ", (unsigned int)offset);
818     }
819 
820     send_ascii_command(buffer);
821     usleep(250);
822 
823     send_ascii_command("\r\n");
824     char rsp[80];
825     read_ascii_response(rsp, sizeof(rsp));
826     assert(strncmp(rsp, "END", strlen("END")) == 0);
827     buffer[3]= ' ';
828     send_ascii_command(buffer);
829     usleep(250);
830     send_ascii_command("\r\n");
831     read_ascii_response(rsp, sizeof(rsp));
832     assert(strncmp(rsp, "END", strlen("END")) == 0);
833 
834     memset(buffer, ' ', sizeof(buffer));
835     int len = snprintf(buffer + 101, sizeof(buffer) - 101, "gets foo");
836     buffer[101 + len] = ' ';
837     buffer[sizeof(buffer) - 1] = '\0';
838     send_ascii_command(buffer);
839     /* verify that the server closed the connection */
840     assert(recv(sock, buffer, sizeof(buffer), 0) == 0);
841 
842     close(sock);
843     sock = connect_server("127.0.0.1", port, false);
844 
845     return TEST_PASS;
846 }
847 
start_memcached_server(void)848 static enum test_return start_memcached_server(void) {
849     server_pid = start_server(&port, false, 600);
850     sock = connect_server("127.0.0.1", port, false);
851 
852     return TEST_PASS;
853 }
854 
stop_memcached_server(void)855 static enum test_return stop_memcached_server(void) {
856     close(sock);
857     assert(kill(server_pid, SIGTERM) == 0);
858     return TEST_PASS;
859 }
860 
safe_send(const void * buf,size_t len,bool hickup)861 static void safe_send(const void* buf, size_t len, bool hickup)
862 {
863     off_t offset = 0;
864     const char* ptr = buf;
865 #ifdef MESSAGE_DEBUG
866     uint8_t val = *ptr;
867     assert(val == (uint8_t)0x80);
868     fprintf(stderr, "About to send %lu bytes:", (unsigned long)len);
869     for (int ii = 0; ii < len; ++ii) {
870         if (ii % 4 == 0) {
871             fprintf(stderr, "\n   ");
872         }
873         val = *(ptr + ii);
874         fprintf(stderr, " 0x%02x", val);
875     }
876     fprintf(stderr, "\n");
877     usleep(500);
878 #endif
879 
880     do {
881         size_t num_bytes = len - offset;
882         if (hickup) {
883             if (num_bytes > 1024) {
884                 num_bytes = (rand() % 1023) + 1;
885             }
886         }
887 
888         ssize_t nw = send(sock, ptr + offset, num_bytes, 0);
889         if (nw == -1) {
890             if (errno != EINTR) {
891                 fprintf(stderr, "Failed to write: %s\n", strerror(errno));
892                 abort();
893             }
894         } else {
895             if (hickup) {
896                 usleep(100);
897             }
898             offset += nw;
899         }
900     } while (offset < len);
901 }
902 
safe_recv(void * buf,size_t len)903 static bool safe_recv(void *buf, size_t len) {
904     if (len == 0) {
905         return true;
906     }
907     off_t offset = 0;
908     do {
909         ssize_t nr = recv(sock, ((char*)buf) + offset, len - offset, 0);
910         if (nr == -1) {
911             if (errno != EINTR) {
912                 fprintf(stderr, "Failed to read: %s\n", strerror(errno));
913                 abort();
914             }
915         } else {
916             if (nr == 0 && allow_closed_read) {
917                 return false;
918             }
919             assert(nr != 0);
920             offset += nr;
921         }
922     } while (offset < len);
923 
924     return true;
925 }
926 
safe_recv_packet(void * buf,size_t size)927 static bool safe_recv_packet(void *buf, size_t size) {
928     protocol_binary_response_no_extras *response = buf;
929     assert(size > sizeof(*response));
930     if (!safe_recv(response, sizeof(*response))) {
931         return false;
932     }
933     response->message.header.response.keylen = ntohs(response->message.header.response.keylen);
934     response->message.header.response.status = ntohs(response->message.header.response.status);
935     response->message.header.response.bodylen = ntohl(response->message.header.response.bodylen);
936 
937     size_t len = sizeof(*response);
938 
939     char *ptr = buf;
940     ptr += len;
941     if (!safe_recv(ptr, response->message.header.response.bodylen)) {
942         return false;
943     }
944 
945 #ifdef MESSAGE_DEBUG
946     usleep(500);
947     ptr = buf;
948     len += response->message.header.response.bodylen;
949     uint8_t val = *ptr;
950     assert(val == (uint8_t)0x81);
951     fprintf(stderr, "Received %lu bytes:", (unsigned long)len);
952     for (int ii = 0; ii < len; ++ii) {
953         if (ii % 4 == 0) {
954             fprintf(stderr, "\n   ");
955         }
956         val = *(ptr + ii);
957         fprintf(stderr, " 0x%02x", val);
958     }
959     fprintf(stderr, "\n");
960 #endif
961     return true;
962 }
963 
storage_command(char * buf,size_t bufsz,uint8_t cmd,const void * key,size_t keylen,const void * dta,size_t dtalen,uint32_t flags,uint32_t exp)964 static off_t storage_command(char*buf,
965                              size_t bufsz,
966                              uint8_t cmd,
967                              const void* key,
968                              size_t keylen,
969                              const void* dta,
970                              size_t dtalen,
971                              uint32_t flags,
972                              uint32_t exp) {
973     /* all of the storage commands use the same command layout */
974     protocol_binary_request_set *request = (void*)buf;
975     assert(bufsz > sizeof(*request) + keylen + dtalen);
976 
977     memset(request, 0, sizeof(*request));
978     request->message.header.request.magic = PROTOCOL_BINARY_REQ;
979     request->message.header.request.opcode = cmd;
980     request->message.header.request.keylen = htons(keylen);
981     request->message.header.request.extlen = 8;
982     request->message.header.request.bodylen = htonl(keylen + 8 + dtalen);
983     request->message.header.request.opaque = 0xdeadbeef;
984     request->message.body.flags = flags;
985     request->message.body.expiration = exp;
986 
987     off_t key_offset = sizeof(protocol_binary_request_no_extras) + 8;
988 
989     memcpy(buf + key_offset, key, keylen);
990     if (dta != NULL) {
991         memcpy(buf + key_offset + keylen, dta, dtalen);
992     }
993 
994     return key_offset + keylen + dtalen;
995 }
996 
raw_command(char * buf,size_t bufsz,uint8_t cmd,const void * key,size_t keylen,const void * dta,size_t dtalen)997 static off_t raw_command(char* buf,
998                          size_t bufsz,
999                          uint8_t cmd,
1000                          const void* key,
1001                          size_t keylen,
1002                          const void* dta,
1003                          size_t dtalen) {
1004     /* all of the storage commands use the same command layout */
1005     protocol_binary_request_no_extras *request = (void*)buf;
1006     assert(bufsz > sizeof(*request) + keylen + dtalen);
1007 
1008     memset(request, 0, sizeof(*request));
1009     request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1010     request->message.header.request.opcode = cmd;
1011     request->message.header.request.keylen = htons(keylen);
1012     request->message.header.request.bodylen = htonl(keylen + dtalen);
1013     request->message.header.request.opaque = 0xdeadbeef;
1014 
1015     off_t key_offset = sizeof(protocol_binary_request_no_extras);
1016 
1017     if (key != NULL) {
1018         memcpy(buf + key_offset, key, keylen);
1019     }
1020     if (dta != NULL) {
1021         memcpy(buf + key_offset + keylen, dta, dtalen);
1022     }
1023 
1024     return sizeof(*request) + keylen + dtalen;
1025 }
1026 
flush_command(char * buf,size_t bufsz,uint8_t cmd,uint32_t exptime,bool use_extra)1027 static off_t flush_command(char* buf, size_t bufsz, uint8_t cmd, uint32_t exptime, bool use_extra) {
1028     protocol_binary_request_flush *request = (void*)buf;
1029     assert(bufsz > sizeof(*request));
1030 
1031     memset(request, 0, sizeof(*request));
1032     request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1033     request->message.header.request.opcode = cmd;
1034 
1035     off_t size = sizeof(protocol_binary_request_no_extras);
1036     if (use_extra) {
1037         request->message.header.request.extlen = 4;
1038         request->message.body.expiration = htonl(exptime);
1039         request->message.header.request.bodylen = htonl(4);
1040         size += 4;
1041     }
1042 
1043     request->message.header.request.opaque = 0xdeadbeef;
1044 
1045     return size;
1046 }
1047 
arithmetic_command(char * buf,size_t bufsz,uint8_t cmd,const void * key,size_t keylen,uint64_t delta,uint64_t initial,uint32_t exp)1048 static off_t arithmetic_command(char* buf,
1049                                 size_t bufsz,
1050                                 uint8_t cmd,
1051                                 const void* key,
1052                                 size_t keylen,
1053                                 uint64_t delta,
1054                                 uint64_t initial,
1055                                 uint32_t exp) {
1056     protocol_binary_request_incr *request = (void*)buf;
1057     assert(bufsz > sizeof(*request) + keylen);
1058 
1059     memset(request, 0, sizeof(*request));
1060     request->message.header.request.magic = PROTOCOL_BINARY_REQ;
1061     request->message.header.request.opcode = cmd;
1062     request->message.header.request.keylen = htons(keylen);
1063     request->message.header.request.extlen = 20;
1064     request->message.header.request.bodylen = htonl(keylen + 20);
1065     request->message.header.request.opaque = 0xdeadbeef;
1066     request->message.body.delta = htonll(delta);
1067     request->message.body.initial = htonll(initial);
1068     request->message.body.expiration = htonl(exp);
1069 
1070     off_t key_offset = sizeof(protocol_binary_request_no_extras) + 20;
1071 
1072     memcpy(buf + key_offset, key, keylen);
1073     return key_offset + keylen;
1074 }
1075 
validate_response_header(protocol_binary_response_no_extras * response,uint8_t cmd,uint16_t status)1076 static void validate_response_header(protocol_binary_response_no_extras *response,
1077                                      uint8_t cmd, uint16_t status)
1078 {
1079     assert(response->message.header.response.magic == PROTOCOL_BINARY_RES);
1080     assert(response->message.header.response.opcode == cmd);
1081     assert(response->message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
1082     if (status == PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND) {
1083         if (response->message.header.response.status == PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED) {
1084             response->message.header.response.status = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
1085         }
1086     }
1087     assert(response->message.header.response.status == status);
1088     assert(response->message.header.response.opaque == 0xdeadbeef);
1089 
1090     if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
1091         switch (cmd) {
1092         case PROTOCOL_BINARY_CMD_ADDQ:
1093         case PROTOCOL_BINARY_CMD_APPENDQ:
1094         case PROTOCOL_BINARY_CMD_DECREMENTQ:
1095         case PROTOCOL_BINARY_CMD_DELETEQ:
1096         case PROTOCOL_BINARY_CMD_FLUSHQ:
1097         case PROTOCOL_BINARY_CMD_INCREMENTQ:
1098         case PROTOCOL_BINARY_CMD_PREPENDQ:
1099         case PROTOCOL_BINARY_CMD_QUITQ:
1100         case PROTOCOL_BINARY_CMD_REPLACEQ:
1101         case PROTOCOL_BINARY_CMD_SETQ:
1102             assert("Quiet command shouldn't return on success" == NULL);
1103         default:
1104             break;
1105         }
1106 
1107         switch (cmd) {
1108         case PROTOCOL_BINARY_CMD_ADD:
1109         case PROTOCOL_BINARY_CMD_REPLACE:
1110         case PROTOCOL_BINARY_CMD_SET:
1111         case PROTOCOL_BINARY_CMD_APPEND:
1112         case PROTOCOL_BINARY_CMD_PREPEND:
1113             assert(response->message.header.response.keylen == 0);
1114             assert(response->message.header.response.extlen == 0);
1115             assert(response->message.header.response.bodylen == 0);
1116             assert(response->message.header.response.cas != 0);
1117             break;
1118         case PROTOCOL_BINARY_CMD_FLUSH:
1119         case PROTOCOL_BINARY_CMD_NOOP:
1120         case PROTOCOL_BINARY_CMD_QUIT:
1121         case PROTOCOL_BINARY_CMD_DELETE:
1122             assert(response->message.header.response.keylen == 0);
1123             assert(response->message.header.response.extlen == 0);
1124             assert(response->message.header.response.bodylen == 0);
1125             assert(response->message.header.response.cas == 0);
1126             break;
1127 
1128         case PROTOCOL_BINARY_CMD_DECREMENT:
1129         case PROTOCOL_BINARY_CMD_INCREMENT:
1130             assert(response->message.header.response.keylen == 0);
1131             assert(response->message.header.response.extlen == 0);
1132             assert(response->message.header.response.bodylen == 8);
1133             assert(response->message.header.response.cas != 0);
1134             break;
1135 
1136         case PROTOCOL_BINARY_CMD_STAT:
1137             assert(response->message.header.response.extlen == 0);
1138             /* key and value exists in all packets except in the terminating */
1139             assert(response->message.header.response.cas == 0);
1140             break;
1141 
1142         case PROTOCOL_BINARY_CMD_VERSION:
1143             assert(response->message.header.response.keylen == 0);
1144             assert(response->message.header.response.extlen == 0);
1145             assert(response->message.header.response.bodylen != 0);
1146             assert(response->message.header.response.cas == 0);
1147             break;
1148 
1149         case PROTOCOL_BINARY_CMD_GET:
1150         case PROTOCOL_BINARY_CMD_GETQ:
1151             assert(response->message.header.response.keylen == 0);
1152             assert(response->message.header.response.extlen == 4);
1153             assert(response->message.header.response.cas != 0);
1154             break;
1155 
1156         case PROTOCOL_BINARY_CMD_GETK:
1157         case PROTOCOL_BINARY_CMD_GETKQ:
1158             assert(response->message.header.response.keylen != 0);
1159             assert(response->message.header.response.extlen == 4);
1160             assert(response->message.header.response.cas != 0);
1161             break;
1162 
1163         default:
1164             /* Undefined command code */
1165             break;
1166         }
1167     } else {
1168         assert(response->message.header.response.cas == 0);
1169         assert(response->message.header.response.extlen == 0);
1170         if (cmd != PROTOCOL_BINARY_CMD_GETK) {
1171             assert(response->message.header.response.keylen == 0);
1172         }
1173     }
1174 }
1175 
test_binary_noop(void)1176 static enum test_return test_binary_noop(void) {
1177     union {
1178         protocol_binary_request_no_extras request;
1179         protocol_binary_response_no_extras response;
1180         char bytes[1024];
1181     } buffer;
1182 
1183     size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1184                              PROTOCOL_BINARY_CMD_NOOP,
1185                              NULL, 0, NULL, 0);
1186 
1187     safe_send(buffer.bytes, len, false);
1188     safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1189     validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_NOOP,
1190                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1191 
1192     return TEST_PASS;
1193 }
1194 
test_binary_quit_impl(uint8_t cmd)1195 static enum test_return test_binary_quit_impl(uint8_t cmd) {
1196     union {
1197         protocol_binary_request_no_extras request;
1198         protocol_binary_response_no_extras response;
1199         char bytes[1024];
1200     } buffer;
1201     size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1202                              cmd, NULL, 0, NULL, 0);
1203 
1204     safe_send(buffer.bytes, len, false);
1205     if (cmd == PROTOCOL_BINARY_CMD_QUIT) {
1206         safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1207         validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_QUIT,
1208                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1209     }
1210 
1211     /* Socket should be closed now, read should return 0 */
1212     assert(recv(sock, buffer.bytes, sizeof(buffer.bytes), 0) == 0);
1213     close(sock);
1214     sock = connect_server("127.0.0.1", port, false);
1215 
1216     return TEST_PASS;
1217 }
1218 
test_binary_quit(void)1219 static enum test_return test_binary_quit(void) {
1220     return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT);
1221 }
1222 
test_binary_quitq(void)1223 static enum test_return test_binary_quitq(void) {
1224     return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ);
1225 }
1226 
test_binary_set_impl(const char * key,uint8_t cmd)1227 static enum test_return test_binary_set_impl(const char *key, uint8_t cmd) {
1228     union {
1229         protocol_binary_request_no_extras request;
1230         protocol_binary_response_no_extras response;
1231         char bytes[1024];
1232     } send, receive;
1233     uint64_t value = 0xdeadbeefdeadcafe;
1234     size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1235                                  key, strlen(key), &value, sizeof(value),
1236                                  0, 0);
1237 
1238     /* Set should work over and over again */
1239     int ii;
1240     for (ii = 0; ii < 10; ++ii) {
1241         safe_send(send.bytes, len, false);
1242         if (cmd == PROTOCOL_BINARY_CMD_SET) {
1243             safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1244             validate_response_header(&receive.response, cmd,
1245                                      PROTOCOL_BINARY_RESPONSE_SUCCESS);
1246         }
1247     }
1248 
1249     if (cmd == PROTOCOL_BINARY_CMD_SETQ) {
1250         return test_binary_noop();
1251     }
1252 
1253     send.request.message.header.request.cas = receive.response.message.header.response.cas;
1254     safe_send(send.bytes, len, false);
1255     if (cmd == PROTOCOL_BINARY_CMD_SET) {
1256         safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1257         validate_response_header(&receive.response, cmd,
1258                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1259         assert(receive.response.message.header.response.cas != send.request.message.header.request.cas);
1260     } else {
1261         return test_binary_noop();
1262     }
1263 
1264     return TEST_PASS;
1265 }
1266 
test_binary_set(void)1267 static enum test_return test_binary_set(void) {
1268     return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET);
1269 }
1270 
test_binary_setq(void)1271 static enum test_return test_binary_setq(void) {
1272     return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ);
1273 }
1274 
test_binary_add_impl(const char * key,uint8_t cmd)1275 static enum test_return test_binary_add_impl(const char *key, uint8_t cmd) {
1276     uint64_t value = 0xdeadbeefdeadcafe;
1277     union {
1278         protocol_binary_request_no_extras request;
1279         protocol_binary_response_no_extras response;
1280         char bytes[1024];
1281     } send, receive;
1282     size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd, key,
1283                                  strlen(key), &value, sizeof(value),
1284                                  0, 0);
1285 
1286     /* Add should only work the first time */
1287     int ii;
1288     for (ii = 0; ii < 10; ++ii) {
1289         safe_send(send.bytes, len, false);
1290         if (ii == 0) {
1291             if (cmd == PROTOCOL_BINARY_CMD_ADD) {
1292                 safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1293                 validate_response_header(&receive.response, cmd,
1294                                          PROTOCOL_BINARY_RESPONSE_SUCCESS);
1295             }
1296         } else {
1297             safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1298             validate_response_header(&receive.response, cmd,
1299                                      PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
1300         }
1301     }
1302 
1303     return TEST_PASS;
1304 }
1305 
test_binary_add(void)1306 static enum test_return test_binary_add(void) {
1307     return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD);
1308 }
1309 
test_binary_addq(void)1310 static enum test_return test_binary_addq(void) {
1311     return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ);
1312 }
1313 
test_binary_replace_impl(const char * key,uint8_t cmd)1314 static enum test_return test_binary_replace_impl(const char* key, uint8_t cmd) {
1315     uint64_t value = 0xdeadbeefdeadcafe;
1316     union {
1317         protocol_binary_request_no_extras request;
1318         protocol_binary_response_no_extras response;
1319         char bytes[1024];
1320     } send, receive;
1321     size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1322                                  key, strlen(key), &value, sizeof(value),
1323                                  0, 0);
1324     safe_send(send.bytes, len, false);
1325     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1326     validate_response_header(&receive.response, cmd,
1327                              PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1328     len = storage_command(send.bytes, sizeof(send.bytes),
1329                           PROTOCOL_BINARY_CMD_ADD,
1330                           key, strlen(key), &value, sizeof(value), 0, 0);
1331     safe_send(send.bytes, len, false);
1332     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1333     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1334                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1335 
1336     len = storage_command(send.bytes, sizeof(send.bytes), cmd,
1337                           key, strlen(key), &value, sizeof(value), 0, 0);
1338     int ii;
1339     for (ii = 0; ii < 10; ++ii) {
1340         safe_send(send.bytes, len, false);
1341         if (cmd == PROTOCOL_BINARY_CMD_REPLACE) {
1342             safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1343             validate_response_header(&receive.response,
1344                                      PROTOCOL_BINARY_CMD_REPLACE,
1345                                      PROTOCOL_BINARY_RESPONSE_SUCCESS);
1346         }
1347     }
1348 
1349     if (cmd == PROTOCOL_BINARY_CMD_REPLACEQ) {
1350         test_binary_noop();
1351     }
1352 
1353     return TEST_PASS;
1354 }
1355 
test_binary_replace(void)1356 static enum test_return test_binary_replace(void) {
1357     return test_binary_replace_impl("test_binary_replace",
1358                                     PROTOCOL_BINARY_CMD_REPLACE);
1359 }
1360 
test_binary_replaceq(void)1361 static enum test_return test_binary_replaceq(void) {
1362     return test_binary_replace_impl("test_binary_replaceq",
1363                                     PROTOCOL_BINARY_CMD_REPLACEQ);
1364 }
1365 
test_binary_delete_impl(const char * key,uint8_t cmd)1366 static enum test_return test_binary_delete_impl(const char *key, uint8_t cmd) {
1367     union {
1368         protocol_binary_request_no_extras request;
1369         protocol_binary_response_no_extras response;
1370         char bytes[1024];
1371     } send, receive;
1372     size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1373                              key, strlen(key), NULL, 0);
1374 
1375     safe_send(send.bytes, len, false);
1376     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1377     validate_response_header(&receive.response, cmd,
1378                              PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1379     len = storage_command(send.bytes, sizeof(send.bytes),
1380                           PROTOCOL_BINARY_CMD_ADD,
1381                           key, strlen(key), NULL, 0, 0, 0);
1382     safe_send(send.bytes, len, false);
1383     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1384     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1385                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1386 
1387     len = raw_command(send.bytes, sizeof(send.bytes),
1388                       cmd, key, strlen(key), NULL, 0);
1389     safe_send(send.bytes, len, false);
1390 
1391     if (cmd == PROTOCOL_BINARY_CMD_DELETE) {
1392         safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1393         validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE,
1394                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1395     }
1396 
1397     safe_send(send.bytes, len, false);
1398     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1399     validate_response_header(&receive.response, cmd,
1400                              PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1401 
1402     return TEST_PASS;
1403 }
1404 
test_binary_delete(void)1405 static enum test_return test_binary_delete(void) {
1406     return test_binary_delete_impl("test_binary_delete",
1407                                    PROTOCOL_BINARY_CMD_DELETE);
1408 }
1409 
test_binary_deleteq(void)1410 static enum test_return test_binary_deleteq(void) {
1411     return test_binary_delete_impl("test_binary_deleteq",
1412                                    PROTOCOL_BINARY_CMD_DELETEQ);
1413 }
1414 
test_binary_get_impl(const char * key,uint8_t cmd)1415 static enum test_return test_binary_get_impl(const char *key, uint8_t cmd) {
1416     union {
1417         protocol_binary_request_no_extras request;
1418         protocol_binary_response_no_extras response;
1419         char bytes[1024];
1420     } send, receive;
1421     size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1422                              key, strlen(key), NULL, 0);
1423 
1424     safe_send(send.bytes, len, false);
1425     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1426     validate_response_header(&receive.response, cmd,
1427                              PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1428 
1429     len = storage_command(send.bytes, sizeof(send.bytes),
1430                           PROTOCOL_BINARY_CMD_ADD,
1431                           key, strlen(key), NULL, 0,
1432                           0, 0);
1433     safe_send(send.bytes, len, false);
1434     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1435     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1436                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1437 
1438     /* run a little pipeline test ;-) */
1439     len = 0;
1440     int ii;
1441     for (ii = 0; ii < 10; ++ii) {
1442         union {
1443             protocol_binary_request_no_extras request;
1444             char bytes[1024];
1445         } temp;
1446         size_t l = raw_command(temp.bytes, sizeof(temp.bytes),
1447                                cmd, key, strlen(key), NULL, 0);
1448         memcpy(send.bytes + len, temp.bytes, l);
1449         len += l;
1450     }
1451 
1452     safe_send(send.bytes, len, false);
1453     for (ii = 0; ii < 10; ++ii) {
1454         safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1455         validate_response_header(&receive.response, cmd,
1456                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1457     }
1458 
1459     return TEST_PASS;
1460 }
1461 
test_binary_get(void)1462 static enum test_return test_binary_get(void) {
1463     return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET);
1464 }
1465 
test_binary_getk(void)1466 static enum test_return test_binary_getk(void) {
1467     return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK);
1468 }
1469 
test_binary_getq_impl(const char * key,uint8_t cmd)1470 static enum test_return test_binary_getq_impl(const char *key, uint8_t cmd) {
1471     const char *missing = "test_binary_getq_missing";
1472     union {
1473         protocol_binary_request_no_extras request;
1474         protocol_binary_response_no_extras response;
1475         char bytes[1024];
1476     } send, temp, receive;
1477     size_t len = storage_command(send.bytes, sizeof(send.bytes),
1478                                  PROTOCOL_BINARY_CMD_ADD,
1479                                  key, strlen(key), NULL, 0,
1480                                  0, 0);
1481     size_t len2 = raw_command(temp.bytes, sizeof(temp.bytes), cmd,
1482                              missing, strlen(missing), NULL, 0);
1483     /* I need to change the first opaque so that I can separate the two
1484      * return packets */
1485     temp.request.message.header.request.opaque = 0xfeedface;
1486     memcpy(send.bytes + len, temp.bytes, len2);
1487     len += len2;
1488 
1489     len2 = raw_command(temp.bytes, sizeof(temp.bytes), cmd,
1490                        key, strlen(key), NULL, 0);
1491     memcpy(send.bytes + len, temp.bytes, len2);
1492     len += len2;
1493 
1494     safe_send(send.bytes, len, false);
1495     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1496     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1497                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1498     /* The first GETQ shouldn't return anything */
1499     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1500     validate_response_header(&receive.response, cmd,
1501                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1502 
1503     return TEST_PASS;
1504 }
1505 
test_binary_getq(void)1506 static enum test_return test_binary_getq(void) {
1507     return test_binary_getq_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ);
1508 }
1509 
test_binary_getkq(void)1510 static enum test_return test_binary_getkq(void) {
1511     return test_binary_getq_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ);
1512 }
1513 
test_binary_incr_impl(const char * key,uint8_t cmd)1514 static enum test_return test_binary_incr_impl(const char* key, uint8_t cmd) {
1515     union {
1516         protocol_binary_request_no_extras request;
1517         protocol_binary_response_no_extras response_header;
1518         protocol_binary_response_incr response;
1519         char bytes[1024];
1520     } send, receive;
1521     size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
1522                                     key, strlen(key), 1, 0, 0);
1523 
1524     int ii;
1525     for (ii = 0; ii < 10; ++ii) {
1526         safe_send(send.bytes, len, false);
1527         if (cmd == PROTOCOL_BINARY_CMD_INCREMENT) {
1528             safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1529             validate_response_header(&receive.response_header, cmd,
1530                                      PROTOCOL_BINARY_RESPONSE_SUCCESS);
1531             assert(ntohll(receive.response.message.body.value) == ii);
1532         }
1533     }
1534 
1535     if (cmd == PROTOCOL_BINARY_CMD_INCREMENTQ) {
1536         test_binary_noop();
1537     }
1538     return TEST_PASS;
1539 }
1540 
test_binary_incr(void)1541 static enum test_return test_binary_incr(void) {
1542     return test_binary_incr_impl("test_binary_incr",
1543                                  PROTOCOL_BINARY_CMD_INCREMENT);
1544 }
1545 
test_binary_incrq(void)1546 static enum test_return test_binary_incrq(void) {
1547     return test_binary_incr_impl("test_binary_incrq",
1548                                  PROTOCOL_BINARY_CMD_INCREMENTQ);
1549 }
1550 
test_binary_decr_impl(const char * key,uint8_t cmd)1551 static enum test_return test_binary_decr_impl(const char* key, uint8_t cmd) {
1552     union {
1553         protocol_binary_request_no_extras request;
1554         protocol_binary_response_no_extras response_header;
1555         protocol_binary_response_decr response;
1556         char bytes[1024];
1557     } send, receive;
1558     size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
1559                                     key, strlen(key), 1, 9, 0);
1560 
1561     int ii;
1562     for (ii = 9; ii >= 0; --ii) {
1563         safe_send(send.bytes, len, false);
1564         if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
1565             safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1566             validate_response_header(&receive.response_header, cmd,
1567                                      PROTOCOL_BINARY_RESPONSE_SUCCESS);
1568             assert(ntohll(receive.response.message.body.value) == ii);
1569         }
1570     }
1571 
1572     /* decr on 0 should not wrap */
1573     safe_send(send.bytes, len, false);
1574     if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
1575         safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1576         validate_response_header(&receive.response_header, cmd,
1577                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1578         assert(ntohll(receive.response.message.body.value) == 0);
1579     } else {
1580         test_binary_noop();
1581     }
1582 
1583     return TEST_PASS;
1584 }
1585 
test_binary_decr(void)1586 static enum test_return test_binary_decr(void) {
1587     return test_binary_decr_impl("test_binary_decr",
1588                                  PROTOCOL_BINARY_CMD_DECREMENT);
1589 }
1590 
test_binary_decrq(void)1591 static enum test_return test_binary_decrq(void) {
1592     return test_binary_decr_impl("test_binary_decrq",
1593                                  PROTOCOL_BINARY_CMD_DECREMENTQ);
1594 }
1595 
test_binary_version(void)1596 static enum test_return test_binary_version(void) {
1597     union {
1598         protocol_binary_request_no_extras request;
1599         protocol_binary_response_no_extras response;
1600         char bytes[1024];
1601     } buffer;
1602 
1603     size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1604                              PROTOCOL_BINARY_CMD_VERSION,
1605                              NULL, 0, NULL, 0);
1606 
1607     safe_send(buffer.bytes, len, false);
1608     safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1609     validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_VERSION,
1610                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1611 
1612     return TEST_PASS;
1613 }
1614 
test_binary_flush_impl(const char * key,uint8_t cmd)1615 static enum test_return test_binary_flush_impl(const char *key, uint8_t cmd) {
1616     union {
1617         protocol_binary_request_no_extras request;
1618         protocol_binary_response_no_extras response;
1619         char bytes[1024];
1620     } send, receive;
1621 
1622     size_t len = storage_command(send.bytes, sizeof(send.bytes),
1623                                  PROTOCOL_BINARY_CMD_ADD,
1624                                  key, strlen(key), NULL, 0, 0, 0);
1625     safe_send(send.bytes, len, false);
1626     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1627     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1628                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1629 
1630     len = flush_command(send.bytes, sizeof(send.bytes), cmd, 2, true);
1631     safe_send(send.bytes, len, false);
1632     if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
1633         safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1634         validate_response_header(&receive.response, cmd,
1635                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1636     }
1637 
1638     len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GET,
1639                       key, strlen(key), NULL, 0);
1640     safe_send(send.bytes, len, false);
1641     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1642     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1643                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1644 
1645     sleep(2);
1646     safe_send(send.bytes, len, false);
1647     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1648     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1649                              PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1650 
1651     int ii;
1652     for (ii = 0; ii < 2; ++ii) {
1653         len = storage_command(send.bytes, sizeof(send.bytes),
1654                               PROTOCOL_BINARY_CMD_ADD,
1655                               key, strlen(key), NULL, 0, 0, 0);
1656         safe_send(send.bytes, len, false);
1657         safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1658         validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1659                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1660 
1661         len = flush_command(send.bytes, sizeof(send.bytes), cmd, 0, ii == 0);
1662         safe_send(send.bytes, len, false);
1663         if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
1664             safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1665             validate_response_header(&receive.response, cmd,
1666                                      PROTOCOL_BINARY_RESPONSE_SUCCESS);
1667         }
1668 
1669         len = raw_command(send.bytes, sizeof(send.bytes),
1670                           PROTOCOL_BINARY_CMD_GET,
1671                           key, strlen(key), NULL, 0);
1672         safe_send(send.bytes, len, false);
1673         safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1674         validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
1675                                  PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1676     }
1677 
1678     return TEST_PASS;
1679 }
1680 
test_binary_flush(void)1681 static enum test_return test_binary_flush(void) {
1682     return test_binary_flush_impl("test_binary_flush",
1683                                   PROTOCOL_BINARY_CMD_FLUSH);
1684 }
1685 
test_binary_flushq(void)1686 static enum test_return test_binary_flushq(void) {
1687     return test_binary_flush_impl("test_binary_flushq",
1688                                   PROTOCOL_BINARY_CMD_FLUSHQ);
1689 }
1690 
test_binary_cas(void)1691 static enum test_return test_binary_cas(void) {
1692     union {
1693         protocol_binary_request_no_extras request;
1694         protocol_binary_response_no_extras response;
1695         char bytes[1024];
1696     } send, receive;
1697 
1698     size_t len = flush_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_FLUSH,
1699                                0, false);
1700     safe_send(send.bytes, len, false);
1701     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1702     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_FLUSH,
1703                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1704 
1705     uint64_t value = 0xdeadbeefdeadcafe;
1706     len = storage_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_SET,
1707                           "FOO", 3, &value, sizeof(value), 0, 0);
1708 
1709     send.request.message.header.request.cas = 0x7ffffff;
1710     safe_send(send.bytes, len, false);
1711     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1712     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1713                              PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
1714 
1715     send.request.message.header.request.cas = 0x0;
1716     safe_send(send.bytes, len, false);
1717     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1718     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1719                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1720 
1721     send.request.message.header.request.cas = receive.response.message.header.response.cas;
1722     safe_send(send.bytes, len, false);
1723     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1724     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1725                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1726 
1727     send.request.message.header.request.cas = receive.response.message.header.response.cas - 1;
1728     safe_send(send.bytes, len, false);
1729     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1730     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_SET,
1731                              PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
1732     return TEST_PASS;
1733 }
1734 
test_binary_concat_impl(const char * key,uint8_t cmd)1735 static enum test_return test_binary_concat_impl(const char *key, uint8_t cmd) {
1736     union {
1737         protocol_binary_request_no_extras request;
1738         protocol_binary_response_no_extras response;
1739         char bytes[1024];
1740     } send, receive;
1741     const char *value = "world";
1742 
1743     size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1744                               key, strlen(key), value, strlen(value));
1745 
1746 
1747     safe_send(send.bytes, len, false);
1748     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1749     validate_response_header(&receive.response, cmd,
1750                              PROTOCOL_BINARY_RESPONSE_NOT_STORED);
1751 
1752     len = storage_command(send.bytes, sizeof(send.bytes),
1753                           PROTOCOL_BINARY_CMD_ADD,
1754                           key, strlen(key), value, strlen(value), 0, 0);
1755     safe_send(send.bytes, len, false);
1756     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1757     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
1758                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1759 
1760     len = raw_command(send.bytes, sizeof(send.bytes), cmd,
1761                       key, strlen(key), value, strlen(value));
1762     safe_send(send.bytes, len, false);
1763 
1764     if (cmd == PROTOCOL_BINARY_CMD_APPEND || cmd == PROTOCOL_BINARY_CMD_PREPEND) {
1765         safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1766         validate_response_header(&receive.response, cmd,
1767                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1768     } else {
1769         len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_NOOP,
1770                           NULL, 0, NULL, 0);
1771         safe_send(send.bytes, len, false);
1772         safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1773         validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_NOOP,
1774                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1775     }
1776 
1777     len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GETK,
1778                       key, strlen(key), NULL, 0);
1779 
1780     safe_send(send.bytes, len, false);
1781     safe_recv_packet(receive.bytes, sizeof(receive.bytes));
1782     validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GETK,
1783                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1784 
1785     assert(receive.response.message.header.response.keylen == strlen(key));
1786     assert(receive.response.message.header.response.bodylen == (strlen(key) + 2*strlen(value) + 4));
1787 
1788     char *ptr = receive.bytes;
1789     ptr += sizeof(receive.response);
1790     ptr += 4;
1791 
1792     assert(memcmp(ptr, key, strlen(key)) == 0);
1793     ptr += strlen(key);
1794     assert(memcmp(ptr, value, strlen(value)) == 0);
1795     ptr += strlen(value);
1796     assert(memcmp(ptr, value, strlen(value)) == 0);
1797 
1798     return TEST_PASS;
1799 }
1800 
test_binary_append(void)1801 static enum test_return test_binary_append(void) {
1802     return test_binary_concat_impl("test_binary_append",
1803                                    PROTOCOL_BINARY_CMD_APPEND);
1804 }
1805 
test_binary_prepend(void)1806 static enum test_return test_binary_prepend(void) {
1807     return test_binary_concat_impl("test_binary_prepend",
1808                                    PROTOCOL_BINARY_CMD_PREPEND);
1809 }
1810 
test_binary_appendq(void)1811 static enum test_return test_binary_appendq(void) {
1812     return test_binary_concat_impl("test_binary_appendq",
1813                                    PROTOCOL_BINARY_CMD_APPENDQ);
1814 }
1815 
test_binary_prependq(void)1816 static enum test_return test_binary_prependq(void) {
1817     return test_binary_concat_impl("test_binary_prependq",
1818                                    PROTOCOL_BINARY_CMD_PREPENDQ);
1819 }
1820 
test_binary_stat(void)1821 static enum test_return test_binary_stat(void) {
1822     union {
1823         protocol_binary_request_no_extras request;
1824         protocol_binary_response_no_extras response;
1825         char bytes[1024];
1826     } buffer;
1827 
1828     size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1829                              PROTOCOL_BINARY_CMD_STAT,
1830                              NULL, 0, NULL, 0);
1831 
1832     safe_send(buffer.bytes, len, false);
1833     do {
1834         safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1835         validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_STAT,
1836                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
1837     } while (buffer.response.message.header.response.keylen != 0);
1838 
1839     return TEST_PASS;
1840 }
1841 
test_binary_scrub(void)1842 static enum test_return test_binary_scrub(void) {
1843     union {
1844         protocol_binary_request_no_extras request;
1845         protocol_binary_response_no_extras response;
1846         char bytes[1024];
1847     } buffer;
1848 
1849     size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
1850                              PROTOCOL_BINARY_CMD_SCRUB,
1851                              NULL, 0, NULL, 0);
1852 
1853     safe_send(buffer.bytes, len, false);
1854     safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
1855     validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_SCRUB,
1856                              PROTOCOL_BINARY_RESPONSE_SUCCESS);
1857 
1858     return TEST_PASS;
1859 }
1860 
1861 
1862 volatile bool hickup_thread_running;
1863 
binary_hickup_recv_verification_thread(void * arg)1864 static void *binary_hickup_recv_verification_thread(void *arg) {
1865     protocol_binary_response_no_extras *response = malloc(65*1024);
1866     if (response != NULL) {
1867         while (safe_recv_packet(response, 65*1024)) {
1868             /* Just validate the packet format */
1869             validate_response_header(response,
1870                                      response->message.header.response.opcode,
1871                                      response->message.header.response.status);
1872         }
1873         free(response);
1874     }
1875     hickup_thread_running = false;
1876     allow_closed_read = false;
1877     return NULL;
1878 }
1879 
test_binary_pipeline_hickup_chunk(void * buffer,size_t buffersize)1880 static enum test_return test_binary_pipeline_hickup_chunk(void *buffer, size_t buffersize) {
1881     off_t offset = 0;
1882     char *key[256];
1883     uint64_t value = 0xfeedfacedeadbeef;
1884 
1885     while (hickup_thread_running &&
1886            offset + sizeof(protocol_binary_request_no_extras) < buffersize) {
1887         union {
1888             protocol_binary_request_no_extras request;
1889             char bytes[65 * 1024];
1890         } command;
1891         uint8_t cmd = (uint8_t)(rand() & 0xff);
1892         size_t len;
1893         size_t keylen = (rand() % 250) + 1;
1894 
1895         switch (cmd) {
1896         case PROTOCOL_BINARY_CMD_ADD:
1897         case PROTOCOL_BINARY_CMD_ADDQ:
1898         case PROTOCOL_BINARY_CMD_REPLACE:
1899         case PROTOCOL_BINARY_CMD_REPLACEQ:
1900         case PROTOCOL_BINARY_CMD_SET:
1901         case PROTOCOL_BINARY_CMD_SETQ:
1902             len = storage_command(command.bytes, sizeof(command.bytes), cmd,
1903                                   key, keylen , &value, sizeof(value),
1904                                   0, 0);
1905             break;
1906         case PROTOCOL_BINARY_CMD_APPEND:
1907         case PROTOCOL_BINARY_CMD_APPENDQ:
1908         case PROTOCOL_BINARY_CMD_PREPEND:
1909         case PROTOCOL_BINARY_CMD_PREPENDQ:
1910             len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1911                               key, keylen, &value, sizeof(value));
1912             break;
1913         case PROTOCOL_BINARY_CMD_FLUSH:
1914         case PROTOCOL_BINARY_CMD_FLUSHQ:
1915             len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1916                               NULL, 0, NULL, 0);
1917             break;
1918         case PROTOCOL_BINARY_CMD_NOOP:
1919             len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1920                               NULL, 0, NULL, 0);
1921             break;
1922         case PROTOCOL_BINARY_CMD_DELETE:
1923         case PROTOCOL_BINARY_CMD_DELETEQ:
1924             len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1925                              key, keylen, NULL, 0);
1926             break;
1927         case PROTOCOL_BINARY_CMD_DECREMENT:
1928         case PROTOCOL_BINARY_CMD_DECREMENTQ:
1929         case PROTOCOL_BINARY_CMD_INCREMENT:
1930         case PROTOCOL_BINARY_CMD_INCREMENTQ:
1931             len = arithmetic_command(command.bytes, sizeof(command.bytes), cmd,
1932                                      key, keylen, 1, 0, 0);
1933             break;
1934         case PROTOCOL_BINARY_CMD_VERSION:
1935             len = raw_command(command.bytes, sizeof(command.bytes),
1936                              PROTOCOL_BINARY_CMD_VERSION,
1937                              NULL, 0, NULL, 0);
1938             break;
1939         case PROTOCOL_BINARY_CMD_GET:
1940         case PROTOCOL_BINARY_CMD_GETK:
1941         case PROTOCOL_BINARY_CMD_GETKQ:
1942         case PROTOCOL_BINARY_CMD_GETQ:
1943             len = raw_command(command.bytes, sizeof(command.bytes), cmd,
1944                              key, keylen, NULL, 0);
1945             break;
1946 
1947         case PROTOCOL_BINARY_CMD_STAT:
1948             len = raw_command(command.bytes, sizeof(command.bytes),
1949                               PROTOCOL_BINARY_CMD_STAT,
1950                               NULL, 0, NULL, 0);
1951             break;
1952 
1953         default:
1954             // don't run commands we don't know
1955             continue;
1956         }
1957 
1958         if ((len + offset) < buffersize) {
1959             memcpy(((char*)buffer) + offset, command.bytes, len);
1960             offset += len;
1961         } else {
1962             break;
1963         }
1964     }
1965     safe_send(buffer, offset, true);
1966 
1967     return TEST_PASS;
1968 }
1969 
test_binary_pipeline_hickup(void)1970 static enum test_return test_binary_pipeline_hickup(void)
1971 {
1972     size_t buffersize = 65 * 1024;
1973     void *buffer = malloc(buffersize);
1974     int ii;
1975 
1976     pthread_t tid;
1977     int ret;
1978     allow_closed_read = true;
1979     hickup_thread_running = true;
1980     if ((ret = pthread_create(&tid, NULL,
1981                               binary_hickup_recv_verification_thread, NULL)) != 0) {
1982         fprintf(stderr, "Can't create thread: %s\n", strerror(ret));
1983         return TEST_FAIL;
1984     }
1985 
1986     /* Allow the thread to start */
1987     usleep(250);
1988 
1989     srand((int)time(NULL));
1990     for (ii = 0; ii < 2; ++ii) {
1991         test_binary_pipeline_hickup_chunk(buffer, buffersize);
1992     }
1993 
1994     /* send quitq to shut down the read thread ;-) */
1995     size_t len = raw_command(buffer, buffersize, PROTOCOL_BINARY_CMD_QUITQ,
1996                              NULL, 0, NULL, 0);
1997     safe_send(buffer, len, false);
1998 
1999     pthread_join(tid, NULL);
2000     free(buffer);
2001     return TEST_PASS;
2002 }
2003 
test_binary_verbosity(void)2004 static enum test_return test_binary_verbosity(void) {
2005     union {
2006         protocol_binary_request_verbosity request;
2007         protocol_binary_response_no_extras response;
2008         char bytes[1024];
2009     } buffer;
2010 
2011     for (int ii = 10; ii > -1; --ii) {
2012         size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
2013                                  PROTOCOL_BINARY_CMD_VERBOSITY,
2014                                  NULL, 0, NULL, 0);
2015         buffer.request.message.header.request.extlen = 4;
2016         buffer.request.message.header.request.bodylen = ntohl(4);
2017         buffer.request.message.body.level = (uint32_t)ntohl(ii);
2018         safe_send(buffer.bytes, len + sizeof(4), false);
2019         safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
2020         validate_response_header(&buffer.response,
2021                                  PROTOCOL_BINARY_CMD_VERBOSITY,
2022                                  PROTOCOL_BINARY_RESPONSE_SUCCESS);
2023     }
2024 
2025     return TEST_PASS;
2026 }
2027 
test_issue_101(void)2028 static enum test_return test_issue_101(void) {
2029     const int max = 2;
2030     enum test_return ret = TEST_PASS;
2031     int fds[max];
2032     int ii = 0;
2033     pid_t child = 0;
2034 
2035     if (getenv("DONT_SKIP_TEST_101") == NULL) {
2036         return TEST_SKIP;
2037     }
2038 
2039     const char *command = "stats\r\nstats\r\nstats\r\nstats\r\nstats\r\n";
2040     size_t cmdlen = strlen(command);
2041 
2042     server_pid = start_server(&port, false, 1000);
2043 
2044     for (ii = 0; ii < max; ++ii) {
2045         fds[ii] = connect_server("127.0.0.1", port, true);
2046         assert(fds[ii] > 0);
2047     }
2048 
2049     /* Send command on the connection until it blocks */
2050     for (ii = 0; ii < max; ++ii) {
2051         bool more = true;
2052         do {
2053             ssize_t err = send(fds[ii], command, cmdlen, 0);
2054             if (err == -1) {
2055                 switch (errno) {
2056                 case EINTR:
2057                     break;
2058                 case ENOMEM:
2059                 case EWOULDBLOCK:
2060                     more = false;
2061                     break;
2062                 default:
2063                     ret = TEST_FAIL;
2064                     goto cleanup;
2065                 }
2066             }
2067         } while (more);
2068     }
2069 
2070     child = fork();
2071     if (child == (pid_t)-1) {
2072         abort();
2073     } else if (child > 0) {
2074         int stat;
2075         pid_t c;
2076         while ((c = waitpid(child, &stat, 0)) == (pid_t)-1 && errno == EINTR);
2077         assert(c == child);
2078         assert(stat == 0);
2079     } else {
2080         sock = connect_server("127.0.0.1", port, false);
2081         ret = test_binary_noop();
2082         close(sock);
2083         exit(0);
2084     }
2085 
2086  cleanup:
2087     /* close all connections */
2088     for (ii = 0; ii < max; ++ii) {
2089         close(fds[ii]);
2090     }
2091 
2092     assert(kill(server_pid, SIGTERM) == 0);
2093 
2094     return ret;
2095 }
2096 
2097 typedef enum test_return (*TEST_FUNC)(void);
2098 struct testcase {
2099     const char *description;
2100     TEST_FUNC function;
2101 };
2102 
2103 struct testcase testcases[] = {
2104     { "cache_create", cache_create_test },
2105     { "cache_constructor", cache_constructor_test },
2106     { "cache_constructor_fail", cache_fail_constructor_test },
2107     { "cache_destructor", cache_destructor_test },
2108     { "cache_reuse", cache_reuse_test },
2109     { "cache_redzone", cache_redzone_test },
2110     { "issue_161", test_issue_161 },
2111     { "strtof", test_safe_strtof },
2112     { "strtol", test_safe_strtol },
2113     { "strtoll", test_safe_strtoll },
2114     { "strtoul", test_safe_strtoul },
2115     { "strtoull", test_safe_strtoull },
2116     { "issue_44", test_issue_44 },
2117     { "vperror", test_vperror },
2118     { "issue_101", test_issue_101 },
2119     { "config_parser", test_config_parser },
2120     /* The following tests all run towards the same server */
2121     { "start_server", start_memcached_server },
2122     { "issue_92", test_issue_92 },
2123     { "issue_102", test_issue_102 },
2124     { "binary_noop", test_binary_noop },
2125     { "binary_quit", test_binary_quit },
2126     { "binary_quitq", test_binary_quitq },
2127     { "binary_set", test_binary_set },
2128     { "binary_setq", test_binary_setq },
2129     { "binary_add", test_binary_add },
2130     { "binary_addq", test_binary_addq },
2131     { "binary_replace", test_binary_replace },
2132     { "binary_replaceq", test_binary_replaceq },
2133     { "binary_delete", test_binary_delete },
2134     { "binary_deleteq", test_binary_deleteq },
2135     { "binary_get", test_binary_get },
2136     { "binary_getq", test_binary_getq },
2137     { "binary_getk", test_binary_getk },
2138     { "binary_getkq", test_binary_getkq },
2139     { "binary_incr", test_binary_incr },
2140     { "binary_incrq", test_binary_incrq },
2141     { "binary_decr", test_binary_decr },
2142     { "binary_decrq", test_binary_decrq },
2143     { "binary_version", test_binary_version },
2144     { "binary_flush", test_binary_flush },
2145     { "binary_flushq", test_binary_flushq },
2146     { "binary_cas", test_binary_cas },
2147     { "binary_append", test_binary_append },
2148     { "binary_appendq", test_binary_appendq },
2149     { "binary_prepend", test_binary_prepend },
2150     { "binary_prependq", test_binary_prependq },
2151     { "binary_stat", test_binary_stat },
2152     { "binary_scrub", test_binary_scrub },
2153     { "binary_verbosity", test_binary_verbosity },
2154     { "binary_pipeline_hickup", test_binary_pipeline_hickup },
2155     { "stop_server", stop_memcached_server },
2156     { NULL, NULL }
2157 };
2158 
main(int argc,char ** argv)2159 int main(int argc, char **argv)
2160 {
2161     int exitcode = 0;
2162     int ii = 0, num_cases = 0;
2163 
2164     /* Use unbuffered stdio */
2165     setbuf(stdout, NULL);
2166     setbuf(stderr, NULL);
2167 
2168     for (num_cases = 0; testcases[num_cases].description; num_cases++) {
2169         /* Just counting */
2170     }
2171 
2172     printf("1..%d\n", num_cases);
2173 
2174     for (ii = 0; testcases[ii].description != NULL; ++ii) {
2175         fflush(stdout);
2176 #if 0
2177         /* the test program shouldn't run longer than 10 minutes... */
2178         alarm(600);
2179 #endif
2180         enum test_return ret = testcases[ii].function();
2181         if (ret == TEST_SKIP) {
2182             fprintf(stdout, "ok # SKIP %d - %s\n", ii + 1, testcases[ii].description);
2183         } else if (ret == TEST_PASS) {
2184             fprintf(stdout, "ok %d - %s\n", ii + 1, testcases[ii].description);
2185         } else {
2186             fprintf(stdout, "not ok %d - %s\n", ii + 1, testcases[ii].description);
2187             exitcode = 1;
2188         }
2189         fflush(stdout);
2190     }
2191 
2192     return exitcode;
2193 }
2194