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