1/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2#include "config.h"
3
4#include <memcached/protocol_binary.h>
5#include <memcached/openssl.h>
6#include <platform/platform.h>
7
8#include <getopt.h>
9#include <stdlib.h>
10#include <stdio.h>
11
12#include "programs/utilities.h"
13
14
15static void *get_response(BIO *bio, protocol_binary_response_no_extras *res) {
16    uint32_t vallen;
17
18    ensure_recv(bio, res, sizeof(*res));
19    vallen = ntohl(res->message.header.response.bodylen);
20
21    if (vallen == 0) {
22        return NULL;
23    } else {
24        void *buffer = malloc(vallen);
25        cb_assert(buffer != NULL);
26        ensure_recv(bio, buffer, vallen);
27        return buffer;
28    }
29}
30
31static void store(BIO *bio,
32                  const void *key,
33                  uint16_t nkey,
34                  const void *bytes,
35                  uint32_t nbytes)
36{
37    protocol_binary_request_set request;
38    protocol_binary_response_no_extras response;
39    void *payload;
40
41    memset(&request, 0, sizeof(request));
42    request.message.header.request.magic = PROTOCOL_BINARY_REQ;
43    request.message.header.request.opcode = PROTOCOL_BINARY_CMD_SET;
44    request.message.header.request.keylen = htons((uint16_t)nkey);
45    request.message.header.request.extlen = 8;
46    request.message.header.request.bodylen = htonl(nkey + 8 + nbytes);
47
48    ensure_send(bio, &request, sizeof(request.bytes));
49    ensure_send(bio, key, nkey);
50    ensure_send(bio, bytes, nbytes);
51    if (BIO_flush(bio) != 1) {
52        fprintf(stderr, "Failed to flush bio instance\n");
53        exit(EXIT_FAILURE);
54    }
55
56    payload = get_response(bio, &response);
57    free(payload);
58    cb_assert(ntohs(response.message.header.response.status) == PROTOCOL_BINARY_RESPONSE_SUCCESS);
59}
60
61static char * fetch(BIO *bio,
62                  const void *key,
63                  uint16_t nkey)
64{
65    protocol_binary_request_get request;
66    protocol_binary_response_no_extras response;
67    char *payload;
68
69    memset(&request, 0, sizeof(request));
70    request.message.header.request.magic = PROTOCOL_BINARY_REQ;
71    request.message.header.request.opcode = PROTOCOL_BINARY_CMD_GET;
72    request.message.header.request.keylen = htons((uint16_t)nkey);
73    request.message.header.request.bodylen = htonl(nkey);
74
75    ensure_send(bio, &request, sizeof(request.bytes));
76    ensure_send(bio, key, nkey);
77    if (BIO_flush(bio) != 1) {
78        fprintf(stderr, "Failed to flush bio instance\n");
79        exit(EXIT_FAILURE);
80    }
81
82    payload = get_response(bio, &response);
83    cb_assert(ntohs(response.message.header.response.status) == PROTOCOL_BINARY_RESPONSE_SUCCESS);
84    cb_assert(payload != NULL);
85    return payload;
86
87}
88
89
90static void do_ssl_test(BIO *bio)
91{
92    uint32_t datalen = 512*1024;
93    void *data = malloc(datalen);
94    char *rcv = NULL;
95    const char *key = "Hello World";
96    int ii;
97
98    for (ii = 0; ii < 1024; ++ii) {
99        fprintf(stdout, "%u\n", ii);
100        store(bio, key, (uint16_t)strlen(key), data, datalen);
101        rcv = fetch(bio, key, (uint16_t)strlen(key));
102        cb_assert(memcmp(data, rcv + 4, datalen) == 0);
103        free(rcv);
104    }
105}
106
107int main(int argc, char** argv) {
108    int cmd;
109    const char *port = "11210";
110    const char *host = "localhost";
111    const char *user = NULL;
112    const char *pass = NULL;
113    int secure = 0;
114    char *ptr;
115    SSL_CTX* ctx;
116    BIO* bio;
117
118    /* Initialize the socket subsystem */
119    cb_initialize_sockets();
120
121    while ((cmd = getopt(argc, argv, "h:p:u:P:s")) != EOF) {
122        switch (cmd) {
123        case 'h' :
124            host = optarg;
125            ptr = strchr(optarg, ':');
126            if (ptr != NULL) {
127                *ptr = '\0';
128                port = ptr + 1;
129            }
130            break;
131        case 'p':
132            port = optarg;
133            break;
134        case 'u' :
135            user = optarg;
136            break;
137        case 'P':
138            pass = optarg;
139            break;
140        case 's':
141            secure = 1;
142            break;
143        default:
144            fprintf(stderr,
145                    "Usage ssltest [-h host[:port]] [-p port] [-u user] [-p pass] [-s]\n");
146            return 1;
147        }
148    }
149
150    if (create_ssl_connection(&ctx, &bio, host, port, user, pass, secure) != 0) {
151        return 1;
152    }
153
154    do_ssl_test(bio);
155
156    BIO_free_all(bio);
157    if (secure) {
158        SSL_CTX_free(ctx);
159    }
160
161    return EXIT_SUCCESS;
162}
163