1/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
3/*
4    Memcached protocol extensions for testapp.
5
6    Provides extended protocol commands to enable interesting testcases.
7
8    1. Currently supports shifting the Memcached's timeofday.
9      * protocol command can be overridden in config.
10*/
11
12#include "config.h"
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/types.h>
17#include <inttypes.h>
18
19#include "extensions/protocol_extension.h"
20#include <memcached/util.h>
21#include <platform/platform.h>
22#include "extensions/protocol/testapp_extension.h"
23
24static uint8_t adjust_timeofday_command = PROTOCOL_BINARY_CMD_ADJUST_TIMEOFDAY;
25
26GET_SERVER_API server_api;
27
28static const char *get_name(void);
29static void setup(void (*add)(EXTENSION_BINARY_PROTOCOL_DESCRIPTOR *descriptor,
30                              uint8_t cmd,
31                              BINARY_COMMAND_CALLBACK new_handler));
32
33static ENGINE_ERROR_CODE handle_adjust_time(EXTENSION_BINARY_PROTOCOL_DESCRIPTOR *descriptor,
34                                            ENGINE_HANDLE* handle,
35                                            const void* cookie,
36                                            protocol_binary_request_header *request,
37                                            ADD_RESPONSE response);
38
39static EXTENSION_BINARY_PROTOCOL_DESCRIPTOR descriptor;
40
41static const char *get_name(void) {
42    return "testapp protocol extension";
43}
44
45static void setup(void (*add)(EXTENSION_BINARY_PROTOCOL_DESCRIPTOR *descriptor,
46                              uint8_t cmd,
47                              BINARY_COMMAND_CALLBACK new_handler))
48{
49    add(&descriptor, adjust_timeofday_command, handle_adjust_time);
50}
51
52
53static ENGINE_ERROR_CODE handle_adjust_time(EXTENSION_BINARY_PROTOCOL_DESCRIPTOR *descriptor,
54                                            ENGINE_HANDLE* handle,
55                                            const void* cookie,
56                                            protocol_binary_request_header *request,
57                                            ADD_RESPONSE response)
58{
59    protocol_binary_adjust_time *req = (protocol_binary_adjust_time*)request;
60    ENGINE_ERROR_CODE r = ENGINE_SUCCESS;
61    uint64_t offset = 0;
62
63    offset = ntohll(req->message.body.offset);
64
65    if (r == ENGINE_SUCCESS) {
66
67        if (r == ENGINE_SUCCESS) {
68            if (request->request.opcode == adjust_timeofday_command) {
69                cb_set_timeofday_offset(offset);
70
71                if (!response(NULL, 0, NULL, 0, NULL, 0,
72                                PROTOCOL_BINARY_RAW_BYTES,
73                                PROTOCOL_BINARY_RESPONSE_SUCCESS,
74                                0, cookie)) {
75                    return ENGINE_DISCONNECT;
76                }
77            } else {
78                if (!response(NULL, 0, NULL, 0, NULL, 0,
79                                PROTOCOL_BINARY_RAW_BYTES,
80                                PROTOCOL_BINARY_RESPONSE_SUCCESS,
81                                0, cookie)) {
82                    return ENGINE_DISCONNECT;
83                }
84            }
85
86        }
87    }
88    return r;
89}
90
91MEMCACHED_PUBLIC_API
92EXTENSION_ERROR_CODE memcached_extensions_initialize(const char *config,
93                                                     GET_SERVER_API get_server_api) {
94    SERVER_HANDLE_V1 *server = get_server_api();
95    server_api = get_server_api;
96    descriptor.get_name = get_name;
97    descriptor.setup = setup;
98
99    if (server == NULL) {
100        return EXTENSION_FATAL;
101    }
102
103    if (config != NULL) {
104        size_t time_op = 0;
105        struct config_item items[2];
106        memset(&items, 0, sizeof(items));
107
108        items[0].key = "t";
109        items[0].datatype = DT_SIZE;
110        items[0].value.dt_size = &time_op;
111        items[2].key = NULL;
112
113        if (server->core->parse_config(config, items, stderr) != 0) {
114            return EXTENSION_FATAL;
115        }
116
117        if (items[0].found) {
118            adjust_timeofday_command = (uint8_t)(time_op & 0xff);
119        }
120    }
121
122    if (!server->extension->register_extension(EXTENSION_BINARY_PROTOCOL,
123                                               &descriptor)) {
124        return EXTENSION_FATAL;
125    }
126
127    return EXTENSION_SUCCESS;
128}
129