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