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 <libmemcachedprotocol-0.0/handler.h>
20 #include <example/byteorder.h>
21 #include "example/memcached_light.h"
22 #include "example/storage.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 memset(&response
, 0, sizeof(protocol_binary_response_no_extras
));
31 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
32 response
.message
.header
.response
.opcode
= PROTOCOL_BINARY_CMD_NOOP
;
33 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
34 response
.message
.header
.response
.opaque
= header
->request
.opaque
;
36 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
39 static protocol_binary_response_status
quit_command_handler(const void *cookie
,
40 protocol_binary_request_header
*header
,
41 memcached_binary_protocol_raw_response_handler response_handler
)
43 protocol_binary_response_no_extras response
;
44 memset(&response
, 0, sizeof(protocol_binary_response_no_extras
));
46 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
47 response
.message
.header
.response
.opcode
= PROTOCOL_BINARY_CMD_QUIT
;
48 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
49 response
.message
.header
.response
.opaque
= header
->request
.opaque
;
51 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_QUIT
)
53 response_handler(cookie
, header
, (protocol_binary_response_header
*)&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
;
65 union protocol_binary_response_get_un
{
66 protocol_binary_response_get response
;
70 protocol_binary_response_get_un msg
;
71 memset(&msg
, 0, sizeof(protocol_binary_response_get_un
));
73 msg
.response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
74 msg
.response
.message
.header
.response
.opcode
= opcode
;
75 msg
.response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
76 msg
.response
.message
.header
.response
.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
= example_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
, (protocol_binary_response_header
*)&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
, (protocol_binary_response_header
*)&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
);
116 char *key
= ((char*)header
) + sizeof(*header
);
117 protocol_binary_response_no_extras response
;
118 memset(&response
, 0, sizeof(protocol_binary_response_no_extras
));
120 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
121 response
.message
.header
.response
.opcode
= header
->request
.opcode
;
122 response
.message
.header
.response
.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
, (protocol_binary_response_header
*)&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
, (protocol_binary_response_header
*)&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 memset(&response
, 0, sizeof(protocol_binary_response_no_extras
));
153 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
154 response
.message
.header
.response
.opcode
= opcode
;
155 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
156 response
.message
.header
.response
.opaque
= header
->request
.opaque
;
158 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&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
= (protocol_binary_request_incr
*)header
;
169 protocol_binary_response_incr response
;
170 memset(&response
, 0, sizeof(protocol_binary_response_incr
));
172 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
173 response
.message
.header
.response
.opcode
= header
->request
.opcode
;
174 response
.message
.header
.response
.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
, (protocol_binary_response_header
*)&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";
246 union protocol_binary_response_header_un
248 protocol_binary_response_header packet
;
252 protocol_binary_response_header_un response
;
253 memset(&response
, 0, sizeof(protocol_binary_response_header_un
));
255 response
.packet
.response
.magic
= PROTOCOL_BINARY_RES
;
256 response
.packet
.response
.opcode
= PROTOCOL_BINARY_CMD_VERSION
;
257 response
.packet
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
258 response
.packet
.response
.opaque
= header
->request
.opaque
;
259 response
.packet
.response
.cas
= 0;
260 response
.packet
.response
.bodylen
= htonl((uint32_t)strlen(versionstring
));
262 assert(sizeof(protocol_binary_response_header
) +strlen(versionstring
) <= 256);
263 memcpy(response
.buffer
+ sizeof(protocol_binary_response_header
), versionstring
, strlen(versionstring
));
265 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
268 static protocol_binary_response_status
concat_command_handler(const void *cookie
,
269 protocol_binary_request_header
*header
,
270 memcached_binary_protocol_raw_response_handler response_handler
)
272 protocol_binary_response_status rval
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
273 uint16_t keylen
= ntohs(header
->request
.keylen
);
274 uint64_t cas
= example_ntohll(header
->request
.cas
);
275 void *key
= header
+ 1;
276 uint32_t vallen
= ntohl(header
->request
.bodylen
) - keylen
;
277 void *val
= (char*)key
+ keylen
;
279 struct item
*item
= get_item(key
, keylen
);
280 struct item
*nitem
= NULL
;
284 rval
= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
;
286 else if (cas
!= 0 && cas
!= item
->cas
)
288 rval
= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
;
290 else if ((nitem
= create_item(key
, keylen
, NULL
, item
->size
+ vallen
,
291 item
->flags
, item
->exp
)) == NULL
)
294 rval
= PROTOCOL_BINARY_RESPONSE_ENOMEM
;
298 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_APPEND
||
299 header
->request
.opcode
== PROTOCOL_BINARY_CMD_APPENDQ
)
301 memcpy(nitem
->data
, item
->data
, item
->size
);
302 memcpy(((char*)(nitem
->data
)) + item
->size
, val
, vallen
);
306 memcpy(nitem
->data
, val
, vallen
);
307 memcpy(((char*)(nitem
->data
)) + vallen
, item
->data
, item
->size
);
310 delete_item(key
, keylen
);
315 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_APPEND
||
316 header
->request
.opcode
== PROTOCOL_BINARY_CMD_PREPEND
)
318 protocol_binary_response_no_extras response
;
319 memset(&response
, 0, sizeof(protocol_binary_response_no_extras
));
321 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
322 response
.message
.header
.response
.opcode
= header
->request
.opcode
;
323 response
.message
.header
.response
.status
= htons(rval
);
324 response
.message
.header
.response
.opaque
= header
->request
.opaque
;
325 response
.message
.header
.response
.cas
= example_htonll(cas
);
327 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
334 static protocol_binary_response_status
set_command_handler(const void *cookie
,
335 protocol_binary_request_header
*header
,
336 memcached_binary_protocol_raw_response_handler response_handler
)
338 size_t keylen
= ntohs(header
->request
.keylen
);
339 size_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
340 protocol_binary_request_replace
*request
= (protocol_binary_request_replace
*)header
;
341 uint32_t flags
= ntohl(request
->message
.body
.flags
);
342 time_t timeout
= (time_t)ntohl(request
->message
.body
.expiration
);
343 char *key
= ((char*)header
) + sizeof(*header
) + 8;
344 char *data
= key
+ keylen
;
346 protocol_binary_response_no_extras response
;
347 memset(&response
, 0, sizeof(protocol_binary_response_no_extras
));
349 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
350 response
.message
.header
.response
.opcode
= header
->request
.opcode
;
351 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
352 response
.message
.header
.response
.opaque
= header
->request
.opaque
;
354 if (header
->request
.cas
!= 0)
357 struct item
* item
= get_item(key
, keylen
);
360 if (item
->cas
!= example_ntohll(header
->request
.cas
))
363 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
);
364 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
370 delete_item(key
, keylen
);
371 struct item
* item
= create_item(key
, keylen
, data
, datalen
, flags
, timeout
);
374 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM
);
379 /* SETQ shouldn't return a message */
380 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_SET
)
382 response
.message
.header
.response
.cas
= example_htonll(item
->cas
);
384 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
388 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
391 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
394 static protocol_binary_response_status
add_command_handler(const void *cookie
,
395 protocol_binary_request_header
*header
,
396 memcached_binary_protocol_raw_response_handler response_handler
)
398 size_t keylen
= ntohs(header
->request
.keylen
);
399 size_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
400 protocol_binary_request_add
*request
= (protocol_binary_request_add
*)header
;
401 uint32_t flags
= ntohl(request
->message
.body
.flags
);
402 time_t timeout
= (time_t)ntohl(request
->message
.body
.expiration
);
403 char *key
= ((char*)header
) + sizeof(*header
) + 8;
404 char *data
= key
+ keylen
;
406 protocol_binary_response_no_extras response
;
407 memset(&response
, 0, sizeof(protocol_binary_response_no_extras
));
409 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
410 response
.message
.header
.response
.opcode
= header
->request
.opcode
;
411 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
412 response
.message
.header
.response
.opaque
= header
->request
.opaque
;
414 struct item
* item
= get_item(key
, keylen
);
417 item
= create_item(key
, keylen
, data
, datalen
, flags
, timeout
);
419 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM
);
423 /* ADDQ shouldn't return a message */
424 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_ADD
)
426 response
.message
.header
.response
.cas
= example_htonll(item
->cas
);
428 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
431 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
437 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
);
440 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
443 static protocol_binary_response_status
replace_command_handler(const void *cookie
,
444 protocol_binary_request_header
*header
,
445 memcached_binary_protocol_raw_response_handler response_handler
)
447 size_t keylen
= ntohs(header
->request
.keylen
);
448 size_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
449 protocol_binary_request_replace
*request
= (protocol_binary_request_replace
*)header
;
450 uint32_t flags
= ntohl(request
->message
.body
.flags
);
451 time_t timeout
= (time_t)ntohl(request
->message
.body
.expiration
);
452 char *key
= ((char*)header
) + sizeof(*header
) + 8;
453 char *data
= key
+ keylen
;
455 protocol_binary_response_no_extras response
;
456 memset(&response
, 0, sizeof(protocol_binary_response_no_extras
));
458 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
459 response
.message
.header
.response
.opcode
= header
->request
.opcode
;
460 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
461 response
.message
.header
.response
.opaque
= header
->request
.opaque
;
463 struct item
* item
= get_item(key
, keylen
);
466 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
);
468 else if (header
->request
.cas
== 0 || example_ntohll(header
->request
.cas
) == item
->cas
)
471 delete_item(key
, keylen
);
472 item
= create_item(key
, keylen
, data
, datalen
, flags
, timeout
);
476 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM
);
481 /* REPLACEQ shouldn't return a message */
482 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_REPLACE
)
484 response
.message
.header
.response
.cas
= example_htonll(item
->cas
);
486 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
489 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
494 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
);
498 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
501 static protocol_binary_response_status
stat_command_handler(const void *cookie
,
502 protocol_binary_request_header
*header
,
503 memcached_binary_protocol_raw_response_handler response_handler
)
505 /* Just send the terminating packet*/
506 protocol_binary_response_no_extras response
;
507 memset(&response
, 0, sizeof(protocol_binary_response_no_extras
));
509 response
.message
.header
.response
.magic
= PROTOCOL_BINARY_RES
;
510 response
.message
.header
.response
.opcode
= PROTOCOL_BINARY_CMD_STAT
;
511 response
.message
.header
.response
.status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
);
512 response
.message
.header
.response
.opaque
= header
->request
.opaque
;
514 return response_handler(cookie
, header
, (protocol_binary_response_header
*)&response
);
517 memcached_binary_protocol_callback_st interface_v0_impl
;
519 void initialize_interface_v0_handler(void)
521 interface_v0_impl
.interface_version
= MEMCACHED_PROTOCOL_HANDLER_V0
;
522 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GET
]= get_command_handler
;
523 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_SET
]= set_command_handler
;
524 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_ADD
]= add_command_handler
;
525 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_REPLACE
]= replace_command_handler
;
526 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DELETE
]= delete_command_handler
;
527 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_INCREMENT
]= arithmetic_command_handler
;
528 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DECREMENT
]= arithmetic_command_handler
;
529 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_QUIT
]= quit_command_handler
;
530 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_FLUSH
]= flush_command_handler
;
531 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GETQ
]= get_command_handler
;
532 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_NOOP
]= noop_command_handler
;
533 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_VERSION
]= version_command_handler
;
534 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GETK
]= get_command_handler
;
535 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_GETKQ
]= get_command_handler
;
536 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_APPEND
]= concat_command_handler
;
537 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_PREPEND
]= concat_command_handler
;
538 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_STAT
]= stat_command_handler
;
539 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_SETQ
]= set_command_handler
;
540 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_ADDQ
]= add_command_handler
;
541 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_REPLACEQ
]= replace_command_handler
;
542 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DELETEQ
]= delete_command_handler
;
543 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_INCREMENTQ
]= arithmetic_command_handler
;
544 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_DECREMENTQ
]= arithmetic_command_handler
;
545 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_QUITQ
]= quit_command_handler
;
546 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_FLUSHQ
]= flush_command_handler
;
547 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_APPENDQ
]= concat_command_handler
;
548 interface_v0_impl
.interface
.v0
.comcode
[PROTOCOL_BINARY_CMD_PREPENDQ
]= concat_command_handler
;