semver: 1.0 -> 1
[m6w6/libmemcached] / example / interface_v0.cc
1 /* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2 /**
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 ;-)
6 */
7
8 #include "mem_config.h"
9
10 #include <cassert>
11 #include <sys/types.h>
12 #include <cstdio>
13 #if HAVE_UNISTD_H
14 # include <unistd.h>
15 #endif
16 #include <fcntl.h>
17 #include <cerrno>
18 #include <cstdlib>
19 #include <cstring>
20
21 #include <libmemcachedprotocol-0/handler.h>
22 #include <example/byteorder.h>
23 #include "example/memcached_light.h"
24 #include "example/storage.h"
25 #include "util/log.hpp"
26
27
28 using namespace datadifferential;
29
30 static util::log_info_st *log_file= NULL;
31
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)
35 {
36 protocol_binary_response_no_extras response;
37 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
38
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;
43
44 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
45 }
46
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)
50 {
51 protocol_binary_response_no_extras response;
52 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
53
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;
58
59 if (header->request.opcode == PROTOCOL_BINARY_CMD_QUIT)
60 {
61 response_handler(cookie, header, (protocol_binary_response_header*)&response);
62 }
63
64 /* I need a better way to signal to close the connection */
65 return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
66 }
67
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)
71 {
72 uint8_t opcode= header->request.opcode;
73 union protocol_binary_response_get_un {
74 protocol_binary_response_get response;
75 char buffer[4096];
76 };
77
78 protocol_binary_response_get_un msg;
79 memset(&msg, 0, sizeof(protocol_binary_response_get_un));
80
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;
85
86 struct item *item= get_item(header + 1, ntohs(header->request.keylen));
87 if (item)
88 {
89 msg.response.message.body.flags= htonl(item->flags);
90 char *ptr= (char*)(msg.response.bytes + sizeof(*header) + 4);
91 uint32_t bodysize= 4;
92 msg.response.message.header.response.cas= example_htonll(item->cas);
93 if (opcode == PROTOCOL_BINARY_CMD_GETK || opcode == PROTOCOL_BINARY_CMD_GETKQ)
94 {
95 memcpy(ptr, item->key, item->nkey);
96 msg.response.message.header.response.keylen= htons((uint16_t)item->nkey);
97 ptr += item->nkey;
98 bodysize += (uint32_t)item->nkey;
99 }
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;
104
105 release_item(item);
106 return response_handler(cookie, header, (protocol_binary_response_header*)&msg);
107 }
108 else if (opcode == PROTOCOL_BINARY_CMD_GET || opcode == PROTOCOL_BINARY_CMD_GETK)
109 {
110 msg.response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
111 return response_handler(cookie, header, (protocol_binary_response_header*)&msg);
112 }
113
114 /* Q shouldn't report a miss ;-) */
115 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
116 }
117
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)
121 {
122 size_t keylen= ntohs(header->request.keylen);
123
124 char *key= ((char*)header) + sizeof(*header);
125 protocol_binary_response_no_extras response;
126 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
127
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;
131
132 if (delete_item(key, keylen) == false)
133 {
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);
137 }
138 else if (header->request.opcode == PROTOCOL_BINARY_CMD_DELETE)
139 {
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);
144 }
145
146 log_file->write(util::VERBOSE_NOTICE, "%s deleted: %.*s", __func__, keylen, key);
147
148 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
149 }
150
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)
154 {
155 uint8_t opcode= header->request.opcode;
156
157 /* @fixme sett inn when! */
158 flush(0);
159
160 if (opcode == PROTOCOL_BINARY_CMD_FLUSH)
161 {
162 protocol_binary_response_no_extras response;
163 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
164
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;
169
170 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
171 }
172
173 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
174 }
175
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)
179 {
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));
183
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;
187
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);
192 uint32_t flags= 0;
193 void *key= req->bytes + sizeof(req->bytes);
194 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
195
196 uint64_t value= initial;
197
198 struct item *item= get_item(key, keylen);
199 if (item != NULL)
200 {
201 if (header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENT ||
202 header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENTQ)
203 {
204 value= (*(uint64_t*)item->data) + delta;
205 }
206 else
207 {
208 if (delta > *(uint64_t*)item->data)
209 {
210 value= 0;
211 }
212 else
213 {
214 value= *(uint64_t*)item->data - delta;
215 }
216 }
217 expiration= (uint32_t)item->exp;
218 flags= item->flags;
219
220 release_item(item);
221 delete_item(key, keylen);
222 }
223
224 item= create_item(key, keylen, NULL, sizeof(value), flags, (time_t)expiration);
225 if (item == NULL)
226 {
227 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
228 }
229 else
230 {
231 memcpy(item->data, &value, sizeof(value));
232 put_item(item);
233 }
234
235 response.message.header.response.status= htons(rval);
236 if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
237 {
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);
241
242 release_item(item);
243 if (header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENTQ ||
244 header->request.opcode == PROTOCOL_BINARY_CMD_DECREMENTQ)
245 {
246 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
247 }
248 }
249
250 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
251 }
252
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)
256 {
257 const char *versionstring= "1.0.0";
258 union protocol_binary_response_header_un
259 {
260 protocol_binary_response_header packet;
261 char buffer[256];
262 };
263
264 protocol_binary_response_header_un response;
265 memset(&response, 0, sizeof(protocol_binary_response_header_un));
266
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));
273
274 assert(sizeof(protocol_binary_response_header) +strlen(versionstring) <= 256);
275 memcpy(response.buffer + sizeof(protocol_binary_response_header), versionstring, strlen(versionstring));
276
277 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
278 }
279
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)
283 {
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;
290
291 struct item *item= get_item(key, keylen);
292 struct item *nitem= NULL;
293
294 if (item == NULL)
295 {
296 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
297 }
298 else if (cas != 0 && cas != item->cas)
299 {
300 rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
301 }
302 else if ((nitem= create_item(key, keylen, NULL, item->size + vallen,
303 item->flags, item->exp)) == NULL)
304 {
305 release_item(item);
306 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
307 }
308 else
309 {
310 if (header->request.opcode == PROTOCOL_BINARY_CMD_APPEND ||
311 header->request.opcode == PROTOCOL_BINARY_CMD_APPENDQ)
312 {
313 memcpy(nitem->data, item->data, item->size);
314 memcpy(((char*)(nitem->data)) + item->size, val, vallen);
315 }
316 else
317 {
318 memcpy(nitem->data, val, vallen);
319 memcpy(((char*)(nitem->data)) + vallen, item->data, item->size);
320 }
321 release_item(item);
322 delete_item(key, keylen);
323 put_item(nitem);
324 cas= nitem->cas;
325 release_item(nitem);
326
327 if (header->request.opcode == PROTOCOL_BINARY_CMD_APPEND ||
328 header->request.opcode == PROTOCOL_BINARY_CMD_PREPEND)
329 {
330 protocol_binary_response_no_extras response;
331 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
332
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);
338
339 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
340 }
341 }
342
343 return rval;
344 }
345
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)
349 {
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;
357
358 protocol_binary_response_no_extras response;
359 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
360
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;
365
366 if (header->request.cas != 0)
367 {
368 /* validate cas */
369 struct item* item= get_item(key, keylen);
370 if (item != NULL)
371 {
372 if (item->cas != example_ntohll(header->request.cas))
373 {
374 release_item(item);
375 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
376 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
377 }
378 release_item(item);
379 }
380 }
381
382 delete_item(key, keylen);
383 struct item* item= create_item(key, keylen, data, datalen, flags, timeout);
384 if (item == NULL)
385 {
386 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
387 }
388 else
389 {
390 put_item(item);
391 /* SETQ shouldn't return a message */
392 if (header->request.opcode == PROTOCOL_BINARY_CMD_SET)
393 {
394 response.message.header.response.cas= example_htonll(item->cas);
395 release_item(item);
396 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
397 }
398 release_item(item);
399
400 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
401 }
402
403 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
404 }
405
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)
409 {
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;
417
418 protocol_binary_response_no_extras response;
419 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
420
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;
425
426 struct item* item= get_item(key, keylen);
427 if (item == NULL)
428 {
429 item= create_item(key, keylen, data, datalen, flags, timeout);
430 if (item == NULL)
431 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
432 else
433 {
434 put_item(item);
435 /* ADDQ shouldn't return a message */
436 if (header->request.opcode == PROTOCOL_BINARY_CMD_ADD)
437 {
438 response.message.header.response.cas= example_htonll(item->cas);
439 release_item(item);
440 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
441 }
442 release_item(item);
443 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
444 }
445 }
446 else
447 {
448 release_item(item);
449 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
450 }
451
452 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
453 }
454
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)
458 {
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;
466
467 protocol_binary_response_no_extras response;
468 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
469
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;
474
475 struct item* item= get_item(key, keylen);
476 if (item == NULL)
477 {
478 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
479 }
480 else if (header->request.cas == 0 || example_ntohll(header->request.cas) == item->cas)
481 {
482 release_item(item);
483 delete_item(key, keylen);
484 item= create_item(key, keylen, data, datalen, flags, timeout);
485
486 if (item == NULL)
487 {
488 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
489 }
490 else
491 {
492 put_item(item);
493 /* REPLACEQ shouldn't return a message */
494 if (header->request.opcode == PROTOCOL_BINARY_CMD_REPLACE)
495 {
496 response.message.header.response.cas= example_htonll(item->cas);
497 release_item(item);
498 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
499 }
500 release_item(item);
501 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
502 }
503 }
504 else
505 {
506 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
507 release_item(item);
508 }
509
510 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
511 }
512
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)
516 {
517 /* Just send the terminating packet*/
518 protocol_binary_response_no_extras response;
519 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
520
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;
525
526 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
527 }
528
529 memcached_binary_protocol_callback_st interface_v0_impl;
530
531 void initialize_interface_v0_handler(util::log_info_st& arg)
532 {
533 log_file= &arg;
534
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;
563 }