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 
noop_command_handler(const void * cookie,protocol_binary_request_header * header,memcached_binary_protocol_raw_response_handler response_handler)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 
quit_command_handler(const void * cookie,protocol_binary_request_header * header,memcached_binary_protocol_raw_response_handler response_handler)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 
get_command_handler(const void * cookie,protocol_binary_request_header * header,memcached_binary_protocol_raw_response_handler response_handler)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 
delete_command_handler(const void * cookie,protocol_binary_request_header * header,memcached_binary_protocol_raw_response_handler response_handler)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 
flush_command_handler(const void * cookie,protocol_binary_request_header * header,memcached_binary_protocol_raw_response_handler response_handler)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 
arithmetic_command_handler(const void * cookie,protocol_binary_request_header * header,memcached_binary_protocol_raw_response_handler response_handler)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 
version_command_handler(const void * cookie,protocol_binary_request_header * header,memcached_binary_protocol_raw_response_handler response_handler)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 
concat_command_handler(const void * cookie,protocol_binary_request_header * header,memcached_binary_protocol_raw_response_handler response_handler)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 
set_command_handler(const void * cookie,protocol_binary_request_header * header,memcached_binary_protocol_raw_response_handler response_handler)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 
add_command_handler(const void * cookie,protocol_binary_request_header * header,memcached_binary_protocol_raw_response_handler response_handler)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 
replace_command_handler(const void * cookie,protocol_binary_request_header * header,memcached_binary_protocol_raw_response_handler response_handler)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 
stat_command_handler(const void * cookie,protocol_binary_request_header * header,memcached_binary_protocol_raw_response_handler response_handler)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 
initialize_interface_v0_handler(util::log_info_st & arg)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 }
562