Merge lp:~tangent-org/libmemcached/1.0-build/ Build: jenkins-Libmemcached-187
[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 #include <unistd.h>
14 #include <fcntl.h>
15 #include <cerrno>
16 #include <cstdlib>
17 #include <cstring>
18
19 #include <libmemcachedprotocol-0.0/handler.h>
20 #include <example/byteorder.h>
21 #include "example/memcached_light.h"
22 #include "example/storage.h"
23 #include "util/log.hpp"
24
25
26 using namespace datadifferential;
27
28 static util::log_info_st *log_file= NULL;
29
30 static protocol_binary_response_status noop_command_handler(const void *cookie,
31 protocol_binary_request_header *header,
32 memcached_binary_protocol_raw_response_handler response_handler)
33 {
34 protocol_binary_response_no_extras response;
35 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
36
37 response.message.header.response.magic= PROTOCOL_BINARY_RES;
38 response.message.header.response.opcode= PROTOCOL_BINARY_CMD_NOOP;
39 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
40 response.message.header.response.opaque= header->request.opaque;
41
42 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
43 }
44
45 static protocol_binary_response_status quit_command_handler(const void *cookie,
46 protocol_binary_request_header *header,
47 memcached_binary_protocol_raw_response_handler response_handler)
48 {
49 protocol_binary_response_no_extras response;
50 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
51
52 response.message.header.response.magic= PROTOCOL_BINARY_RES;
53 response.message.header.response.opcode= PROTOCOL_BINARY_CMD_QUIT;
54 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
55 response.message.header.response.opaque= header->request.opaque;
56
57 if (header->request.opcode == PROTOCOL_BINARY_CMD_QUIT)
58 {
59 response_handler(cookie, header, (protocol_binary_response_header*)&response);
60 }
61
62 /* I need a better way to signal to close the connection */
63 return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
64 }
65
66 static protocol_binary_response_status get_command_handler(const void *cookie,
67 protocol_binary_request_header *header,
68 memcached_binary_protocol_raw_response_handler response_handler)
69 {
70 uint8_t opcode= header->request.opcode;
71 union protocol_binary_response_get_un {
72 protocol_binary_response_get response;
73 char buffer[4096];
74 };
75
76 protocol_binary_response_get_un msg;
77 memset(&msg, 0, sizeof(protocol_binary_response_get_un));
78
79 msg.response.message.header.response.magic= PROTOCOL_BINARY_RES;
80 msg.response.message.header.response.opcode= opcode;
81 msg.response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
82 msg.response.message.header.response.opaque= header->request.opaque;
83
84 struct item *item= get_item(header + 1, ntohs(header->request.keylen));
85 if (item)
86 {
87 msg.response.message.body.flags= htonl(item->flags);
88 char *ptr= (char*)(msg.response.bytes + sizeof(*header) + 4);
89 uint32_t bodysize= 4;
90 msg.response.message.header.response.cas= example_htonll(item->cas);
91 if (opcode == PROTOCOL_BINARY_CMD_GETK || opcode == PROTOCOL_BINARY_CMD_GETKQ)
92 {
93 memcpy(ptr, item->key, item->nkey);
94 msg.response.message.header.response.keylen= htons((uint16_t)item->nkey);
95 ptr += item->nkey;
96 bodysize += (uint32_t)item->nkey;
97 }
98 memcpy(ptr, item->data, item->size);
99 bodysize += (uint32_t)item->size;
100 msg.response.message.header.response.bodylen= htonl(bodysize);
101 msg.response.message.header.response.extlen= 4;
102
103 release_item(item);
104 return response_handler(cookie, header, (protocol_binary_response_header*)&msg);
105 }
106 else if (opcode == PROTOCOL_BINARY_CMD_GET || opcode == PROTOCOL_BINARY_CMD_GETK)
107 {
108 msg.response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
109 return response_handler(cookie, header, (protocol_binary_response_header*)&msg);
110 }
111
112 /* Q shouldn't report a miss ;-) */
113 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
114 }
115
116 static protocol_binary_response_status delete_command_handler(const void *cookie,
117 protocol_binary_request_header *header,
118 memcached_binary_protocol_raw_response_handler response_handler)
119 {
120 size_t keylen= ntohs(header->request.keylen);
121
122 char *key= ((char*)header) + sizeof(*header);
123 protocol_binary_response_no_extras response;
124 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
125
126 response.message.header.response.magic= PROTOCOL_BINARY_RES;
127 response.message.header.response.opcode= header->request.opcode;
128 response.message.header.response.opaque= header->request.opaque;
129
130 if (delete_item(key, keylen) == false)
131 {
132 log_file->write(util::VERBOSE_NOTICE, "%s not found: %.*s", __func__, keylen, key);
133 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
134 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
135 }
136 else if (header->request.opcode == PROTOCOL_BINARY_CMD_DELETE)
137 {
138 log_file->write(util::VERBOSE_NOTICE, "%s not found: %.*s", __func__, keylen, key);
139 /* DELETEQ doesn't want success response */
140 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
141 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
142 }
143
144 log_file->write(util::VERBOSE_NOTICE, "%s deleted: %.*s", __func__, keylen, key);
145
146 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
147 }
148
149 static protocol_binary_response_status flush_command_handler(const void *cookie,
150 protocol_binary_request_header *header,
151 memcached_binary_protocol_raw_response_handler response_handler)
152 {
153 uint8_t opcode= header->request.opcode;
154
155 /* @fixme sett inn when! */
156 flush(0);
157
158 if (opcode == PROTOCOL_BINARY_CMD_FLUSH)
159 {
160 protocol_binary_response_no_extras response;
161 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
162
163 response.message.header.response.magic= PROTOCOL_BINARY_RES;
164 response.message.header.response.opcode= opcode;
165 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
166 response.message.header.response.opaque= header->request.opaque;
167
168 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
169 }
170
171 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
172 }
173
174 static protocol_binary_response_status arithmetic_command_handler(const void *cookie,
175 protocol_binary_request_header *header,
176 memcached_binary_protocol_raw_response_handler response_handler)
177 {
178 protocol_binary_request_incr *req= (protocol_binary_request_incr*)header;
179 protocol_binary_response_incr response;
180 memset(&response, 0, sizeof(protocol_binary_response_incr));
181
182 response.message.header.response.magic= PROTOCOL_BINARY_RES;
183 response.message.header.response.opcode= header->request.opcode;
184 response.message.header.response.opaque= header->request.opaque;
185
186 uint16_t keylen= ntohs(header->request.keylen);
187 uint64_t initial= example_ntohll(req->message.body.initial);
188 uint64_t delta= example_ntohll(req->message.body.delta);
189 uint32_t expiration= ntohl(req->message.body.expiration);
190 uint32_t flags= 0;
191 void *key= req->bytes + sizeof(req->bytes);
192 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
193
194 uint64_t value= initial;
195
196 struct item *item= get_item(key, keylen);
197 if (item != NULL)
198 {
199 if (header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENT ||
200 header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENTQ)
201 {
202 value= (*(uint64_t*)item->data) + delta;
203 }
204 else
205 {
206 if (delta > *(uint64_t*)item->data)
207 {
208 value= 0;
209 }
210 else
211 {
212 value= *(uint64_t*)item->data - delta;
213 }
214 }
215 expiration= (uint32_t)item->exp;
216 flags= item->flags;
217
218 release_item(item);
219 delete_item(key, keylen);
220 }
221
222 item= create_item(key, keylen, NULL, sizeof(value), flags, (time_t)expiration);
223 if (item == NULL)
224 {
225 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
226 }
227 else
228 {
229 memcpy(item->data, &value, sizeof(value));
230 put_item(item);
231 }
232
233 response.message.header.response.status= htons(rval);
234 if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
235 {
236 response.message.header.response.bodylen= ntohl(8);
237 response.message.body.value= example_ntohll((*(uint64_t*)item->data));
238 response.message.header.response.cas= example_ntohll(item->cas);
239
240 release_item(item);
241 if (header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENTQ ||
242 header->request.opcode == PROTOCOL_BINARY_CMD_DECREMENTQ)
243 {
244 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
245 }
246 }
247
248 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
249 }
250
251 static protocol_binary_response_status version_command_handler(const void *cookie,
252 protocol_binary_request_header *header,
253 memcached_binary_protocol_raw_response_handler response_handler)
254 {
255 const char *versionstring= "1.0.0";
256 union protocol_binary_response_header_un
257 {
258 protocol_binary_response_header packet;
259 char buffer[256];
260 };
261
262 protocol_binary_response_header_un response;
263 memset(&response, 0, sizeof(protocol_binary_response_header_un));
264
265 response.packet.response.magic= PROTOCOL_BINARY_RES;
266 response.packet.response.opcode= PROTOCOL_BINARY_CMD_VERSION;
267 response.packet.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
268 response.packet.response.opaque= header->request.opaque;
269 response.packet.response.cas= 0;
270 response.packet.response.bodylen= htonl((uint32_t)strlen(versionstring));
271
272 assert(sizeof(protocol_binary_response_header) +strlen(versionstring) <= 256);
273 memcpy(response.buffer + sizeof(protocol_binary_response_header), versionstring, strlen(versionstring));
274
275 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
276 }
277
278 static protocol_binary_response_status concat_command_handler(const void *cookie,
279 protocol_binary_request_header *header,
280 memcached_binary_protocol_raw_response_handler response_handler)
281 {
282 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
283 uint16_t keylen= ntohs(header->request.keylen);
284 uint64_t cas= example_ntohll(header->request.cas);
285 void *key= header + 1;
286 uint32_t vallen= ntohl(header->request.bodylen) - keylen;
287 void *val= (char*)key + keylen;
288
289 struct item *item= get_item(key, keylen);
290 struct item *nitem= NULL;
291
292 if (item == NULL)
293 {
294 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
295 }
296 else if (cas != 0 && cas != item->cas)
297 {
298 rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
299 }
300 else if ((nitem= create_item(key, keylen, NULL, item->size + vallen,
301 item->flags, item->exp)) == NULL)
302 {
303 release_item(item);
304 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
305 }
306 else
307 {
308 if (header->request.opcode == PROTOCOL_BINARY_CMD_APPEND ||
309 header->request.opcode == PROTOCOL_BINARY_CMD_APPENDQ)
310 {
311 memcpy(nitem->data, item->data, item->size);
312 memcpy(((char*)(nitem->data)) + item->size, val, vallen);
313 }
314 else
315 {
316 memcpy(nitem->data, val, vallen);
317 memcpy(((char*)(nitem->data)) + vallen, item->data, item->size);
318 }
319 release_item(item);
320 delete_item(key, keylen);
321 put_item(nitem);
322 cas= nitem->cas;
323 release_item(nitem);
324
325 if (header->request.opcode == PROTOCOL_BINARY_CMD_APPEND ||
326 header->request.opcode == PROTOCOL_BINARY_CMD_PREPEND)
327 {
328 protocol_binary_response_no_extras response;
329 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
330
331 response.message.header.response.magic= PROTOCOL_BINARY_RES;
332 response.message.header.response.opcode= header->request.opcode;
333 response.message.header.response.status= htons(rval);
334 response.message.header.response.opaque= header->request.opaque;
335 response.message.header.response.cas= example_htonll(cas);
336
337 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
338 }
339 }
340
341 return rval;
342 }
343
344 static protocol_binary_response_status set_command_handler(const void *cookie,
345 protocol_binary_request_header *header,
346 memcached_binary_protocol_raw_response_handler response_handler)
347 {
348 size_t keylen= ntohs(header->request.keylen);
349 size_t datalen= ntohl(header->request.bodylen) - keylen - 8;
350 protocol_binary_request_replace *request= (protocol_binary_request_replace*)header;
351 uint32_t flags= ntohl(request->message.body.flags);
352 time_t timeout= (time_t)ntohl(request->message.body.expiration);
353 char *key= ((char*)header) + sizeof(*header) + 8;
354 char *data= key + keylen;
355
356 protocol_binary_response_no_extras response;
357 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
358
359 response.message.header.response.magic= PROTOCOL_BINARY_RES;
360 response.message.header.response.opcode= header->request.opcode;
361 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
362 response.message.header.response.opaque= header->request.opaque;
363
364 if (header->request.cas != 0)
365 {
366 /* validate cas */
367 struct item* item= get_item(key, keylen);
368 if (item != NULL)
369 {
370 if (item->cas != example_ntohll(header->request.cas))
371 {
372 release_item(item);
373 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
374 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
375 }
376 release_item(item);
377 }
378 }
379
380 delete_item(key, keylen);
381 struct item* item= create_item(key, keylen, data, datalen, flags, timeout);
382 if (item == NULL)
383 {
384 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
385 }
386 else
387 {
388 put_item(item);
389 /* SETQ shouldn't return a message */
390 if (header->request.opcode == PROTOCOL_BINARY_CMD_SET)
391 {
392 response.message.header.response.cas= example_htonll(item->cas);
393 release_item(item);
394 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
395 }
396 release_item(item);
397
398 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
399 }
400
401 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
402 }
403
404 static protocol_binary_response_status add_command_handler(const void *cookie,
405 protocol_binary_request_header *header,
406 memcached_binary_protocol_raw_response_handler response_handler)
407 {
408 size_t keylen= ntohs(header->request.keylen);
409 size_t datalen= ntohl(header->request.bodylen) - keylen - 8;
410 protocol_binary_request_add *request= (protocol_binary_request_add*)header;
411 uint32_t flags= ntohl(request->message.body.flags);
412 time_t timeout= (time_t)ntohl(request->message.body.expiration);
413 char *key= ((char*)header) + sizeof(*header) + 8;
414 char *data= key + keylen;
415
416 protocol_binary_response_no_extras response;
417 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
418
419 response.message.header.response.magic= PROTOCOL_BINARY_RES;
420 response.message.header.response.opcode= header->request.opcode;
421 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
422 response.message.header.response.opaque= header->request.opaque;
423
424 struct item* item= get_item(key, keylen);
425 if (item == NULL)
426 {
427 item= create_item(key, keylen, data, datalen, flags, timeout);
428 if (item == NULL)
429 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
430 else
431 {
432 put_item(item);
433 /* ADDQ shouldn't return a message */
434 if (header->request.opcode == PROTOCOL_BINARY_CMD_ADD)
435 {
436 response.message.header.response.cas= example_htonll(item->cas);
437 release_item(item);
438 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
439 }
440 release_item(item);
441 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
442 }
443 }
444 else
445 {
446 release_item(item);
447 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
448 }
449
450 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
451 }
452
453 static protocol_binary_response_status replace_command_handler(const void *cookie,
454 protocol_binary_request_header *header,
455 memcached_binary_protocol_raw_response_handler response_handler)
456 {
457 size_t keylen= ntohs(header->request.keylen);
458 size_t datalen= ntohl(header->request.bodylen) - keylen - 8;
459 protocol_binary_request_replace *request= (protocol_binary_request_replace*)header;
460 uint32_t flags= ntohl(request->message.body.flags);
461 time_t timeout= (time_t)ntohl(request->message.body.expiration);
462 char *key= ((char*)header) + sizeof(*header) + 8;
463 char *data= key + keylen;
464
465 protocol_binary_response_no_extras response;
466 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
467
468 response.message.header.response.magic= PROTOCOL_BINARY_RES;
469 response.message.header.response.opcode= header->request.opcode;
470 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
471 response.message.header.response.opaque= header->request.opaque;
472
473 struct item* item= get_item(key, keylen);
474 if (item == NULL)
475 {
476 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
477 }
478 else if (header->request.cas == 0 || example_ntohll(header->request.cas) == item->cas)
479 {
480 release_item(item);
481 delete_item(key, keylen);
482 item= create_item(key, keylen, data, datalen, flags, timeout);
483
484 if (item == NULL)
485 {
486 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
487 }
488 else
489 {
490 put_item(item);
491 /* REPLACEQ shouldn't return a message */
492 if (header->request.opcode == PROTOCOL_BINARY_CMD_REPLACE)
493 {
494 response.message.header.response.cas= example_htonll(item->cas);
495 release_item(item);
496 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
497 }
498 release_item(item);
499 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
500 }
501 }
502 else
503 {
504 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
505 release_item(item);
506 }
507
508 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
509 }
510
511 static protocol_binary_response_status stat_command_handler(const void *cookie,
512 protocol_binary_request_header *header,
513 memcached_binary_protocol_raw_response_handler response_handler)
514 {
515 /* Just send the terminating packet*/
516 protocol_binary_response_no_extras response;
517 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
518
519 response.message.header.response.magic= PROTOCOL_BINARY_RES;
520 response.message.header.response.opcode= PROTOCOL_BINARY_CMD_STAT;
521 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
522 response.message.header.response.opaque= header->request.opaque;
523
524 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
525 }
526
527 memcached_binary_protocol_callback_st interface_v0_impl;
528
529 void initialize_interface_v0_handler(util::log_info_st& arg)
530 {
531 log_file= &arg;
532
533 interface_v0_impl.interface_version= MEMCACHED_PROTOCOL_HANDLER_V0;
534 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GET]= get_command_handler;
535 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_SET]= set_command_handler;
536 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_ADD]= add_command_handler;
537 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACE]= replace_command_handler;
538 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETE]= delete_command_handler;
539 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENT]= arithmetic_command_handler;
540 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENT]= arithmetic_command_handler;
541 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_QUIT]= quit_command_handler;
542 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSH]= flush_command_handler;
543 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GETQ]= get_command_handler;
544 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_NOOP]= noop_command_handler;
545 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_VERSION]= version_command_handler;
546 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GETK]= get_command_handler;
547 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GETKQ]= get_command_handler;
548 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_APPEND]= concat_command_handler;
549 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPEND]= concat_command_handler;
550 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_STAT]= stat_command_handler;
551 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_SETQ]= set_command_handler;
552 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_ADDQ]= add_command_handler;
553 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACEQ]= replace_command_handler;
554 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETEQ]= delete_command_handler;
555 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENTQ]= arithmetic_command_handler;
556 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENTQ]= arithmetic_command_handler;
557 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_QUITQ]= quit_command_handler;
558 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSHQ]= flush_command_handler;
559 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_APPENDQ]= concat_command_handler;
560 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPENDQ]= concat_command_handler;
561 }