MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
example_protocol.c
1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 
6 #include "protocol_extension.h"
7 
8 /*
9  * This is an example on how you can add your own commands into the
10  * ascii protocol. You load the extensions into memcached by using
11  * the -X option:
12  * ./memcached -X .libs/example_protocol.so -E .libs/default_engine.so
13  *
14  * @todo add an example that require extra userspace data, and communicates
15  * with the engine by getting the engine descriptor.
16  */
17 
18 static const char *get_name(const void *cmd_cookie);
19 static bool accept_command(const void *cmd_cookie, void *cookie,
20  int argc, token_t *argv, size_t *ndata,
21  char **ptr);
22 static ENGINE_ERROR_CODE execute_command(const void *cmd_cookie, const void *cookie,
23  int argc, token_t *argv,
24  ENGINE_ERROR_CODE (*response_handler)(const void *cookie,
25  int nbytes,
26  const char *dta));
27 static void abort_command(const void *cmd_cookie, const void *cookie);
28 
29 static EXTENSION_ASCII_PROTOCOL_DESCRIPTOR noop_descriptor = {
30  .get_name = get_name,
31  .accept = accept_command,
32  .execute = execute_command,
33  .abort = abort_command,
34  .cookie = &noop_descriptor
35 };
36 
37 static EXTENSION_ASCII_PROTOCOL_DESCRIPTOR echo_descriptor = {
38  .get_name = get_name,
39  .accept = accept_command,
40  .execute = execute_command,
41  .abort = abort_command,
42  .cookie = &echo_descriptor
43 };
44 
45 static const char *get_name(const void *cmd_cookie) {
46  if (cmd_cookie == &noop_descriptor) {
47  return "noop";
48  } else {
49  return "echo";
50  }
51 }
52 
53 static bool accept_command(const void *cmd_cookie, void *cookie,
54  int argc, token_t *argv, size_t *ndata,
55  char **ptr) {
56  if (cmd_cookie == &noop_descriptor) {
57  return strcmp(argv[0].value, "noop") == 0;
58  } else {
59  return strcmp(argv[0].value, "echo") == 0;
60  }
61 }
62 
63 static ENGINE_ERROR_CODE execute_command(const void *cmd_cookie, const void *cookie,
64  int argc, token_t *argv,
65  ENGINE_ERROR_CODE (*response_handler)(const void *cookie,
66  int nbytes,
67  const char *dta))
68 {
69  if (cmd_cookie == &noop_descriptor) {
70  return response_handler(cookie, 4, "OK\r\n");
71  } else {
72  if (response_handler(cookie, argv[0].length, argv[0].value) != ENGINE_SUCCESS) {
73  return ENGINE_DISCONNECT;
74  }
75 
76  for (int ii = 1; ii < argc; ++ii) {
77  if (response_handler(cookie, 2, " [") != ENGINE_SUCCESS ||
78  response_handler(cookie, argv[ii].length, argv[ii].value) != ENGINE_SUCCESS ||
79  response_handler(cookie, 1, "]") != ENGINE_SUCCESS) {
80  return ENGINE_DISCONNECT;
81  }
82  }
83 
84  return response_handler(cookie, 2, "\r\n");
85  }
86 }
87 
88 static void abort_command(const void *cmd_cookie, const void *cookie)
89 {
90  /* EMPTY */
91 }
92 
93 #if defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550)
94 __global
95 #elif defined __GNUC__
96 __attribute__ ((visibility("default")))
97 #endif
98 EXTENSION_ERROR_CODE memcached_extensions_initialize(const char *config,
99  GET_SERVER_API get_server_api) {
100  SERVER_HANDLE_V1 *server = get_server_api();
101  if (server == NULL) {
102  return EXTENSION_FATAL;
103  }
104  if (!server->extension->register_extension(EXTENSION_ASCII_PROTOCOL,
105  &noop_descriptor)) {
106  return EXTENSION_FATAL;
107  }
108 
109  if (!server->extension->register_extension(EXTENSION_ASCII_PROTOCOL,
110  &echo_descriptor)) {
111  return EXTENSION_FATAL;
112  }
113 
114  return EXTENSION_SUCCESS;
115 }