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