summaryrefslogtreecommitdiff
path: root/testapp.c
diff options
context:
space:
mode:
authorTrond Norbye <Trond.Norbye@sun.com>2009-08-11 17:31:35 +0200
committerDustin Sallings <dustin@spy.net>2009-08-14 17:51:01 -0700
commit7bb82191573d7eb11f35dc3573a68bf811bae25c (patch)
tree5abc6b6c2a0b90e8cfc372d06145dd00e2df6cc9 /testapp.c
parentb8e106f775db38b50602470142136530c20b1125 (diff)
downloadmemcached-7bb82191573d7eb11f35dc3573a68bf811bae25c.tar.gz
Fix for issue 72: 1.4.0 binary multi-get crash issue
Repack the input buffer if the current command and key doesn't fit in the input buffer (may occur if we read multiple commands in a pipeline) (Dustin's note): The original test was connecting to "localhost" which was resolving to ::1 on a few machines. With the ephemeral port binding, IPv4 and IPv6 were getting different ports, and the code was explicitly looking for the IPv4 port, but implicitly connecting to ::1. Now it explicitly connects to 127.0.0.1 over IPv4.
Diffstat (limited to 'testapp.c')
-rw-r--r--testapp.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/testapp.c b/testapp.c
index 3316968..7c3d3e1 100644
--- a/testapp.c
+++ b/testapp.c
@@ -1,5 +1,11 @@
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#undef NDEBUG
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -11,6 +17,7 @@
#include <unistd.h>
#include <netinet/in.h>
+#include "protocol_binary.h"
#include "config.h"
#include "cache.h"
#include "util.h"
@@ -333,6 +340,78 @@ static enum test_return test_issue_44(void) {
return TEST_PASS;
}
+static struct addrinfo *lookuphost(const char *hostname, in_port_t port)
+{
+ struct addrinfo *ai = 0;
+ struct addrinfo hints = { .ai_family = AF_UNSPEC,
+ .ai_protocol = IPPROTO_TCP,
+ .ai_socktype = SOCK_STREAM };
+ char service[NI_MAXSERV];
+ int error;
+
+ (void)snprintf(service, NI_MAXSERV, "%d", port);
+ if ((error = getaddrinfo(hostname, service, &hints, &ai)) != 0) {
+ if (error != EAI_SYSTEM) {
+ fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
+ } else {
+ perror("getaddrinfo()");
+ }
+ }
+
+ return ai;
+}
+
+static int connect_server(const char *hostname, in_port_t port)
+{
+ struct addrinfo *ai = lookuphost(hostname, port);
+ int sock = -1;
+ if (ai != NULL) {
+ if ((sock = socket(ai->ai_family, ai->ai_socktype,
+ ai->ai_protocol)) != -1) {
+ if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
+ fprintf(stderr, "Failed to connect socket: %s\n",
+ strerror(errno));
+ close(sock);
+ sock = -1;
+ }
+ } else {
+ fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
+ }
+
+ freeaddrinfo(ai);
+ }
+ return sock;
+}
+
+
+static enum test_return test_issue_72(void) {
+ in_port_t port;
+ pid_t pid = start_server(&port, false);
+ int sock = connect_server("127.0.0.1", port);
+ assert(sock != -1);
+
+ char data[sizeof(protocol_binary_request_set) + 2048] = { 0 };
+ protocol_binary_request_set *request = (protocol_binary_request_set*)data;
+ request->message.header.request.magic = PROTOCOL_BINARY_REQ;
+ request->message.header.request.opcode = PROTOCOL_BINARY_CMD_SET;
+ uint16_t keylen = 2048;
+ request->message.header.request.keylen = htons(keylen);
+ request->message.header.request.extlen = 8;
+ request->message.header.request.bodylen = htonl(keylen + 8);
+
+ assert(write(sock, data, 2000) == 2000);
+ usleep(250);
+ assert(write(sock, data, sizeof(data) - 2000) == sizeof(data) - 2000);
+
+ protocol_binary_response_set response;
+ assert(read(sock, &response, sizeof(response)) == sizeof(response));
+ assert(response.message.header.response.magic == PROTOCOL_BINARY_RES);
+ assert(response.message.header.response.status == PROTOCOL_BINARY_RESPONSE_SUCCESS);
+ close(sock);
+ assert(kill(pid, SIGTERM) == 0);
+ return TEST_PASS;
+}
+
typedef enum test_return (*TEST_FUNC)(void);
struct testcase {
const char *description;
@@ -351,6 +430,7 @@ struct testcase testcases[] = {
{ "strtoul", test_safe_strtoul },
{ "strtoull", test_safe_strtoull },
{ "issue_44", test_issue_44 },
+ { "issue_72", test_issue_72 },
{ NULL, NULL }
};