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 ;-)
11 #include <sys/types.h>
19 #include <libmemcached/protocol_handler.h>
20 #include <example/byteorder.h>
22 #include "memcached_light.h"
24 static protocol_binary_response_status
noop_command_handler(const void *cookie
,
25 protocol_binary_request_header
*header
,
26 memcached_binary_protocol_raw_response_handler response_handler
)
28 protocol_binary_response_no_extras response
= {
29 .message
.header
.response
= {
30 .magic
= PROTOCOL_BINARY_RES
,
31 .opcode
= PROTOCOL_BINARY_CMD_NOOP
,
32 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
33 .opaque
= header
->request
.opaque
37 return response_handler(cookie
, header
, (void*)&response
);
40 static protocol_binary_response_status
quit_command_handler(const void *cookie
,
41 protocol_binary_request_header
*header
,
42 memcached_binary_protocol_raw_response_handler response_handler
)
44 protocol_binary_response_no_extras response
= {
45 .message
.header
.response
= {
46 .magic
= PROTOCOL_BINARY_RES
,
47 .opcode
= PROTOCOL_BINARY_CMD_QUIT
,
48 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
49 .opaque
= header
->request
.opaque
53 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_QUIT
)
54 response_handler(cookie
, header
, (void*)&response
);
56 /* I need a better way to signal to close the connection */
57 return PROTOCOL_BINARY_RESPONSE_EINTERNAL
;
60 static protocol_binary_response_status
get_command_handler(const void *cookie
,
61 protocol_binary_request_header
*header
,
62 memcached_binary_protocol_raw_response_handler response_handler
)
64 uint8_t opcode
= header
->request
.opcode
;
66 protocol_binary_response_get response
;
69 .response
.message
.header
.response
= {
70 .magic
= PROTOCOL_BINARY_RES
,
72 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
73 .opaque
= header
->request
.opaque
77 struct item
*item
= get_item(header
+ 1, ntohs(header
->request
.keylen
));
80 msg
.response
.message
.body
.flags
= htonl(item
->flags
);
81 char *ptr
= (char*)(msg
.response
.bytes
+ sizeof(*header
) + 4);
83 msg
.response
.message
.header
.response
.cas
= example_htonll(item
->cas
);
84 if (opcode
== PROTOCOL_BINARY_CMD_GETK
|| opcode
== PROTOCOL_BINARY_CMD_GETKQ
)
86 memcpy(ptr
, item
->key
, item
->nkey
);
87 msg
.response
.message
.header
.response
.keylen
= htons((uint16_t)item
->nkey
);
89 bodysize
+= (uint32_t)item
->nkey
;
91 memcpy(ptr
, item
->data
, item
->size
);
92 bodysize
+= (uint32_t)item
->size
;
93 msg
.response
.message
.header
.response
.bodylen
= htonl(bodysize
);
94 msg
.response
.message
.header
.response
.extlen
= 4;
97 return response_handler(cookie
, header
, (void*)&msg
);
99 else if (opcode
== PROTOCOL_BINARY_CMD_GET
|| opcode
== PROTOCOL_BINARY_CMD_GETK
)
101 msg
.response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
102 return response_handler(cookie
, header
, (void*)&msg
);
105 /* Q shouldn't report a miss ;-) */
106 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
109 static protocol_binary_response_status
delete_command_handler(const void *cookie
,
110 protocol_binary_request_header
*header
,
111 memcached_binary_protocol_raw_response_handler response_handler
)
113 size_t keylen
= ntohs(header
->request
.keylen
);
114 char *key
= ((char*)header
) + sizeof(*header
);
115 protocol_binary_response_no_extras response
= {
116 .message
.header
.response
= {
117 .magic
= PROTOCOL_BINARY_RES
,
118 .opcode
= header
->request
.opcode
,
119 .opaque
= header
->request
.opaque
123 if (!delete_item(key
, keylen
))
125 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
126 return response_handler(cookie
, header
, (void*)&response
);
128 else if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_DELETE
)
130 /* DELETEQ doesn't want success response */
131 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
132 return response_handler(cookie
, header
, (void*)&response
);
135 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
138 static protocol_binary_response_status
flush_command_handler(const void *cookie
,
139 protocol_binary_request_header
*header
,
140 memcached_binary_protocol_raw_response_handler response_handler
)
142 uint8_t opcode
= header
->request
.opcode
;
144 /* @fixme sett inn when! */
147 if (opcode
== PROTOCOL_BINARY_CMD_FLUSH
)
149 protocol_binary_response_no_extras response
= {
150 .message
.header
.response
= {
151 .magic
= PROTOCOL_BINARY_RES
,
153 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
154 .opaque
= header
->request
.opaque
157 return response_handler(cookie
, header
, (void*)&response
);
160 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
163 static protocol_binary_response_status
arithmetic_command_handler(const void *cookie
,
164 protocol_binary_request_header
*header
,
165 memcached_binary_protocol_raw_response_handler response_handler
)
167 protocol_binary_request_incr
*req
= (void*)header
;
168 protocol_binary_response_incr response
= {
169 .message
.header
.response
= {
170 .magic
= PROTOCOL_BINARY_RES
,
171 .opcode
= header
->request
.opcode
,
172 .opaque
= header
->request
.opaque
,
176 uint16_t keylen
= ntohs(header
->request
.keylen
);
177 uint64_t initial
= example_ntohll(req
->message
.body
.initial
);
178 uint64_t delta
= example_ntohll(req
->message
.body
.delta
);
179 uint32_t expiration
= ntohl(req
->message
.body
.expiration
);
181 void *key
= req
->bytes
+ sizeof(req
->bytes
);
182 protocol_binary_response_status rval
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
184 uint64_t value
= initial
;
186 struct item
*item
= get_item(key
, keylen
);
189 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_INCREMENT
||
190 header
->request
.opcode
== PROTOCOL_BINARY_CMD_INCREMENTQ
)
192 value
= (*(uint64_t*)item
->data
) + delta
;
196 if (delta
> *(uint64_t*)item
->data
)
202 value
= *(uint64_t*)item
->data
- delta
;
205 expiration
= (uint32_t)item
->exp
;
209 delete_item(key
, keylen
);
212 item
= create_item(key
, keylen
, NULL
, sizeof(value
), flags
, (time_t)expiration
);
215 rval
= PROTOCOL_BINARY_RESPONSE_ENOMEM
;
219 memcpy(item
->data
, &value
, sizeof(value
));
223 response
.message
.header
.response
.status
= htons(rval
);
224 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
)
226 response
.message
.header
.response
.bodylen
= ntohl(8);
227 response
.message
.body
.value
= example_ntohll((*(uint64_t*)item
->data
));
228 response
.message
.header
.response
.cas
= example_ntohll(item
->cas
);
231 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_INCREMENTQ
||
232 header
->request
.opcode
== PROTOCOL_BINARY_CMD_DECREMENTQ
)
234 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
238 return response_handler(cookie
, header
, (void*)&response
);
241 static protocol_binary_response_status
version_command_handler(const void *cookie
,
242 protocol_binary_request_header
*header
,
243 memcached_binary_protocol_raw_response_handler response_handler
)
245 const char *versionstring
= "1.0.0";
247 protocol_binary_response_header packet
;
251 .magic
= PROTOCOL_BINARY_RES
,
252 .opcode
= PROTOCOL_BINARY_CMD_VERSION
,
253 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
254 .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
= example_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
,
322 .cas
= example_htonll(cas
),
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
!= example_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
= example_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
= example_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
);
474 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
476 else if (header
->request
.cas
== 0 || example_ntohll(header
->request
.cas
) == item
->cas
)
479 delete_item(key
, keylen
);
480 item
= create_item(key
, keylen
, data
, datalen
, flags
, timeout
);
484 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM
);
489 /* REPLACEQ shouldn't return a message */
490 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_REPLACE
)
492 response
.message
.header
.response
.cas
= example_htonll(item
->cas
);
494 return response_handler(cookie
, header
, (void*)&response
);
497 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
502 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
);
506 return response_handler(cookie
, header
, (void*)&response
);
509 static protocol_binary_response_status
stat_command_handler(const void *cookie
,
510 protocol_binary_request_header
*header
,
511 memcached_binary_protocol_raw_response_handler response_handler
)
513 /* Just send the terminating packet*/
514 protocol_binary_response_no_extras response
= {
517 .magic
= PROTOCOL_BINARY_RES
,
518 .opcode
= PROTOCOL_BINARY_CMD_STAT
,
519 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
520 .opaque
= header
->request
.opaque
525 return response_handler(cookie
, header
, (void*)&response
);
528 memcached_binary_protocol_callback_st interface_v0_impl
= {
529 .interface_version
= MEMCACHED_PROTOCOL_HANDLER_V0
,
532 ** There is a number of bugs in the extra options for gcc causing
533 ** warning on these struct initializers. It hurts my heart to remove
534 ** it so I'll just leave it in here so that we can enable it when
535 ** we can drop support for the broken compilers
537 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GET
]= get_command_handler
,
538 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_SET
]= set_command_handler
,
539 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_ADD
]= add_command_handler
,
540 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_REPLACE
]= replace_command_handler
,
541 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DELETE
]= delete_command_handler
,
542 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_INCREMENT
]= arithmetic_command_handler
,
543 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DECREMENT
]= arithmetic_command_handler
,
544 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_QUIT
]= quit_command_handler
,
545 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_FLUSH
]= flush_command_handler
,
546 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GETQ
]= get_command_handler
,
547 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_NOOP
]= noop_command_handler
,
548 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_VERSION
]= version_command_handler
,
549 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GETK
]= get_command_handler
,
550 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GETKQ
]= get_command_handler
,
551 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_APPEND
]= concat_command_handler
,
552 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_PREPEND
]= concat_command_handler
,
553 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_STAT
]= stat_command_handler
,
554 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_SETQ
]= set_command_handler
,
555 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_ADDQ
]= add_command_handler
,
556 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_REPLACEQ
]= replace_command_handler
,
557 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DELETEQ
]= delete_command_handler
,
558 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_INCREMENTQ
]= arithmetic_command_handler
,
559 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DECREMENTQ
]= arithmetic_command_handler
,
560 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_QUITQ
]= quit_command_handler
,
561 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_FLUSHQ
]= flush_command_handler
,
562 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_APPENDQ
]= concat_command_handler
,
563 .interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_PREPENDQ
]= concat_command_handler
,
567 void initialize_interface_v0_handler(void)
569 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GET
]= get_command_handler
;
570 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_SET
]= set_command_handler
;
571 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_ADD
]= add_command_handler
;
572 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_REPLACE
]= replace_command_handler
;
573 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DELETE
]= delete_command_handler
;
574 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_INCREMENT
]= arithmetic_command_handler
;
575 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DECREMENT
]= arithmetic_command_handler
;
576 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_QUIT
]= quit_command_handler
;
577 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_FLUSH
]= flush_command_handler
;
578 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GETQ
]= get_command_handler
;
579 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_NOOP
]= noop_command_handler
;
580 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_VERSION
]= version_command_handler
;
581 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GETK
]= get_command_handler
;
582 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GETKQ
]= get_command_handler
;
583 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_APPEND
]= concat_command_handler
;
584 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_PREPEND
]= concat_command_handler
;
585 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_STAT
]= stat_command_handler
;
586 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_SETQ
]= set_command_handler
;
587 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_ADDQ
]= add_command_handler
;
588 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_REPLACEQ
]= replace_command_handler
;
589 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DELETEQ
]= delete_command_handler
;
590 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_INCREMENTQ
]= arithmetic_command_handler
;
591 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DECREMENTQ
]= arithmetic_command_handler
;
592 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_QUITQ
]= quit_command_handler
;
593 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_FLUSHQ
]= flush_command_handler
;
594 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_APPENDQ
]= concat_command_handler
;
595 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_PREPENDQ
]= concat_command_handler
;