Fix for the light server.
[awesomized/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 "config.h"
9
10 #include <assert.h>
11 #include <sys/types.h>
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <string.h>
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
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)
27 {
28 protocol_binary_response_no_extras response;
29 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
30
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;
35
36 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
37 }
38
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)
42 {
43 protocol_binary_response_no_extras response;
44 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
45
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;
50
51 if (header->request.opcode == PROTOCOL_BINARY_CMD_QUIT)
52 {
53 response_handler(cookie, header, (protocol_binary_response_header*)&response);
54 }
55
56 /* I need a better way to signal to close the connection */
57 return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
58 }
59
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)
63 {
64 uint8_t opcode= header->request.opcode;
65 union protocol_binary_response_get_un {
66 protocol_binary_response_get response;
67 char buffer[4096];
68 };
69
70 protocol_binary_response_get_un msg;
71 memset(&msg, 0, sizeof(protocol_binary_response_get_un));
72
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;
77
78 struct item *item= get_item(header + 1, ntohs(header->request.keylen));
79 if (item)
80 {
81 msg.response.message.body.flags= htonl(item->flags);
82 char *ptr= (char*)(msg.response.bytes + sizeof(*header) + 4);
83 uint32_t bodysize= 4;
84 msg.response.message.header.response.cas= example_htonll(item->cas);
85 if (opcode == PROTOCOL_BINARY_CMD_GETK || opcode == PROTOCOL_BINARY_CMD_GETKQ)
86 {
87 memcpy(ptr, item->key, item->nkey);
88 msg.response.message.header.response.keylen= htons((uint16_t)item->nkey);
89 ptr += item->nkey;
90 bodysize += (uint32_t)item->nkey;
91 }
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;
96
97 release_item(item);
98 return response_handler(cookie, header, (protocol_binary_response_header*)&msg);
99 }
100 else if (opcode == PROTOCOL_BINARY_CMD_GET || opcode == PROTOCOL_BINARY_CMD_GETK)
101 {
102 msg.response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
103 return response_handler(cookie, header, (protocol_binary_response_header*)&msg);
104 }
105
106 /* Q shouldn't report a miss ;-) */
107 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
108 }
109
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)
113 {
114 size_t keylen= ntohs(header->request.keylen);
115
116 char *key= ((char*)header) + sizeof(*header);
117 protocol_binary_response_no_extras response;
118 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
119
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;
123
124 if (!delete_item(key, keylen))
125 {
126 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
127 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
128 }
129 else if (header->request.opcode == PROTOCOL_BINARY_CMD_DELETE)
130 {
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);
134 }
135
136 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
137 }
138
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)
142 {
143 uint8_t opcode= header->request.opcode;
144
145 /* @fixme sett inn when! */
146 flush(0);
147
148 if (opcode == PROTOCOL_BINARY_CMD_FLUSH)
149 {
150 protocol_binary_response_no_extras response;
151 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
152
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;
157
158 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
159 }
160
161 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
162 }
163
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)
167 {
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));
171
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;
175
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);
180 uint32_t flags= 0;
181 void *key= req->bytes + sizeof(req->bytes);
182 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
183
184 uint64_t value= initial;
185
186 struct item *item= get_item(key, keylen);
187 if (item != NULL)
188 {
189 if (header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENT ||
190 header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENTQ)
191 {
192 value= (*(uint64_t*)item->data) + delta;
193 }
194 else
195 {
196 if (delta > *(uint64_t*)item->data)
197 {
198 value= 0;
199 }
200 else
201 {
202 value= *(uint64_t*)item->data - delta;
203 }
204 }
205 expiration= (uint32_t)item->exp;
206 flags= item->flags;
207
208 release_item(item);
209 delete_item(key, keylen);
210 }
211
212 item= create_item(key, keylen, NULL, sizeof(value), flags, (time_t)expiration);
213 if (item == NULL)
214 {
215 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
216 }
217 else
218 {
219 memcpy(item->data, &value, sizeof(value));
220 put_item(item);
221 }
222
223 response.message.header.response.status= htons(rval);
224 if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
225 {
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);
229
230 release_item(item);
231 if (header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENTQ ||
232 header->request.opcode == PROTOCOL_BINARY_CMD_DECREMENTQ)
233 {
234 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
235 }
236 }
237
238 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
239 }
240
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)
244 {
245 const char *versionstring= "1.0.0";
246 union protocol_binary_response_header_un
247 {
248 protocol_binary_response_header packet;
249 char buffer[256];
250 };
251
252 protocol_binary_response_header_un response;
253 memset(&response, 0, sizeof(protocol_binary_response_header_un));
254
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));
261
262 assert(sizeof(protocol_binary_response_header) +strlen(versionstring) <= 256);
263 memcpy(response.buffer + sizeof(protocol_binary_response_header), versionstring, strlen(versionstring));
264
265 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
266 }
267
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)
271 {
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;
278
279 struct item *item= get_item(key, keylen);
280 struct item *nitem= NULL;
281
282 if (item == NULL)
283 {
284 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
285 }
286 else if (cas != 0 && cas != item->cas)
287 {
288 rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
289 }
290 else if ((nitem= create_item(key, keylen, NULL, item->size + vallen,
291 item->flags, item->exp)) == NULL)
292 {
293 release_item(item);
294 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
295 }
296 else
297 {
298 if (header->request.opcode == PROTOCOL_BINARY_CMD_APPEND ||
299 header->request.opcode == PROTOCOL_BINARY_CMD_APPENDQ)
300 {
301 memcpy(nitem->data, item->data, item->size);
302 memcpy(((char*)(nitem->data)) + item->size, val, vallen);
303 }
304 else
305 {
306 memcpy(nitem->data, val, vallen);
307 memcpy(((char*)(nitem->data)) + vallen, item->data, item->size);
308 }
309 release_item(item);
310 delete_item(key, keylen);
311 put_item(nitem);
312 cas= nitem->cas;
313 release_item(nitem);
314
315 if (header->request.opcode == PROTOCOL_BINARY_CMD_APPEND ||
316 header->request.opcode == PROTOCOL_BINARY_CMD_PREPEND)
317 {
318 protocol_binary_response_no_extras response;
319 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
320
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);
326
327 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
328 }
329 }
330
331 return rval;
332 }
333
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)
337 {
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;
345
346 protocol_binary_response_no_extras response;
347 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
348
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;
353
354 if (header->request.cas != 0)
355 {
356 /* validate cas */
357 struct item* item= get_item(key, keylen);
358 if (item != NULL)
359 {
360 if (item->cas != example_ntohll(header->request.cas))
361 {
362 release_item(item);
363 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
364 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
365 }
366 release_item(item);
367 }
368 }
369
370 delete_item(key, keylen);
371 struct item* item= create_item(key, keylen, data, datalen, flags, timeout);
372 if (item == NULL)
373 {
374 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
375 }
376 else
377 {
378 put_item(item);
379 /* SETQ shouldn't return a message */
380 if (header->request.opcode == PROTOCOL_BINARY_CMD_SET)
381 {
382 response.message.header.response.cas= example_htonll(item->cas);
383 release_item(item);
384 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
385 }
386 release_item(item);
387
388 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
389 }
390
391 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
392 }
393
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)
397 {
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;
405
406 protocol_binary_response_no_extras response;
407 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
408
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;
413
414 struct item* item= get_item(key, keylen);
415 if (item == NULL)
416 {
417 item= create_item(key, keylen, data, datalen, flags, timeout);
418 if (item == NULL)
419 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
420 else
421 {
422 put_item(item);
423 /* ADDQ shouldn't return a message */
424 if (header->request.opcode == PROTOCOL_BINARY_CMD_ADD)
425 {
426 response.message.header.response.cas= example_htonll(item->cas);
427 release_item(item);
428 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
429 }
430 release_item(item);
431 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
432 }
433 }
434 else
435 {
436 release_item(item);
437 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
438 }
439
440 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
441 }
442
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)
446 {
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;
454
455 protocol_binary_response_no_extras response;
456 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
457
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;
462
463 struct item* item= get_item(key, keylen);
464 if (item == NULL)
465 {
466 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
467 }
468 else if (header->request.cas == 0 || example_ntohll(header->request.cas) == item->cas)
469 {
470 release_item(item);
471 delete_item(key, keylen);
472 item= create_item(key, keylen, data, datalen, flags, timeout);
473
474 if (item == NULL)
475 {
476 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
477 }
478 else
479 {
480 put_item(item);
481 /* REPLACEQ shouldn't return a message */
482 if (header->request.opcode == PROTOCOL_BINARY_CMD_REPLACE)
483 {
484 response.message.header.response.cas= example_htonll(item->cas);
485 release_item(item);
486 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
487 }
488 release_item(item);
489 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
490 }
491 }
492 else
493 {
494 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
495 release_item(item);
496 }
497
498 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
499 }
500
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)
504 {
505 /* Just send the terminating packet*/
506 protocol_binary_response_no_extras response;
507 memset(&response, 0, sizeof(protocol_binary_response_no_extras));
508
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;
513
514 return response_handler(cookie, header, (protocol_binary_response_header*)&response);
515 }
516
517 memcached_binary_protocol_callback_st interface_v0_impl;
518
519 void initialize_interface_v0_handler(void)
520 {
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;
549 }