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 468 static enum test_return test_issue_72(void) { 469 in_port_t port; 470 pid_t pid = start_server(&port, false, 15); 471 int sock = connect_server("127.0.0.1", port); 472 assert(sock != -1); 473 474 char data[sizeof(protocol_binary_request_set) + 2048] = { 0 }; 475 protocol_binary_request_set *request = (protocol_binary_request_set*)data; 476 request->message.header.request.magic = PROTOCOL_BINARY_REQ; 477 request->message.header.request.opcode = PROTOCOL_BINARY_CMD_SET; 478 uint16_t keylen = 2048; 479 request->message.header.request.keylen = htons(keylen); 480 request->message.header.request.extlen = 8; 481 request->message.header.request.bodylen = htonl(keylen + 8); 482 483 assert(write(sock, data, 2000) == 2000); 484 usleep(250); 485 assert(write(sock, data, sizeof(data) - 2000) == sizeof(data) - 2000); 486 487 protocol_binary_response_set response; 488 assert(read(sock, &response, sizeof(response)) == sizeof(response)); 489 assert(response.message.header.response.magic == PROTOCOL_BINARY_RES); 490 assert(ntohs(response.message.header.response.status) == PROTOCOL_BINARY_RESPONSE_SUCCESS); 491 close(sock); 492 assert(kill(pid, SIGTERM) == 0); 493 return TEST_PASS; 494 } 495 496 static void send_ascii_command(const char *buf) { 497 off_t offset = 0; 498 const char* ptr = buf; 499 size_t len = strlen(buf); 500 501 do { 502 ssize_t nw = write(sock, ptr + offset, len - offset); 503 if (nw == -1) { 504 if (errno != EINTR) { 505 fprintf(stderr, "Failed to write: %s\n", strerror(errno)); 506 abort(); 507 } 508 } else { 509 offset += nw; 510 } 511 } while (offset < len); 512 } 513 514 /* 515 * This is a dead slow single byte read, but it should only read out 516 * _one_ response and I don't have an input buffer... The current 517 * implementation only supports single-line responses, so if you want to use 518 * it for get commands you need to implement that first ;-) 519 */ 520 static void read_ascii_response(char *buffer, size_t size) { 521 off_t offset = 0; 522 bool need_more = true; 523 do { 524 ssize_t nr = read(sock, buffer + offset, 1); 525 if (nr == -1) { 526 if (errno != EINTR) { 527 fprintf(stderr, "Failed to read: %s\n", strerror(errno)); 528 abort(); 529 } 530 } else { 531 assert(nr == 1); 532 if (buffer[offset] == '\n') { 533 need_more = false; 534 buffer[offset + 1] = '\0'; 535 } 536 offset += nr; 537 assert(offset + 1 < size); 538 } 539 } while (need_more); 540 } 541 542 static enum test_return test_issue_92(void) { 543 char buffer[1024]; 544 545 close(sock); 546 sock = connect_server("127.0.0.1", port); 547 548 send_ascii_command("stats cachedump 1 0 0\r\n"); 549 read_ascii_response(buffer, sizeof(buffer)); 550 assert(strncmp(buffer, "END", strlen("END")) == 0); 551 552 send_ascii_command("stats cachedump 200 0 0\r\n"); 553 read_ascii_response(buffer, sizeof(buffer)); 554 assert(strncmp(buffer, "CLIENT_ERROR", strlen("CLIENT_ERROR")) == 0); 555 556 close(sock); 557 sock = connect_server("127.0.0.1", port); 558 return TEST_PASS; 559 } 560 561 static enum test_return start_memcached_server(void) { 562 server_pid = start_server(&port, false, 600); 563 sock = connect_server("127.0.0.1", port); 564 return TEST_PASS; 565 } 566 567 static enum test_return stop_memcached_server(void) { 568 close(sock); 569 assert(kill(server_pid, SIGTERM) == 0); 570 return TEST_PASS; 571 } 572 573 static void safe_send(const void* buf, size_t len, bool hickup) 574 { 575 off_t offset = 0; 576 const char* ptr = buf; 577 #ifdef MESSAGE_DEBUG 578 uint8_t val = *ptr; 579 assert(val == (uint8_t)0x80); 580 fprintf(stderr, "About to send %lu bytes:", (unsigned long)len); 581 for (int ii = 0; ii < len; ++ii) { 582 if (ii % 4 == 0) { 583 fprintf(stderr, "\n "); 584 } 585 val = *(ptr + ii); 586 fprintf(stderr, " 0x%02x", val); 587 } 588 fprintf(stderr, "\n"); 589 usleep(500); 590 #endif 591 592 do { 593 size_t num_bytes = len - offset; 594 if (hickup) { 595 if (num_bytes > 1024) { 596 num_bytes = (rand() % 1023) + 1; 597 } 598 } 599 600 ssize_t nw = write(sock, ptr + offset, num_bytes); 601 if (nw == -1) { 602 if (errno != EINTR) { 603 fprintf(stderr, "Failed to write: %s\n", strerror(errno)); 604 abort(); 605 } 606 } else { 607 if (hickup) { 608 usleep(100); 609 } 610 offset += nw; 611 } 612 } while (offset < len); 613 } 614 615 static bool safe_recv(void *buf, size_t len) { 616 if (len == 0) { 617 return true; 618 } 619 off_t offset = 0; 620 do { 621 ssize_t nr = read(sock, ((char*)buf) + offset, len - offset); 622 if (nr == -1) { 623 if (errno != EINTR) { 624 fprintf(stderr, "Failed to read: %s\n", strerror(errno)); 625 abort(); 626 } 627 } else { 628 if (nr == 0 && allow_closed_read) { 629 return false; 630 } 631 assert(nr != 0); 632 offset += nr; 633 } 634 } while (offset < len); 635 636 return true; 637 } 638 639 static bool safe_recv_packet(void *buf, size_t size) { 640 protocol_binary_response_no_extras *response = buf; 641 assert(size > sizeof(*response)); 642 if (!safe_recv(response, sizeof(*response))) { 643 return false; 644 } 645 response->message.header.response.keylen = ntohs(response->message.header.response.keylen); 646 response->message.header.response.status = ntohs(response->message.header.response.status); 647 response->message.header.response.bodylen = ntohl(response->message.header.response.bodylen); 648 649 size_t len = sizeof(*response); 650 651 char *ptr = buf; 652 ptr += len; 653 if (!safe_recv(ptr, response->message.header.response.bodylen)) { 654 return false; 655 } 656 657 #ifdef MESSAGE_DEBUG 658 usleep(500); 659 ptr = buf; 660 len += response->message.header.response.bodylen; 661 uint8_t val = *ptr; 662 assert(val == (uint8_t)0x81); 663 fprintf(stderr, "Received %lu bytes:", (unsigned long)len); 664 for (int ii = 0; ii < len; ++ii) { 665 if (ii % 4 == 0) { 666 fprintf(stderr, "\n "); 667 } 668 val = *(ptr + ii); 669 fprintf(stderr, " 0x%02x", val); 670 } 671 fprintf(stderr, "\n"); 672 #endif 673 return true; 674 } 675 676 static off_t storage_command(char*buf, 677 size_t bufsz, 678 uint8_t cmd, 679 const void* key, 680 size_t keylen, 681 const void* dta, 682 size_t dtalen, 683 uint32_t flags, 684 uint32_t exp) { 685 /* all of the storage commands use the same command layout */ 686 protocol_binary_request_set *request = (void*)buf; 687 assert(bufsz > sizeof(*request) + keylen + dtalen); 688 689 memset(request, 0, sizeof(*request)); 690 request->message.header.request.magic = PROTOCOL_BINARY_REQ; 691 request->message.header.request.opcode = cmd; 692 request->message.header.request.keylen = htons(keylen); 693 request->message.header.request.extlen = 8; 694 request->message.header.request.bodylen = htonl(keylen + 8 + dtalen); 695 request->message.header.request.opaque = 0xdeadbeef; 696 request->message.body.flags = flags; 697 request->message.body.expiration = exp; 698 699 off_t key_offset = sizeof(protocol_binary_request_no_extras) + 8; 700 701 memcpy(buf + key_offset, key, keylen); 702 if (dta != NULL) { 703 memcpy(buf + key_offset + keylen, dta, dtalen); 704 } 705 706 return key_offset + keylen + dtalen; 707 } 708 709 static off_t raw_command(char* buf, 710 size_t bufsz, 711 uint8_t cmd, 712 const void* key, 713 size_t keylen, 714 const void* dta, 715 size_t dtalen) { 716 /* all of the storage commands use the same command layout */ 717 protocol_binary_request_no_extras *request = (void*)buf; 718 assert(bufsz > sizeof(*request) + keylen + dtalen); 719 720 memset(request, 0, sizeof(*request)); 721 request->message.header.request.magic = PROTOCOL_BINARY_REQ; 722 request->message.header.request.opcode = cmd; 723 request->message.header.request.keylen = htons(keylen); 724 request->message.header.request.bodylen = htonl(keylen + dtalen); 725 request->message.header.request.opaque = 0xdeadbeef; 726 727 off_t key_offset = sizeof(protocol_binary_request_no_extras); 728 729 if (key != NULL) { 730 memcpy(buf + key_offset, key, keylen); 731 } 732 if (dta != NULL) { 733 memcpy(buf + key_offset + keylen, dta, dtalen); 734 } 735 736 return sizeof(*request) + keylen + dtalen; 737 } 738 739 static off_t flush_command(char* buf, size_t bufsz, uint8_t cmd, uint32_t exptime, bool use_extra) { 740 protocol_binary_request_flush *request = (void*)buf; 741 assert(bufsz > sizeof(*request)); 742 743 memset(request, 0, sizeof(*request)); 744 request->message.header.request.magic = PROTOCOL_BINARY_REQ; 745 request->message.header.request.opcode = cmd; 746 747 off_t size = sizeof(protocol_binary_request_no_extras); 748 if (use_extra) { 749 request->message.header.request.extlen = 4; 750 request->message.body.expiration = htonl(exptime); 751 request->message.header.request.bodylen = htonl(4); 752 size += 4; 753 } 754 755 request->message.header.request.opaque = 0xdeadbeef; 756 757 return size; 758 } 759 760 static off_t arithmetic_command(char* buf, 761 size_t bufsz, 762 uint8_t cmd, 763 const void* key, 764 size_t keylen, 765 uint64_t delta, 766 uint64_t initial, 767 uint32_t exp) { 768 protocol_binary_request_incr *request = (void*)buf; 769 assert(bufsz > sizeof(*request) + keylen); 770 771 memset(request, 0, sizeof(*request)); 772 request->message.header.request.magic = PROTOCOL_BINARY_REQ; 773 request->message.header.request.opcode = cmd; 774 request->message.header.request.keylen = htons(keylen); 775 request->message.header.request.extlen = 20; 776 request->message.header.request.bodylen = htonl(keylen + 20); 777 request->message.header.request.opaque = 0xdeadbeef; 778 request->message.body.delta = htonll(delta); 779 request->message.body.initial = htonll(initial); 780 request->message.body.expiration = htonl(exp); 781 782 off_t key_offset = sizeof(protocol_binary_request_no_extras) + 20; 783 784 memcpy(buf + key_offset, key, keylen); 785 return key_offset + keylen; 786 } 787 788 static void validate_response_header(protocol_binary_response_no_extras *response, 789 uint8_t cmd, uint16_t status) 790 { 791 assert(response->message.header.response.magic == PROTOCOL_BINARY_RES); 792 assert(response->message.header.response.opcode == cmd); 793 assert(response->message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES); 794 assert(response->message.header.response.status == status); 795 assert(response->message.header.response.opaque == 0xdeadbeef); 796 797 if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) { 798 switch (cmd) { 799 case PROTOCOL_BINARY_CMD_ADDQ: 800 case PROTOCOL_BINARY_CMD_APPENDQ: 801 case PROTOCOL_BINARY_CMD_DECREMENTQ: 802 case PROTOCOL_BINARY_CMD_DELETEQ: 803 case PROTOCOL_BINARY_CMD_FLUSHQ: 804 case PROTOCOL_BINARY_CMD_INCREMENTQ: 805 case PROTOCOL_BINARY_CMD_PREPENDQ: 806 case PROTOCOL_BINARY_CMD_QUITQ: 807 case PROTOCOL_BINARY_CMD_REPLACEQ: 808 case PROTOCOL_BINARY_CMD_SETQ: 809 assert("Quiet command shouldn't return on success" == NULL); 810 default: 811 break; 812 } 813 814 switch (cmd) { 815 case PROTOCOL_BINARY_CMD_ADD: 816 case PROTOCOL_BINARY_CMD_REPLACE: 817 case PROTOCOL_BINARY_CMD_SET: 818 case PROTOCOL_BINARY_CMD_APPEND: 819 case PROTOCOL_BINARY_CMD_PREPEND: 820 assert(response->message.header.response.keylen == 0); 821 assert(response->message.header.response.extlen == 0); 822 assert(response->message.header.response.bodylen == 0); 823 assert(response->message.header.response.cas != 0); 824 break; 825 case PROTOCOL_BINARY_CMD_FLUSH: 826 case PROTOCOL_BINARY_CMD_NOOP: 827 case PROTOCOL_BINARY_CMD_QUIT: 828 case PROTOCOL_BINARY_CMD_DELETE: 829 assert(response->message.header.response.keylen == 0); 830 assert(response->message.header.response.extlen == 0); 831 assert(response->message.header.response.bodylen == 0); 832 assert(response->message.header.response.cas == 0); 833 break; 834 835 case PROTOCOL_BINARY_CMD_DECREMENT: 836 case PROTOCOL_BINARY_CMD_INCREMENT: 837 assert(response->message.header.response.keylen == 0); 838 assert(response->message.header.response.extlen == 0); 839 assert(response->message.header.response.bodylen == 8); 840 assert(response->message.header.response.cas != 0); 841 break; 842 843 case PROTOCOL_BINARY_CMD_STAT: 844 assert(response->message.header.response.extlen == 0); 845 /* key and value exists in all packets except in the terminating */ 846 assert(response->message.header.response.cas == 0); 847 break; 848 849 case PROTOCOL_BINARY_CMD_VERSION: 850 assert(response->message.header.response.keylen == 0); 851 assert(response->message.header.response.extlen == 0); 852 assert(response->message.header.response.bodylen != 0); 853 assert(response->message.header.response.cas == 0); 854 break; 855 856 case PROTOCOL_BINARY_CMD_GET: 857 case PROTOCOL_BINARY_CMD_GETQ: 858 assert(response->message.header.response.keylen == 0); 859 assert(response->message.header.response.extlen == 4); 860 assert(response->message.header.response.cas != 0); 861 break; 862 863 case PROTOCOL_BINARY_CMD_GETK: 864 case PROTOCOL_BINARY_CMD_GETKQ: 865 assert(response->message.header.response.keylen != 0); 866 assert(response->message.header.response.extlen == 4); 867 assert(response->message.header.response.cas != 0); 868 break; 869 870 default: 871 /* Undefined command code */ 872 break; 873 } 874 } else { 875 assert(response->message.header.response.cas == 0); 876 assert(response->message.header.response.extlen == 0); 877 if (cmd != PROTOCOL_BINARY_CMD_GETK) { 878 assert(response->message.header.response.keylen == 0); 879 } 880 } 881 } 882 883 static enum test_return test_binary_noop(void) { 884 union { 885 protocol_binary_request_no_extras request; 886 protocol_binary_response_no_extras response; 887 char bytes[1024]; 888 } buffer; 889 890 size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes), 891 PROTOCOL_BINARY_CMD_NOOP, 892 NULL, 0, NULL, 0); 893 894 safe_send(buffer.bytes, len, false); 895 safe_recv_packet(buffer.bytes, sizeof(buffer.bytes)); 896 validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_NOOP, 897 PROTOCOL_BINARY_RESPONSE_SUCCESS); 898 899 return TEST_PASS; 900 } 901 902 static enum test_return test_binary_quit_impl(uint8_t cmd) { 903 union { 904 protocol_binary_request_no_extras request; 905 protocol_binary_response_no_extras response; 906 char bytes[1024]; 907 } buffer; 908 size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes), 909 cmd, NULL, 0, NULL, 0); 910 911 safe_send(buffer.bytes, len, false); 912 if (cmd == PROTOCOL_BINARY_CMD_QUIT) { 913 safe_recv_packet(buffer.bytes, sizeof(buffer.bytes)); 914 validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_QUIT, 915 PROTOCOL_BINARY_RESPONSE_SUCCESS); 916 } 917 918 /* Socket should be closed now, read should return 0 */ 919 assert(read(sock, buffer.bytes, sizeof(buffer.bytes)) == 0); 920 close(sock); 921 sock = connect_server("127.0.0.1", port); 922 923 return TEST_PASS; 924 } 925 926 static enum test_return test_binary_quit(void) { 927 return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT); 928 } 929 930 static enum test_return test_binary_quitq(void) { 931 return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ); 932 } 933 934 static enum test_return test_binary_set_impl(const char *key, uint8_t cmd) { 935 union { 936 protocol_binary_request_no_extras request; 937 protocol_binary_response_no_extras response; 938 char bytes[1024]; 939 } send, receive; 940 uint64_t value = 0xdeadbeefdeadcafe; 941 size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd, 942 key, strlen(key), &value, sizeof(value), 943 0, 0); 944 945 /* Set should work over and over again */ 946 int ii; 947 for (ii = 0; ii < 10; ++ii) { 948 safe_send(send.bytes, len, false); 949 if (cmd == PROTOCOL_BINARY_CMD_SET) { 950 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 951 validate_response_header(&receive.response, cmd, 952 PROTOCOL_BINARY_RESPONSE_SUCCESS); 953 } 954 } 955 956 if (cmd == PROTOCOL_BINARY_CMD_SETQ) { 957 return test_binary_noop(); 958 } 959 960 send.request.message.header.request.cas = receive.response.message.header.response.cas; 961 safe_send(send.bytes, len, false); 962 if (cmd == PROTOCOL_BINARY_CMD_SET) { 963 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 964 validate_response_header(&receive.response, cmd, 965 PROTOCOL_BINARY_RESPONSE_SUCCESS); 966 assert(receive.response.message.header.response.cas != send.request.message.header.request.cas); 967 } else { 968 return test_binary_noop(); 969 } 970 971 return TEST_PASS; 972 } 973 974 static enum test_return test_binary_set(void) { 975 return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET); 976 } 977 978 static enum test_return test_binary_setq(void) { 979 return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ); 980 } 981 982 983 static enum test_return test_binary_add_impl(const char *key, uint8_t cmd) { 984 uint64_t value = 0xdeadbeefdeadcafe; 985 union { 986 protocol_binary_request_no_extras request; 987 protocol_binary_response_no_extras response; 988 char bytes[1024]; 989 } send, receive; 990 size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd, key, 991 strlen(key), &value, sizeof(value), 992 0, 0); 993 994 /* Add should only work the first time */ 995 int ii; 996 for (ii = 0; ii < 10; ++ii) { 997 safe_send(send.bytes, len, false); 998 if (ii == 0) { 999 if (cmd == PROTOCOL_BINARY_CMD_ADD) { 1000 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1001 validate_response_header(&receive.response, cmd, 1002 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1003 } 1004 } else { 1005 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1006 validate_response_header(&receive.response, cmd, 1007 PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS); 1008 } 1009 } 1010 1011 return TEST_PASS; 1012 } 1013 1014 static enum test_return test_binary_add(void) { 1015 return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD); 1016 } 1017 1018 static enum test_return test_binary_addq(void) { 1019 return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ); 1020 } 1021 1022 static enum test_return test_binary_replace_impl(const char* key, uint8_t cmd) { 1023 uint64_t value = 0xdeadbeefdeadcafe; 1024 union { 1025 protocol_binary_request_no_extras request; 1026 protocol_binary_response_no_extras response; 1027 char bytes[1024]; 1028 } send, receive; 1029 size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd, 1030 key, strlen(key), &value, sizeof(value), 1031 0, 0); 1032 safe_send(send.bytes, len, false); 1033 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1034 validate_response_header(&receive.response, cmd, 1035 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT); 1036 len = storage_command(send.bytes, sizeof(send.bytes), 1037 PROTOCOL_BINARY_CMD_ADD, 1038 key, strlen(key), &value, sizeof(value), 0, 0); 1039 safe_send(send.bytes, len, false); 1040 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1041 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD, 1042 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1043 1044 len = storage_command(send.bytes, sizeof(send.bytes), cmd, 1045 key, strlen(key), &value, sizeof(value), 0, 0); 1046 int ii; 1047 for (ii = 0; ii < 10; ++ii) { 1048 safe_send(send.bytes, len, false); 1049 if (cmd == PROTOCOL_BINARY_CMD_REPLACE) { 1050 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1051 validate_response_header(&receive.response, 1052 PROTOCOL_BINARY_CMD_REPLACE, 1053 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1054 } 1055 } 1056 1057 if (cmd == PROTOCOL_BINARY_CMD_REPLACEQ) { 1058 test_binary_noop(); 1059 } 1060 1061 return TEST_PASS; 1062 } 1063 1064 static enum test_return test_binary_replace(void) { 1065 return test_binary_replace_impl("test_binary_replace", 1066 PROTOCOL_BINARY_CMD_REPLACE); 1067 } 1068 1069 static enum test_return test_binary_replaceq(void) { 1070 return test_binary_replace_impl("test_binary_replaceq", 1071 PROTOCOL_BINARY_CMD_REPLACEQ); 1072 } 1073 1074 static enum test_return test_binary_delete_impl(const char *key, uint8_t cmd) { 1075 union { 1076 protocol_binary_request_no_extras request; 1077 protocol_binary_response_no_extras response; 1078 char bytes[1024]; 1079 } send, receive; 1080 size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd, 1081 key, strlen(key), NULL, 0); 1082 1083 safe_send(send.bytes, len, false); 1084 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1085 validate_response_header(&receive.response, cmd, 1086 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT); 1087 len = storage_command(send.bytes, sizeof(send.bytes), 1088 PROTOCOL_BINARY_CMD_ADD, 1089 key, strlen(key), NULL, 0, 0, 0); 1090 safe_send(send.bytes, len, false); 1091 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1092 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD, 1093 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1094 1095 len = raw_command(send.bytes, sizeof(send.bytes), 1096 cmd, key, strlen(key), NULL, 0); 1097 safe_send(send.bytes, len, false); 1098 1099 if (cmd == PROTOCOL_BINARY_CMD_DELETE) { 1100 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1101 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE, 1102 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1103 } 1104 1105 safe_send(send.bytes, len, false); 1106 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1107 validate_response_header(&receive.response, cmd, 1108 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT); 1109 1110 return TEST_PASS; 1111 } 1112 1113 static enum test_return test_binary_delete(void) { 1114 return test_binary_delete_impl("test_binary_delete", 1115 PROTOCOL_BINARY_CMD_DELETE); 1116 } 1117 1118 static enum test_return test_binary_deleteq(void) { 1119 return test_binary_delete_impl("test_binary_deleteq", 1120 PROTOCOL_BINARY_CMD_DELETEQ); 1121 } 1122 1123 static enum test_return test_binary_get_impl(const char *key, uint8_t cmd) { 1124 union { 1125 protocol_binary_request_no_extras request; 1126 protocol_binary_response_no_extras response; 1127 char bytes[1024]; 1128 } send, receive; 1129 size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd, 1130 key, strlen(key), NULL, 0); 1131 1132 safe_send(send.bytes, len, false); 1133 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1134 validate_response_header(&receive.response, cmd, 1135 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT); 1136 1137 len = storage_command(send.bytes, sizeof(send.bytes), 1138 PROTOCOL_BINARY_CMD_ADD, 1139 key, strlen(key), NULL, 0, 1140 0, 0); 1141 safe_send(send.bytes, len, false); 1142 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1143 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD, 1144 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1145 1146 /* run a little pipeline test ;-) */ 1147 len = 0; 1148 int ii; 1149 for (ii = 0; ii < 10; ++ii) { 1150 union { 1151 protocol_binary_request_no_extras request; 1152 char bytes[1024]; 1153 } temp; 1154 size_t l = raw_command(temp.bytes, sizeof(temp.bytes), 1155 cmd, key, strlen(key), NULL, 0); 1156 memcpy(send.bytes + len, temp.bytes, l); 1157 len += l; 1158 } 1159 1160 safe_send(send.bytes, len, false); 1161 for (ii = 0; ii < 10; ++ii) { 1162 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1163 validate_response_header(&receive.response, cmd, 1164 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1165 } 1166 1167 return TEST_PASS; 1168 } 1169 1170 static enum test_return test_binary_get(void) { 1171 return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET); 1172 } 1173 1174 static enum test_return test_binary_getk(void) { 1175 return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK); 1176 } 1177 1178 static enum test_return test_binary_getq_impl(const char *key, uint8_t cmd) { 1179 const char *missing = "test_binary_getq_missing"; 1180 union { 1181 protocol_binary_request_no_extras request; 1182 protocol_binary_response_no_extras response; 1183 char bytes[1024]; 1184 } send, temp, receive; 1185 size_t len = storage_command(send.bytes, sizeof(send.bytes), 1186 PROTOCOL_BINARY_CMD_ADD, 1187 key, strlen(key), NULL, 0, 1188 0, 0); 1189 size_t len2 = raw_command(temp.bytes, sizeof(temp.bytes), cmd, 1190 missing, strlen(missing), NULL, 0); 1191 /* I need to change the first opaque so that I can separate the two 1192 * return packets */ 1193 temp.request.message.header.request.opaque = 0xfeedface; 1194 memcpy(send.bytes + len, temp.bytes, len2); 1195 len += len2; 1196 1197 len2 = raw_command(temp.bytes, sizeof(temp.bytes), cmd, 1198 key, strlen(key), NULL, 0); 1199 memcpy(send.bytes + len, temp.bytes, len2); 1200 len += len2; 1201 1202 safe_send(send.bytes, len, false); 1203 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1204 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD, 1205 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1206 /* The first GETQ shouldn't return anything */ 1207 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1208 validate_response_header(&receive.response, cmd, 1209 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1210 1211 return TEST_PASS; 1212 } 1213 1214 static enum test_return test_binary_getq(void) { 1215 return test_binary_getq_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ); 1216 } 1217 1218 static enum test_return test_binary_getkq(void) { 1219 return test_binary_getq_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ); 1220 } 1221 1222 static enum test_return test_binary_incr_impl(const char* key, uint8_t cmd) { 1223 union { 1224 protocol_binary_request_no_extras request; 1225 protocol_binary_response_no_extras response_header; 1226 protocol_binary_response_incr response; 1227 char bytes[1024]; 1228 } send, receive; 1229 size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd, 1230 key, strlen(key), 1, 0, 0); 1231 1232 int ii; 1233 for (ii = 0; ii < 10; ++ii) { 1234 safe_send(send.bytes, len, false); 1235 if (cmd == PROTOCOL_BINARY_CMD_INCREMENT) { 1236 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1237 validate_response_header(&receive.response_header, cmd, 1238 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1239 assert(ntohll(receive.response.message.body.value) == ii); 1240 } 1241 } 1242 1243 if (cmd == PROTOCOL_BINARY_CMD_INCREMENTQ) { 1244 test_binary_noop(); 1245 } 1246 return TEST_PASS; 1247 } 1248 1249 static enum test_return test_binary_incr(void) { 1250 return test_binary_incr_impl("test_binary_incr", 1251 PROTOCOL_BINARY_CMD_INCREMENT); 1252 } 1253 1254 static enum test_return test_binary_incrq(void) { 1255 return test_binary_incr_impl("test_binary_incrq", 1256 PROTOCOL_BINARY_CMD_INCREMENTQ); 1257 } 1258 1259 static enum test_return test_binary_decr_impl(const char* key, uint8_t cmd) { 1260 union { 1261 protocol_binary_request_no_extras request; 1262 protocol_binary_response_no_extras response_header; 1263 protocol_binary_response_decr response; 1264 char bytes[1024]; 1265 } send, receive; 1266 size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd, 1267 key, strlen(key), 1, 9, 0); 1268 1269 int ii; 1270 for (ii = 9; ii >= 0; --ii) { 1271 safe_send(send.bytes, len, false); 1272 if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) { 1273 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1274 validate_response_header(&receive.response_header, cmd, 1275 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1276 assert(ntohll(receive.response.message.body.value) == ii); 1277 } 1278 } 1279 1280 /* decr on 0 should not wrap */ 1281 safe_send(send.bytes, len, false); 1282 if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) { 1283 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1284 validate_response_header(&receive.response_header, cmd, 1285 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1286 assert(ntohll(receive.response.message.body.value) == 0); 1287 } else { 1288 test_binary_noop(); 1289 } 1290 1291 return TEST_PASS; 1292 } 1293 1294 static enum test_return test_binary_decr(void) { 1295 return test_binary_decr_impl("test_binary_decr", 1296 PROTOCOL_BINARY_CMD_DECREMENT); 1297 } 1298 1299 static enum test_return test_binary_decrq(void) { 1300 return test_binary_decr_impl("test_binary_decrq", 1301 PROTOCOL_BINARY_CMD_DECREMENTQ); 1302 } 1303 1304 static enum test_return test_binary_version(void) { 1305 union { 1306 protocol_binary_request_no_extras request; 1307 protocol_binary_response_no_extras response; 1308 char bytes[1024]; 1309 } buffer; 1310 1311 size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes), 1312 PROTOCOL_BINARY_CMD_VERSION, 1313 NULL, 0, NULL, 0); 1314 1315 safe_send(buffer.bytes, len, false); 1316 safe_recv_packet(buffer.bytes, sizeof(buffer.bytes)); 1317 validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_VERSION, 1318 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1319 1320 return TEST_PASS; 1321 } 1322 1323 static enum test_return test_binary_flush_impl(const char *key, uint8_t cmd) { 1324 union { 1325 protocol_binary_request_no_extras request; 1326 protocol_binary_response_no_extras response; 1327 char bytes[1024]; 1328 } send, receive; 1329 1330 size_t len = storage_command(send.bytes, sizeof(send.bytes), 1331 PROTOCOL_BINARY_CMD_ADD, 1332 key, strlen(key), NULL, 0, 0, 0); 1333 safe_send(send.bytes, len, false); 1334 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1335 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD, 1336 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1337 1338 len = flush_command(send.bytes, sizeof(send.bytes), cmd, 2, true); 1339 safe_send(send.bytes, len, false); 1340 if (cmd == PROTOCOL_BINARY_CMD_FLUSH) { 1341 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1342 validate_response_header(&receive.response, cmd, 1343 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1344 } 1345 1346 len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GET, 1347 key, strlen(key), NULL, 0); 1348 safe_send(send.bytes, len, false); 1349 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1350 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET, 1351 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1352 1353 sleep(2); 1354 safe_send(send.bytes, len, false); 1355 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1356 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET, 1357 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT); 1358 1359 int ii; 1360 for (ii = 0; ii < 2; ++ii) { 1361 len = storage_command(send.bytes, sizeof(send.bytes), 1362 PROTOCOL_BINARY_CMD_ADD, 1363 key, strlen(key), NULL, 0, 0, 0); 1364 safe_send(send.bytes, len, false); 1365 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1366 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD, 1367 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1368 1369 len = flush_command(send.bytes, sizeof(send.bytes), cmd, 0, ii == 0); 1370 safe_send(send.bytes, len, false); 1371 if (cmd == PROTOCOL_BINARY_CMD_FLUSH) { 1372 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1373 validate_response_header(&receive.response, cmd, 1374 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1375 } 1376 1377 len = raw_command(send.bytes, sizeof(send.bytes), 1378 PROTOCOL_BINARY_CMD_GET, 1379 key, strlen(key), NULL, 0); 1380 safe_send(send.bytes, len, false); 1381 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1382 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET, 1383 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT); 1384 } 1385 1386 return TEST_PASS; 1387 } 1388 1389 static enum test_return test_binary_flush(void) { 1390 return test_binary_flush_impl("test_binary_flush", 1391 PROTOCOL_BINARY_CMD_FLUSH); 1392 } 1393 1394 static enum test_return test_binary_flushq(void) { 1395 return test_binary_flush_impl("test_binary_flushq", 1396 PROTOCOL_BINARY_CMD_FLUSHQ); 1397 } 1398 1399 static enum test_return test_binary_concat_impl(const char *key, uint8_t cmd) { 1400 union { 1401 protocol_binary_request_no_extras request; 1402 protocol_binary_response_no_extras response; 1403 char bytes[1024]; 1404 } send, receive; 1405 const char *value = "world"; 1406 1407 size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd, 1408 key, strlen(key), value, strlen(value)); 1409 1410 1411 safe_send(send.bytes, len, false); 1412 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1413 validate_response_header(&receive.response, cmd, 1414 PROTOCOL_BINARY_RESPONSE_NOT_STORED); 1415 1416 len = storage_command(send.bytes, sizeof(send.bytes), 1417 PROTOCOL_BINARY_CMD_ADD, 1418 key, strlen(key), value, strlen(value), 0, 0); 1419 safe_send(send.bytes, len, false); 1420 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1421 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD, 1422 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1423 1424 len = raw_command(send.bytes, sizeof(send.bytes), cmd, 1425 key, strlen(key), value, strlen(value)); 1426 safe_send(send.bytes, len, false); 1427 1428 if (cmd == PROTOCOL_BINARY_CMD_APPEND || cmd == PROTOCOL_BINARY_CMD_PREPEND) { 1429 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1430 validate_response_header(&receive.response, cmd, 1431 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1432 } else { 1433 len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_NOOP, 1434 NULL, 0, NULL, 0); 1435 safe_send(send.bytes, len, false); 1436 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1437 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_NOOP, 1438 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1439 } 1440 1441 len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GETK, 1442 key, strlen(key), NULL, 0); 1443 1444 safe_send(send.bytes, len, false); 1445 safe_recv_packet(receive.bytes, sizeof(receive.bytes)); 1446 validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GETK, 1447 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1448 1449 assert(receive.response.message.header.response.keylen == strlen(key)); 1450 assert(receive.response.message.header.response.bodylen == (strlen(key) + 2*strlen(value) + 4)); 1451 1452 char *ptr = receive.bytes; 1453 ptr += sizeof(receive.response); 1454 ptr += 4; 1455 1456 assert(memcmp(ptr, key, strlen(key)) == 0); 1457 ptr += strlen(key); 1458 assert(memcmp(ptr, value, strlen(value)) == 0); 1459 ptr += strlen(value); 1460 assert(memcmp(ptr, value, strlen(value)) == 0); 1461 1462 return TEST_PASS; 1463 } 1464 1465 static enum test_return test_binary_append(void) { 1466 return test_binary_concat_impl("test_binary_append", 1467 PROTOCOL_BINARY_CMD_APPEND); 1468 } 1469 1470 static enum test_return test_binary_prepend(void) { 1471 return test_binary_concat_impl("test_binary_prepend", 1472 PROTOCOL_BINARY_CMD_PREPEND); 1473 } 1474 1475 static enum test_return test_binary_appendq(void) { 1476 return test_binary_concat_impl("test_binary_appendq", 1477 PROTOCOL_BINARY_CMD_APPENDQ); 1478 } 1479 1480 static enum test_return test_binary_prependq(void) { 1481 return test_binary_concat_impl("test_binary_prependq", 1482 PROTOCOL_BINARY_CMD_PREPENDQ); 1483 } 1484 1485 static enum test_return test_binary_stat(void) { 1486 union { 1487 protocol_binary_request_no_extras request; 1488 protocol_binary_response_no_extras response; 1489 char bytes[1024]; 1490 } buffer; 1491 1492 size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes), 1493 PROTOCOL_BINARY_CMD_STAT, 1494 NULL, 0, NULL, 0); 1495 1496 safe_send(buffer.bytes, len, false); 1497 do { 1498 safe_recv_packet(buffer.bytes, sizeof(buffer.bytes)); 1499 validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_STAT, 1500 PROTOCOL_BINARY_RESPONSE_SUCCESS); 1501 } while (buffer.response.message.header.response.keylen != 0); 1502 1503 return TEST_PASS; 1504 } 1505 1506 static enum test_return test_binary_illegal(void) { 1507 uint8_t cmd = 0x1b; 1508 while (cmd != 0x00) { 1509 union { 1510 protocol_binary_request_no_extras request; 1511 protocol_binary_response_no_extras response; 1512 char bytes[1024]; 1513 } buffer; 1514 size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes), 1515 cmd, NULL, 0, NULL, 0); 1516 safe_send(buffer.bytes, len, false); 1517 safe_recv_packet(buffer.bytes, sizeof(buffer.bytes)); 1518 validate_response_header(&buffer.response, cmd, 1519 PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND); 1520 ++cmd; 1521 } 1522 1523 return TEST_PASS; 1524 } 1525 1526 volatile bool hickup_thread_running; 1527 1528 static void *binary_hickup_recv_verification_thread(void *arg) { 1529 protocol_binary_response_no_extras *response = malloc(65*1024); 1530 if (response != NULL) { 1531 while (safe_recv_packet(response, 65*1024)) { 1532 /* Just validate the packet format */ 1533 validate_response_header(response, 1534 response->message.header.response.opcode, 1535 response->message.header.response.status); 1536 } 1537 free(response); 1538 } 1539 hickup_thread_running = false; 1540 allow_closed_read = false; 1541 return NULL; 1542 } 1543 1544 static enum test_return test_binary_pipeline_hickup_chunk(void *buffer, size_t buffersize) { 1545 off_t offset = 0; 1546 char *key[256]; 1547 uint64_t value = 0xfeedfacedeadbeef; 1548 1549 while (hickup_thread_running && 1550 offset + sizeof(protocol_binary_request_no_extras) < buffersize) { 1551 union { 1552 protocol_binary_request_no_extras request; 1553 char bytes[65 * 1024]; 1554 } command; 1555 uint8_t cmd = (uint8_t)(rand() & 0xff); 1556 size_t len; 1557 size_t keylen = (rand() % 250) + 1; 1558 1559 switch (cmd) { 1560 case PROTOCOL_BINARY_CMD_ADD: 1561 case PROTOCOL_BINARY_CMD_ADDQ: 1562 case PROTOCOL_BINARY_CMD_REPLACE: 1563 case PROTOCOL_BINARY_CMD_REPLACEQ: 1564 case PROTOCOL_BINARY_CMD_SET: 1565 case PROTOCOL_BINARY_CMD_SETQ: 1566 len = storage_command(command.bytes, sizeof(command.bytes), cmd, 1567 key, keylen , &value, sizeof(value), 1568 0, 0); 1569 break; 1570 case PROTOCOL_BINARY_CMD_APPEND: 1571 case PROTOCOL_BINARY_CMD_APPENDQ: 1572 case PROTOCOL_BINARY_CMD_PREPEND: 1573 case PROTOCOL_BINARY_CMD_PREPENDQ: 1574 len = raw_command(command.bytes, sizeof(command.bytes), cmd, 1575 key, keylen, &value, sizeof(value)); 1576 break; 1577 case PROTOCOL_BINARY_CMD_FLUSH: 1578 case PROTOCOL_BINARY_CMD_FLUSHQ: 1579 len = raw_command(command.bytes, sizeof(command.bytes), cmd, 1580 NULL, 0, NULL, 0); 1581 break; 1582 case PROTOCOL_BINARY_CMD_NOOP: 1583 len = raw_command(command.bytes, sizeof(command.bytes), cmd, 1584 NULL, 0, NULL, 0); 1585 break; 1586 case PROTOCOL_BINARY_CMD_DELETE: 1587 case PROTOCOL_BINARY_CMD_DELETEQ: 1588 len = raw_command(command.bytes, sizeof(command.bytes), cmd, 1589 key, keylen, NULL, 0); 1590 break; 1591 case PROTOCOL_BINARY_CMD_DECREMENT: 1592 case PROTOCOL_BINARY_CMD_DECREMENTQ: 1593 case PROTOCOL_BINARY_CMD_INCREMENT: 1594 case PROTOCOL_BINARY_CMD_INCREMENTQ: 1595 len = arithmetic_command(command.bytes, sizeof(command.bytes), cmd, 1596 key, keylen, 1, 0, 0); 1597 break; 1598 case PROTOCOL_BINARY_CMD_VERSION: 1599 len = raw_command(command.bytes, sizeof(command.bytes), 1600 PROTOCOL_BINARY_CMD_VERSION, 1601 NULL, 0, NULL, 0); 1602 break; 1603 case PROTOCOL_BINARY_CMD_GET: 1604 case PROTOCOL_BINARY_CMD_GETK: 1605 case PROTOCOL_BINARY_CMD_GETKQ: 1606 case PROTOCOL_BINARY_CMD_GETQ: 1607 len = raw_command(command.bytes, sizeof(command.bytes), cmd, 1608 key, keylen, NULL, 0); 1609 break; 1610 1611 case PROTOCOL_BINARY_CMD_STAT: 1612 len = raw_command(command.bytes, sizeof(command.bytes), 1613 PROTOCOL_BINARY_CMD_STAT, 1614 NULL, 0, NULL, 0); 1615 break; 1616 1617 case PROTOCOL_BINARY_CMD_QUITQ: 1618 case PROTOCOL_BINARY_CMD_QUIT: 1619 /* I don't want to pass on the quit commands ;-) */ 1620 cmd |= 0xf0; 1621 /* FALLTHROUGH */ 1622 default: 1623 len = raw_command(command.bytes, sizeof(command.bytes), 1624 cmd, NULL, 0, NULL, 0); 1625 } 1626 1627 if ((len + offset) < buffersize) { 1628 memcpy(((char*)buffer) + offset, command.bytes, len); 1629 offset += len; 1630 } else { 1631 break; 1632 } 1633 } 1634 safe_send(buffer, offset, true); 1635 1636 return TEST_PASS; 1637 } 1638 1639 static enum test_return test_binary_pipeline_hickup(void) 1640 { 1641 size_t buffersize = 65 * 1024; 1642 void *buffer = malloc(buffersize); 1643 int ii; 1644 1645 pthread_t tid; 1646 int ret; 1647 allow_closed_read = true; 1648 hickup_thread_running = true; 1649 if ((ret = pthread_create(&tid, NULL, 1650 binary_hickup_recv_verification_thread, NULL)) != 0) { 1651 fprintf(stderr, "Can't create thread: %s\n", strerror(ret)); 1652 return TEST_FAIL; 1653 } 1654 1655 /* Allow the thread to start */ 1656 usleep(250); 1657 1658 srand((int)time(NULL)); 1659 for (ii = 0; ii < 2; ++ii) { 1660 test_binary_pipeline_hickup_chunk(buffer, buffersize); 1661 } 1662 1663 /* send quitq to shut down the read thread ;-) */ 1664 size_t len = raw_command(buffer, buffersize, PROTOCOL_BINARY_CMD_QUITQ, 1665 NULL, 0, NULL, 0); 1666 safe_send(buffer, len, false); 1667 1668 pthread_join(tid, NULL); 1669 free(buffer); 1670 return TEST_PASS; 1671 } 1672 1673 typedef enum test_return (*TEST_FUNC)(void); 1674 struct testcase { 1675 const char *description; 1676 TEST_FUNC function; 1677 }; 1678 1679 struct testcase testcases[] = { 1680 { "cache_create", cache_create_test }, 1681 { "cache_constructor", cache_constructor_test }, 1682 { "cache_constructor_fail", cache_fail_constructor_test }, 1683 { "cache_destructor", cache_destructor_test }, 1684 { "cache_reuse", cache_reuse_test }, 1685 { "cache_redzone", cache_redzone_test }, 1686 { "strtol", test_safe_strtol }, 1687 { "strtoll", test_safe_strtoll }, 1688 { "strtoul", test_safe_strtoul }, 1689 { "strtoull", test_safe_strtoull }, 1690 { "issue_44", test_issue_44 }, 1691 { "issue_72", test_issue_72 }, 1692 { "vperror", test_vperror }, 1693 /* The following tests all run towards the same server */ 1694 { "start_server", start_memcached_server }, 1695 { "issue_92", test_issue_92 }, 1696 { "binary_noop", test_binary_noop }, 1697 { "binary_quit", test_binary_quit }, 1698 { "binary_quitq", test_binary_quitq }, 1699 { "binary_set", test_binary_set }, 1700 { "binary_setq", test_binary_setq }, 1701 { "binary_add", test_binary_add }, 1702 { "binary_addq", test_binary_addq }, 1703 { "binary_replace", test_binary_replace }, 1704 { "binary_replaceq", test_binary_replaceq }, 1705 { "binary_delete", test_binary_delete }, 1706 { "binary_deleteq", test_binary_deleteq }, 1707 { "binary_get", test_binary_get }, 1708 { "binary_getq", test_binary_getq }, 1709 { "binary_getk", test_binary_getk }, 1710 { "binary_getkq", test_binary_getkq }, 1711 { "binary_incr", test_binary_incr }, 1712 { "binary_incrq", test_binary_incrq }, 1713 { "binary_decr", test_binary_decr }, 1714 { "binary_decrq", test_binary_decrq }, 1715 { "binary_version", test_binary_version }, 1716 { "binary_flush", test_binary_flush }, 1717 { "binary_flushq", test_binary_flushq }, 1718 { "binary_append", test_binary_append }, 1719 { "binary_appendq", test_binary_appendq }, 1720 { "binary_prepend", test_binary_prepend }, 1721 { "binary_prependq", test_binary_prependq }, 1722 { "binary_stat", test_binary_stat }, 1723 { "binary_illegal", test_binary_illegal }, 1724 { "binary_pipeline_hickup", test_binary_pipeline_hickup }, 1725 { "stop_server", stop_memcached_server }, 1726 { NULL, NULL } 1727 }; 1728 1729 int main(int argc, char **argv) 1730 { 1731 int exitcode = 0; 1732 int ii = 0, num_cases = 0; 1733 1734 for (num_cases = 0; testcases[num_cases].description; num_cases++) { 1735 /* Just counting */ 1736 } 1737 1738 printf("1..%d\n", num_cases); 1739 1740 for (ii = 0; testcases[ii].description != NULL; ++ii) { 1741 fflush(stdout); 1742 #ifndef DEBUG 1743 /* the test program shouldn't run longer than 10 minutes... */ 1744 alarm(600); 1745 #endif 1746 enum test_return ret = testcases[ii].function(); 1747 if (ret == TEST_SKIP) { 1748 fprintf(stdout, "ok # SKIP %d - %s\n", ii + 1, testcases[ii].description); 1749 } else if (ret == TEST_PASS) { 1750 fprintf(stdout, "ok %d - %s\n", ii + 1, testcases[ii].description); 1751 } else { 1752 fprintf(stdout, "not ok %d - %s\n", ii + 1, testcases[ii].description); 1753 exitcode = 1; 1754 } 1755 fflush(stdout); 1756 } 1757 1758 return exitcode; 1759 } 1760