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