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