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