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 ;-)
10 #include <sys/socket.h>
12 #include <netinet/tcp.h>
20 #include <libmemcached/protocol_handler.h>
21 #include <libmemcached/byteorder.h>
23 #include "memcached_light.h"
25 static protocol_binary_response_status
noop_command_handler(const void *cookie
,
26 protocol_binary_request_header
*header
,
27 memcached_binary_protocol_raw_response_handler response_handler
)
29 protocol_binary_response_no_extras response
= {
30 .message
.header
.response
= {
31 .magic
= PROTOCOL_BINARY_RES
,
32 .opcode
= PROTOCOL_BINARY_CMD_NOOP
,
33 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
34 .opaque
= header
->request
.opaque
38 return response_handler(cookie
, header
, (void*)&response
);
41 static protocol_binary_response_status
quit_command_handler(const void *cookie
,
42 protocol_binary_request_header
*header
,
43 memcached_binary_protocol_raw_response_handler response_handler
)
45 protocol_binary_response_no_extras response
= {
46 .message
.header
.response
= {
47 .magic
= PROTOCOL_BINARY_RES
,
48 .opcode
= PROTOCOL_BINARY_CMD_QUIT
,
49 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
50 .opaque
= header
->request
.opaque
54 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_QUIT
)
55 response_handler(cookie
, header
, (void*)&response
);
57 /* I need a better way to signal to close the connection */
58 return PROTOCOL_BINARY_RESPONSE_EIO
;
61 static protocol_binary_response_status
get_command_handler(const void *cookie
,
62 protocol_binary_request_header
*header
,
63 memcached_binary_protocol_raw_response_handler response_handler
)
65 uint8_t opcode
= header
->request
.opcode
;
67 protocol_binary_response_get response
;
70 .response
.message
.header
.response
= {
71 .magic
= PROTOCOL_BINARY_RES
,
73 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
74 .opaque
= header
->request
.opaque
78 struct item
*item
= get_item(header
+ 1, ntohs(header
->request
.keylen
));
81 msg
.response
.message
.body
.flags
= htonl(item
->flags
);
82 char *ptr
= (char*)(msg
.response
.bytes
+ sizeof(*header
) + 4);
84 msg
.response
.message
.header
.response
.cas
= htonll(item
->cas
);
85 if (opcode
== PROTOCOL_BINARY_CMD_GETK
|| opcode
== PROTOCOL_BINARY_CMD_GETKQ
)
87 memcpy(ptr
, item
->key
, item
->nkey
);
88 msg
.response
.message
.header
.response
.keylen
= htons((uint16_t)item
->nkey
);
90 bodysize
+= (uint32_t)item
->nkey
;
92 memcpy(ptr
, item
->data
, item
->size
);
93 bodysize
+= (uint32_t)item
->size
;
94 msg
.response
.message
.header
.response
.bodylen
= htonl(bodysize
);
95 msg
.response
.message
.header
.response
.extlen
= 4;
98 return response_handler(cookie
, header
, (void*)&msg
);
100 else if (opcode
== PROTOCOL_BINARY_CMD_GET
|| opcode
== PROTOCOL_BINARY_CMD_GETK
)
102 msg
.response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
103 return response_handler(cookie
, header
, (void*)&msg
);
106 /* Q shouldn't report a miss ;-) */
107 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
110 static protocol_binary_response_status
delete_command_handler(const void *cookie
,
111 protocol_binary_request_header
*header
,
112 memcached_binary_protocol_raw_response_handler response_handler
)
114 size_t keylen
= ntohs(header
->request
.keylen
);
115 char *key
= ((char*)header
) + sizeof(*header
);
116 protocol_binary_response_no_extras response
= {
117 .message
.header
.response
= {
118 .magic
= PROTOCOL_BINARY_RES
,
119 .opcode
= header
->request
.opcode
,
120 .opaque
= header
->request
.opaque
124 if (!delete_item(key
, keylen
))
126 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
127 return response_handler(cookie
, header
, (void*)&response
);
129 else if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_DELETE
)
131 /* DELETEQ doesn't want success response */
132 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
133 return response_handler(cookie
, header
, (void*)&response
);
136 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
139 static protocol_binary_response_status
flush_command_handler(const void *cookie
,
140 protocol_binary_request_header
*header
,
141 memcached_binary_protocol_raw_response_handler response_handler
)
143 uint8_t opcode
= header
->request
.opcode
;
145 /* @fixme sett inn when! */
148 if (opcode
== PROTOCOL_BINARY_CMD_FLUSH
)
150 protocol_binary_response_no_extras response
= {
151 .message
.header
.response
= {
152 .magic
= PROTOCOL_BINARY_RES
,
154 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
155 .opaque
= header
->request
.opaque
158 return response_handler(cookie
, header
, (void*)&response
);
161 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
164 static protocol_binary_response_status
arithmetic_command_handler(const void *cookie
,
165 protocol_binary_request_header
*header
,
166 memcached_binary_protocol_raw_response_handler response_handler
)
168 protocol_binary_request_incr
*req
= (void*)header
;
169 protocol_binary_response_incr response
= {
170 .message
.header
.response
= {
171 .magic
= PROTOCOL_BINARY_RES
,
172 .opcode
= header
->request
.opcode
,
173 .opaque
= header
->request
.opaque
,
177 uint16_t keylen
= ntohs(header
->request
.keylen
);
178 uint64_t initial
= ntohll(req
->message
.body
.initial
);
179 uint64_t delta
= ntohll(req
->message
.body
.delta
);
180 uint32_t expiration
= ntohl(req
->message
.body
.expiration
);
182 void *key
= req
->bytes
+ sizeof(req
->bytes
);
183 protocol_binary_response_status rval
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
185 uint64_t value
= initial
;
187 struct item
*item
= get_item(key
, keylen
);
190 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_INCREMENT
||
191 header
->request
.opcode
== PROTOCOL_BINARY_CMD_INCREMENTQ
)
193 value
= (*(uint64_t*)item
->data
) + delta
;
197 if (delta
> *(uint64_t*)item
->data
)
203 value
= *(uint64_t*)item
->data
- delta
;
206 expiration
= (uint32_t)item
->exp
;
210 delete_item(key
, keylen
);
213 item
= create_item(key
, keylen
, NULL
, sizeof(value
), flags
, (time_t)expiration
);
216 rval
= PROTOCOL_BINARY_RESPONSE_ENOMEM
;
220 memcpy(item
->data
, &value
, sizeof(value
));
224 response
.message
.header
.response
.status
= htons(rval
);
225 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
)
227 response
.message
.header
.response
.bodylen
= ntohl(8);
228 response
.message
.body
.value
= ntohll((*(uint64_t*)item
->data
));
229 response
.message
.header
.response
.cas
= ntohll(item
->cas
);
232 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_INCREMENTQ
||
233 header
->request
.opcode
== PROTOCOL_BINARY_CMD_DECREMENTQ
)
235 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
239 return response_handler(cookie
, header
, (void*)&response
);
242 static protocol_binary_response_status
version_command_handler(const void *cookie
,
243 protocol_binary_request_header
*header
,
244 memcached_binary_protocol_raw_response_handler response_handler
)
246 const char *versionstring
= "1.0.0";
248 protocol_binary_response_header packet
;
252 .magic
= PROTOCOL_BINARY_RES
,
253 .opcode
= PROTOCOL_BINARY_CMD_VERSION
,
254 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
255 .opaque
= header
->request
.opaque
,
256 .bodylen
= htonl((uint32_t)strlen(versionstring
))
260 memcpy(response
.buffer
+ sizeof(response
.packet
), versionstring
, strlen(versionstring
));
262 return response_handler(cookie
, header
, (void*)&response
);
265 static protocol_binary_response_status
concat_command_handler(const void *cookie
,
266 protocol_binary_request_header
*header
,
267 memcached_binary_protocol_raw_response_handler response_handler
)
269 protocol_binary_response_status rval
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
270 uint16_t keylen
= ntohs(header
->request
.keylen
);
271 uint64_t cas
= ntohll(header
->request
.cas
);
272 void *key
= header
+ 1;
273 uint32_t vallen
= ntohl(header
->request
.bodylen
) - keylen
;
274 void *val
= (char*)key
+ keylen
;
276 struct item
*item
= get_item(key
, keylen
);
277 struct item
*nitem
= NULL
;
281 rval
= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
;
283 else if (cas
!= 0 && cas
!= item
->cas
)
285 rval
= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
;
287 else if ((nitem
= create_item(key
, keylen
, NULL
, item
->size
+ vallen
,
288 item
->flags
, item
->exp
)) == NULL
)
291 rval
= PROTOCOL_BINARY_RESPONSE_ENOMEM
;
295 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_APPEND
||
296 header
->request
.opcode
== PROTOCOL_BINARY_CMD_APPENDQ
)
298 memcpy(nitem
->data
, item
->data
, item
->size
);
299 memcpy(((char*)(nitem
->data
)) + item
->size
, val
, vallen
);
303 memcpy(nitem
->data
, val
, vallen
);
304 memcpy(((char*)(nitem
->data
)) + vallen
, item
->data
, item
->size
);
307 delete_item(key
, keylen
);
312 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_APPEND
||
313 header
->request
.opcode
== PROTOCOL_BINARY_CMD_PREPEND
)
315 protocol_binary_response_no_extras response
= {
318 .magic
= PROTOCOL_BINARY_RES
,
319 .opcode
= header
->request
.opcode
,
320 .status
= htons(rval
),
321 .opaque
= header
->request
.opaque
,
326 return response_handler(cookie
, header
, (void*)&response
);
333 static protocol_binary_response_status
set_command_handler(const void *cookie
,
334 protocol_binary_request_header
*header
,
335 memcached_binary_protocol_raw_response_handler response_handler
)
337 size_t keylen
= ntohs(header
->request
.keylen
);
338 size_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
339 protocol_binary_request_replace
*request
= (void*)header
;
340 uint32_t flags
= ntohl(request
->message
.body
.flags
);
341 time_t timeout
= (time_t)ntohl(request
->message
.body
.expiration
);
342 char *key
= ((char*)header
) + sizeof(*header
) + 8;
343 char *data
= key
+ keylen
;
345 protocol_binary_response_no_extras response
= {
348 .magic
= PROTOCOL_BINARY_RES
,
349 .opcode
= header
->request
.opcode
,
350 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
351 .opaque
= header
->request
.opaque
356 if (header
->request
.cas
!= 0)
359 struct item
* item
= get_item(key
, keylen
);
362 if (item
->cas
!= ntohll(header
->request
.cas
))
365 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
);
366 return response_handler(cookie
, header
, (void*)&response
);
372 delete_item(key
, keylen
);
373 struct item
* item
= create_item(key
, keylen
, data
, datalen
, flags
, timeout
);
376 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM
);
381 /* SETQ shouldn't return a message */
382 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_SET
)
384 response
.message
.header
.response
.cas
= htonll(item
->cas
);
386 return response_handler(cookie
, header
, (void*)&response
);
390 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
393 return response_handler(cookie
, header
, (void*)&response
);
396 static protocol_binary_response_status
add_command_handler(const void *cookie
,
397 protocol_binary_request_header
*header
,
398 memcached_binary_protocol_raw_response_handler response_handler
)
400 size_t keylen
= ntohs(header
->request
.keylen
);
401 size_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
402 protocol_binary_request_add
*request
= (void*)header
;
403 uint32_t flags
= ntohl(request
->message
.body
.flags
);
404 time_t timeout
= (time_t)ntohl(request
->message
.body
.expiration
);
405 char *key
= ((char*)header
) + sizeof(*header
) + 8;
406 char *data
= key
+ keylen
;
408 protocol_binary_response_no_extras response
= {
411 .magic
= PROTOCOL_BINARY_RES
,
412 .opcode
= header
->request
.opcode
,
413 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
414 .opaque
= header
->request
.opaque
419 struct item
* item
= get_item(key
, keylen
);
422 item
= create_item(key
, keylen
, data
, datalen
, flags
, timeout
);
424 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM
);
428 /* ADDQ shouldn't return a message */
429 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_ADD
)
431 response
.message
.header
.response
.cas
= htonll(item
->cas
);
433 return response_handler(cookie
, header
, (void*)&response
);
436 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
442 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
);
445 return response_handler(cookie
, header
, (void*)&response
);
448 static protocol_binary_response_status
replace_command_handler(const void *cookie
,
449 protocol_binary_request_header
*header
,
450 memcached_binary_protocol_raw_response_handler response_handler
)
452 size_t keylen
= ntohs(header
->request
.keylen
);
453 size_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
454 protocol_binary_request_replace
*request
= (void*)header
;
455 uint32_t flags
= ntohl(request
->message
.body
.flags
);
456 time_t timeout
= (time_t)ntohl(request
->message
.body
.expiration
);
457 char *key
= ((char*)header
) + sizeof(*header
) + 8;
458 char *data
= key
+ keylen
;
460 protocol_binary_response_no_extras response
= {
463 .magic
= PROTOCOL_BINARY_RES
,
464 .opcode
= header
->request
.opcode
,
465 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
466 .opaque
= header
->request
.opaque
471 struct item
* item
= get_item(key
, keylen
);
473 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
474 else if (header
->request
.cas
== 0 || ntohll(header
->request
.cas
) == item
->cas
)
477 delete_item(key
, keylen
);
478 item
= create_item(key
, keylen
, data
, datalen
, flags
, timeout
);
480 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM
);
484 /* REPLACEQ shouldn't return a message */
485 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_REPLACE
)
487 response
.message
.header
.response
.cas
= htonll(item
->cas
);
489 return response_handler(cookie
, header
, (void*)&response
);
492 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
497 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
);
501 return response_handler(cookie
, header
, (void*)&response
);
504 static protocol_binary_response_status
stat_command_handler(const void *cookie
,
505 protocol_binary_request_header
*header
,
506 memcached_binary_protocol_raw_response_handler response_handler
)
508 /* Just send the terminating packet*/
509 protocol_binary_response_no_extras response
= {
512 .magic
= PROTOCOL_BINARY_RES
,
513 .opcode
= PROTOCOL_BINARY_CMD_STAT
,
514 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
515 .opaque
= header
->request
.opaque
520 return response_handler(cookie
, header
, (void*)&response
);
523 memcached_binary_protocol_callback_st interface_v0_impl
= {
524 .interface_version
= 0,
527 ** There is a number of bugs in the extra options for gcc causing
528 ** warning on these struct initializers. It hurts my heart to remove
529 ** it so I'll just leave it in here so that we can enable it when
530 ** we can drop support for the broken compilers
532 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GET
]= get_command_handler
,
533 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_SET
]= set_command_handler
,
534 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_ADD
]= add_command_handler
,
535 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_REPLACE
]= replace_command_handler
,
536 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DELETE
]= delete_command_handler
,
537 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_INCREMENT
]= arithmetic_command_handler
,
538 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DECREMENT
]= arithmetic_command_handler
,
539 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_QUIT
]= quit_command_handler
,
540 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_FLUSH
]= flush_command_handler
,
541 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GETQ
]= get_command_handler
,
542 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_NOOP
]= noop_command_handler
,
543 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_VERSION
]= version_command_handler
,
544 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GETK
]= get_command_handler
,
545 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GETKQ
]= get_command_handler
,
546 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_APPEND
]= concat_command_handler
,
547 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_PREPEND
]= concat_command_handler
,
548 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_STAT
]= stat_command_handler
,
549 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_SETQ
]= set_command_handler
,
550 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_ADDQ
]= add_command_handler
,
551 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_REPLACEQ
]= replace_command_handler
,
552 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DELETEQ
]= delete_command_handler
,
553 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_INCREMENTQ
]= arithmetic_command_handler
,
554 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DECREMENTQ
]= arithmetic_command_handler
,
555 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_QUITQ
]= quit_command_handler
,
556 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_FLUSHQ
]= flush_command_handler
,
557 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_APPENDQ
]= concat_command_handler
,
558 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_PREPENDQ
]= concat_command_handler
,
562 void initialize_iterface_v0_handler(void)
564 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GET
]= get_command_handler
;
565 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_SET
]= set_command_handler
;
566 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_ADD
]= add_command_handler
;
567 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_REPLACE
]= replace_command_handler
;
568 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DELETE
]= delete_command_handler
;
569 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_INCREMENT
]= arithmetic_command_handler
;
570 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DECREMENT
]= arithmetic_command_handler
;
571 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_QUIT
]= quit_command_handler
;
572 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_FLUSH
]= flush_command_handler
;
573 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GETQ
]= get_command_handler
;
574 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_NOOP
]= noop_command_handler
;
575 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_VERSION
]= version_command_handler
;
576 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GETK
]= get_command_handler
;
577 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GETKQ
]= get_command_handler
;
578 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_APPEND
]= concat_command_handler
;
579 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_PREPEND
]= concat_command_handler
;
580 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_STAT
]= stat_command_handler
;
581 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_SETQ
]= set_command_handler
;
582 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_ADDQ
]= add_command_handler
;
583 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_REPLACEQ
]= replace_command_handler
;
584 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DELETEQ
]= delete_command_handler
;
585 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_INCREMENTQ
]= arithmetic_command_handler
;
586 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DECREMENTQ
]= arithmetic_command_handler
;
587 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_QUITQ
]= quit_command_handler
;
588 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_FLUSHQ
]= flush_command_handler
;
589 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_APPENDQ
]= concat_command_handler
;
590 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_PREPENDQ
]= concat_command_handler
;