1 /* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
3 * This file contains an implementation of the callback interface for level 0
4 * in the protocol library. You might want to have your copy of the protocol
5 * specification next to your coffee ;-)
8 #include "mem_config.h"
11 #include <sys/types.h>
21 #include <libmemcachedprotocol-0.0/handler.h>
22 #include <example/byteorder.h>
23 #include "example/memcached_light.h"
24 #include "example/storage.h"
25 #include "util/log.hpp"
28 using namespace datadifferential
;
30 static util::log_info_st
*log_file
= NULL
;
32 static protocol_binary_response_status
noop_command_handler(const void *cookie
,
33 protocol_binary_request_header
*header
,
34 memcached_binary_protocol_raw_response_handler response_handler
)
36 protocol_binary_response_no_extras response
;
37 memset(&response
, 0, sizeof(protocol_binary_response_no_extras
));
39 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
40 response
.message
.header
.response
.opcode
= PROTOCOL_BINARY_CMD_NOOP
;
41 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
42 response
.message
.header
.response
.opaque
= header
->request
.opaque
;
44 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
47 static protocol_binary_response_status
quit_command_handler(const void *cookie
,
48 protocol_binary_request_header
*header
,
49 memcached_binary_protocol_raw_response_handler response_handler
)
51 protocol_binary_response_no_extras response
;
52 memset(&response
, 0, sizeof(protocol_binary_response_no_extras
));
54 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
55 response
.message
.header
.response
.opcode
= PROTOCOL_BINARY_CMD_QUIT
;
56 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
57 response
.message
.header
.response
.opaque
= header
->request
.opaque
;
59 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_QUIT
)
61 response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
64 /* I need a better way to signal to close the connection */
65 return PROTOCOL_BINARY_RESPONSE_EINTERNAL
;
68 static protocol_binary_response_status
get_command_handler(const void *cookie
,
69 protocol_binary_request_header
*header
,
70 memcached_binary_protocol_raw_response_handler response_handler
)
72 uint8_t opcode
= header
->request
.opcode
;
73 union protocol_binary_response_get_un
{
74 protocol_binary_response_get response
;
78 protocol_binary_response_get_un msg
;
79 memset(&msg
, 0, sizeof(protocol_binary_response_get_un
));
81 msg
.response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
82 msg
.response
.message
.header
.response
.opcode
= opcode
;
83 msg
.response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
84 msg
.response
.message
.header
.response
.opaque
= header
->request
.opaque
;
86 struct item
*item
= get_item(header
+ 1, ntohs(header
->request
.keylen
));
89 msg
.response
.message
.body
.flags
= htonl(item
->flags
);
90 char *ptr
= (char*)(msg
.response
.bytes
+ sizeof(*header
) + 4);
92 msg
.response
.message
.header
.response
.cas
= example_htonll(item
->cas
);
93 if (opcode
== PROTOCOL_BINARY_CMD_GETK
|| opcode
== PROTOCOL_BINARY_CMD_GETKQ
)
95 memcpy(ptr
, item
->key
, item
->nkey
);
96 msg
.response
.message
.header
.response
.keylen
= htons((uint16_t)item
->nkey
);
98 bodysize
+= (uint32_t)item
->nkey
;
100 memcpy(ptr
, item
->data
, item
->size
);
101 bodysize
+= (uint32_t)item
->size
;
102 msg
.response
.message
.header
.response
.bodylen
= htonl(bodysize
);
103 msg
.response
.message
.header
.response
.extlen
= 4;
106 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&msg
);
108 else if (opcode
== PROTOCOL_BINARY_CMD_GET
|| opcode
== PROTOCOL_BINARY_CMD_GETK
)
110 msg
.response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
111 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&msg
);
114 /* Q shouldn't report a miss ;-) */
115 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
118 static protocol_binary_response_status
delete_command_handler(const void *cookie
,
119 protocol_binary_request_header
*header
,
120 memcached_binary_protocol_raw_response_handler response_handler
)
122 size_t keylen
= ntohs(header
->request
.keylen
);
124 char *key
= ((char*)header
) + sizeof(*header
);
125 protocol_binary_response_no_extras response
;
126 memset(&response
, 0, sizeof(protocol_binary_response_no_extras
));
128 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
129 response
.message
.header
.response
.opcode
= header
->request
.opcode
;
130 response
.message
.header
.response
.opaque
= header
->request
.opaque
;
132 if (delete_item(key
, keylen
) == false)
134 log_file
->write(util::VERBOSE_NOTICE
, "%s not found: %.*s", __func__
, keylen
, key
);
135 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
136 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
138 else if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_DELETE
)
140 log_file
->write(util::VERBOSE_NOTICE
, "%s not found: %.*s", __func__
, keylen
, key
);
141 /* DELETEQ doesn't want success response */
142 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
143 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
146 log_file
->write(util::VERBOSE_NOTICE
, "%s deleted: %.*s", __func__
, keylen
, key
);
148 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
151 static protocol_binary_response_status
flush_command_handler(const void *cookie
,
152 protocol_binary_request_header
*header
,
153 memcached_binary_protocol_raw_response_handler response_handler
)
155 uint8_t opcode
= header
->request
.opcode
;
157 /* @fixme sett inn when! */
160 if (opcode
== PROTOCOL_BINARY_CMD_FLUSH
)
162 protocol_binary_response_no_extras response
;
163 memset(&response
, 0, sizeof(protocol_binary_response_no_extras
));
165 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
166 response
.message
.header
.response
.opcode
= opcode
;
167 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
168 response
.message
.header
.response
.opaque
= header
->request
.opaque
;
170 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
173 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
176 static protocol_binary_response_status
arithmetic_command_handler(const void *cookie
,
177 protocol_binary_request_header
*header
,
178 memcached_binary_protocol_raw_response_handler response_handler
)
180 protocol_binary_request_incr
*req
= (protocol_binary_request_incr
*)header
;
181 protocol_binary_response_incr response
;
182 memset(&response
, 0, sizeof(protocol_binary_response_incr
));
184 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
185 response
.message
.header
.response
.opcode
= header
->request
.opcode
;
186 response
.message
.header
.response
.opaque
= header
->request
.opaque
;
188 uint16_t keylen
= ntohs(header
->request
.keylen
);
189 uint64_t initial
= example_ntohll(req
->message
.body
.initial
);
190 uint64_t delta
= example_ntohll(req
->message
.body
.delta
);
191 uint32_t expiration
= ntohl(req
->message
.body
.expiration
);
193 void *key
= req
->bytes
+ sizeof(req
->bytes
);
194 protocol_binary_response_status rval
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
196 uint64_t value
= initial
;
198 struct item
*item
= get_item(key
, keylen
);
201 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_INCREMENT
||
202 header
->request
.opcode
== PROTOCOL_BINARY_CMD_INCREMENTQ
)
204 value
= (*(uint64_t*)item
->data
) + delta
;
208 if (delta
> *(uint64_t*)item
->data
)
214 value
= *(uint64_t*)item
->data
- delta
;
217 expiration
= (uint32_t)item
->exp
;
221 delete_item(key
, keylen
);
224 item
= create_item(key
, keylen
, NULL
, sizeof(value
), flags
, (time_t)expiration
);
227 rval
= PROTOCOL_BINARY_RESPONSE_ENOMEM
;
231 memcpy(item
->data
, &value
, sizeof(value
));
235 response
.message
.header
.response
.status
= htons(rval
);
236 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
)
238 response
.message
.header
.response
.bodylen
= ntohl(8);
239 response
.message
.body
.value
= example_ntohll((*(uint64_t*)item
->data
));
240 response
.message
.header
.response
.cas
= example_ntohll(item
->cas
);
243 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_INCREMENTQ
||
244 header
->request
.opcode
== PROTOCOL_BINARY_CMD_DECREMENTQ
)
246 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
250 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
253 static protocol_binary_response_status
version_command_handler(const void *cookie
,
254 protocol_binary_request_header
*header
,
255 memcached_binary_protocol_raw_response_handler response_handler
)
257 const char *versionstring
= "1.0.0";
258 union protocol_binary_response_header_un
260 protocol_binary_response_header packet
;
264 protocol_binary_response_header_un response
;
265 memset(&response
, 0, sizeof(protocol_binary_response_header_un
));
267 response
.packet
.response
.magic
= PROTOCOL_BINARY_RES
;
268 response
.packet
.response
.opcode
= PROTOCOL_BINARY_CMD_VERSION
;
269 response
.packet
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
270 response
.packet
.response
.opaque
= header
->request
.opaque
;
271 response
.packet
.response
.cas
= 0;
272 response
.packet
.response
.bodylen
= htonl((uint32_t)strlen(versionstring
));
274 assert(sizeof(protocol_binary_response_header
) +strlen(versionstring
) <= 256);
275 memcpy(response
.buffer
+ sizeof(protocol_binary_response_header
), versionstring
, strlen(versionstring
));
277 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
280 static protocol_binary_response_status
concat_command_handler(const void *cookie
,
281 protocol_binary_request_header
*header
,
282 memcached_binary_protocol_raw_response_handler response_handler
)
284 protocol_binary_response_status rval
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
285 uint16_t keylen
= ntohs(header
->request
.keylen
);
286 uint64_t cas
= example_ntohll(header
->request
.cas
);
287 void *key
= header
+ 1;
288 uint32_t vallen
= ntohl(header
->request
.bodylen
) - keylen
;
289 void *val
= (char*)key
+ keylen
;
291 struct item
*item
= get_item(key
, keylen
);
292 struct item
*nitem
= NULL
;
296 rval
= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
;
298 else if (cas
!= 0 && cas
!= item
->cas
)
300 rval
= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
;
302 else if ((nitem
= create_item(key
, keylen
, NULL
, item
->size
+ vallen
,
303 item
->flags
, item
->exp
)) == NULL
)
306 rval
= PROTOCOL_BINARY_RESPONSE_ENOMEM
;
310 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_APPEND
||
311 header
->request
.opcode
== PROTOCOL_BINARY_CMD_APPENDQ
)
313 memcpy(nitem
->data
, item
->data
, item
->size
);
314 memcpy(((char*)(nitem
->data
)) + item
->size
, val
, vallen
);
318 memcpy(nitem
->data
, val
, vallen
);
319 memcpy(((char*)(nitem
->data
)) + vallen
, item
->data
, item
->size
);
322 delete_item(key
, keylen
);
327 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_APPEND
||
328 header
->request
.opcode
== PROTOCOL_BINARY_CMD_PREPEND
)
330 protocol_binary_response_no_extras response
;
331 memset(&response
, 0, sizeof(protocol_binary_response_no_extras
));
333 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
334 response
.message
.header
.response
.opcode
= header
->request
.opcode
;
335 response
.message
.header
.response
.status
= htons(rval
);
336 response
.message
.header
.response
.opaque
= header
->request
.opaque
;
337 response
.message
.header
.response
.cas
= example_htonll(cas
);
339 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
346 static protocol_binary_response_status
set_command_handler(const void *cookie
,
347 protocol_binary_request_header
*header
,
348 memcached_binary_protocol_raw_response_handler response_handler
)
350 size_t keylen
= ntohs(header
->request
.keylen
);
351 size_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
352 protocol_binary_request_replace
*request
= (protocol_binary_request_replace
*)header
;
353 uint32_t flags
= ntohl(request
->message
.body
.flags
);
354 time_t timeout
= (time_t)ntohl(request
->message
.body
.expiration
);
355 char *key
= ((char*)header
) + sizeof(*header
) + 8;
356 char *data
= key
+ keylen
;
358 protocol_binary_response_no_extras response
;
359 memset(&response
, 0, sizeof(protocol_binary_response_no_extras
));
361 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
362 response
.message
.header
.response
.opcode
= header
->request
.opcode
;
363 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
364 response
.message
.header
.response
.opaque
= header
->request
.opaque
;
366 if (header
->request
.cas
!= 0)
369 struct item
* item
= get_item(key
, keylen
);
372 if (item
->cas
!= example_ntohll(header
->request
.cas
))
375 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
);
376 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
382 delete_item(key
, keylen
);
383 struct item
* item
= create_item(key
, keylen
, data
, datalen
, flags
, timeout
);
386 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM
);
391 /* SETQ shouldn't return a message */
392 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_SET
)
394 response
.message
.header
.response
.cas
= example_htonll(item
->cas
);
396 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
400 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
403 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
406 static protocol_binary_response_status
add_command_handler(const void *cookie
,
407 protocol_binary_request_header
*header
,
408 memcached_binary_protocol_raw_response_handler response_handler
)
410 size_t keylen
= ntohs(header
->request
.keylen
);
411 size_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
412 protocol_binary_request_add
*request
= (protocol_binary_request_add
*)header
;
413 uint32_t flags
= ntohl(request
->message
.body
.flags
);
414 time_t timeout
= (time_t)ntohl(request
->message
.body
.expiration
);
415 char *key
= ((char*)header
) + sizeof(*header
) + 8;
416 char *data
= key
+ keylen
;
418 protocol_binary_response_no_extras response
;
419 memset(&response
, 0, sizeof(protocol_binary_response_no_extras
));
421 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
422 response
.message
.header
.response
.opcode
= header
->request
.opcode
;
423 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
424 response
.message
.header
.response
.opaque
= header
->request
.opaque
;
426 struct item
* item
= get_item(key
, keylen
);
429 item
= create_item(key
, keylen
, data
, datalen
, flags
, timeout
);
431 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM
);
435 /* ADDQ shouldn't return a message */
436 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_ADD
)
438 response
.message
.header
.response
.cas
= example_htonll(item
->cas
);
440 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
443 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
449 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
);
452 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
455 static protocol_binary_response_status
replace_command_handler(const void *cookie
,
456 protocol_binary_request_header
*header
,
457 memcached_binary_protocol_raw_response_handler response_handler
)
459 size_t keylen
= ntohs(header
->request
.keylen
);
460 size_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
461 protocol_binary_request_replace
*request
= (protocol_binary_request_replace
*)header
;
462 uint32_t flags
= ntohl(request
->message
.body
.flags
);
463 time_t timeout
= (time_t)ntohl(request
->message
.body
.expiration
);
464 char *key
= ((char*)header
) + sizeof(*header
) + 8;
465 char *data
= key
+ keylen
;
467 protocol_binary_response_no_extras response
;
468 memset(&response
, 0, sizeof(protocol_binary_response_no_extras
));
470 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
471 response
.message
.header
.response
.opcode
= header
->request
.opcode
;
472 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
473 response
.message
.header
.response
.opaque
= header
->request
.opaque
;
475 struct item
* item
= get_item(key
, keylen
);
478 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
480 else if (header
->request
.cas
== 0 || example_ntohll(header
->request
.cas
) == item
->cas
)
483 delete_item(key
, keylen
);
484 item
= create_item(key
, keylen
, data
, datalen
, flags
, timeout
);
488 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM
);
493 /* REPLACEQ shouldn't return a message */
494 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_REPLACE
)
496 response
.message
.header
.response
.cas
= example_htonll(item
->cas
);
498 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
501 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
506 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
);
510 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
513 static protocol_binary_response_status
stat_command_handler(const void *cookie
,
514 protocol_binary_request_header
*header
,
515 memcached_binary_protocol_raw_response_handler response_handler
)
517 /* Just send the terminating packet*/
518 protocol_binary_response_no_extras response
;
519 memset(&response
, 0, sizeof(protocol_binary_response_no_extras
));
521 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
522 response
.message
.header
.response
.opcode
= PROTOCOL_BINARY_CMD_STAT
;
523 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
524 response
.message
.header
.response
.opaque
= header
->request
.opaque
;
526 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
529 memcached_binary_protocol_callback_st interface_v0_impl
;
531 void initialize_interface_v0_handler(util::log_info_st
& arg
)
535 interface_v0_impl
.interface_version
= MEMCACHED_PROTOCOL_HANDLER_V0
;
536 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GET
]= get_command_handler
;
537 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_SET
]= set_command_handler
;
538 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_ADD
]= add_command_handler
;
539 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_REPLACE
]= replace_command_handler
;
540 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DELETE
]= delete_command_handler
;
541 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_INCREMENT
]= arithmetic_command_handler
;
542 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DECREMENT
]= arithmetic_command_handler
;
543 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_QUIT
]= quit_command_handler
;
544 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_FLUSH
]= flush_command_handler
;
545 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GETQ
]= get_command_handler
;
546 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_NOOP
]= noop_command_handler
;
547 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_VERSION
]= version_command_handler
;
548 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GETK
]= get_command_handler
;
549 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GETKQ
]= get_command_handler
;
550 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_APPEND
]= concat_command_handler
;
551 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_PREPEND
]= concat_command_handler
;
552 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_STAT
]= stat_command_handler
;
553 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_SETQ
]= set_command_handler
;
554 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_ADDQ
]= add_command_handler
;
555 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_REPLACEQ
]= replace_command_handler
;
556 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DELETEQ
]= delete_command_handler
;
557 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_INCREMENTQ
]= arithmetic_command_handler
;
558 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DECREMENTQ
]= arithmetic_command_handler
;
559 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_QUITQ
]= quit_command_handler
;
560 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_FLUSHQ
]= flush_command_handler
;
561 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_APPENDQ
]= concat_command_handler
;
562 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_PREPENDQ
]= concat_command_handler
;