1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
19 * * The names of its contributors may not be used to endorse or
20 * promote products derived from this software without specific prior
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <libmemcachedprotocol/common.h>
40 #include <sys/types.h>
47 ** **********************************************************************
49 ** **********************************************************************
53 * Send a preformatted packet back to the client. If the connection is in
54 * pedantic mode, it will validate the packet and refuse to send it if it
55 * breaks the specification.
57 * @param cookie client identification
58 * @param request the original request packet
59 * @param response the packet to send
60 * @return The status of the operation
62 static protocol_binary_response_status
raw_response_handler(const void *cookie
,
63 protocol_binary_request_header
*request
,
64 protocol_binary_response_header
*response
)
66 memcached_protocol_client_st
*client
= (void*)cookie
;
68 if (client
->root
->pedantic
&&
69 !memcached_binary_protocol_pedantic_check_response(request
, response
))
71 return PROTOCOL_BINARY_RESPONSE_EINVAL
;
74 if (client
->root
->drain(client
) == false)
76 return PROTOCOL_BINARY_RESPONSE_EINTERNAL
;
79 size_t len
= sizeof(protocol_binary_response_header
) + htonl(response
->response
.bodylen
);
81 char *ptr
= (void*)response
;
83 if (client
->output
== NULL
)
85 /* I can write directly to the socket.... */
88 size_t num_bytes
= len
- offset
;
89 ssize_t nw
= client
->root
->send(client
,
95 if (get_socket_errno() == EWOULDBLOCK
)
99 else if (get_socket_errno() != EINTR
)
101 client
->error
= errno
;
102 return PROTOCOL_BINARY_RESPONSE_EINTERNAL
;
107 offset
+= (size_t)nw
;
109 } while (offset
< len
);
112 return client
->root
->spool(client
, ptr
, len
- offset
);
115 static void print_cmd(protocol_binary_command cmd
)
119 case PROTOCOL_BINARY_CMD_GET
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GET\n", __FILE__
, __LINE__
); return;
120 case PROTOCOL_BINARY_CMD_SET
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SET\n", __FILE__
, __LINE__
); return;
121 case PROTOCOL_BINARY_CMD_ADD
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_ADD\n", __FILE__
, __LINE__
); return;
122 case PROTOCOL_BINARY_CMD_REPLACE
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_REPLACE\n", __FILE__
, __LINE__
); return;
123 case PROTOCOL_BINARY_CMD_DELETE
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DELETE\n", __FILE__
, __LINE__
); return;
124 case PROTOCOL_BINARY_CMD_INCREMENT
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_INCREMENT\n", __FILE__
, __LINE__
); return;
125 case PROTOCOL_BINARY_CMD_DECREMENT
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DECREMENT\n", __FILE__
, __LINE__
); return;
126 case PROTOCOL_BINARY_CMD_QUIT
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_QUIT\n", __FILE__
, __LINE__
); return;
127 case PROTOCOL_BINARY_CMD_FLUSH
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_FLUSH\n", __FILE__
, __LINE__
); return;
128 case PROTOCOL_BINARY_CMD_GETQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GETQ\n", __FILE__
, __LINE__
); return;
129 case PROTOCOL_BINARY_CMD_NOOP
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_NOOP\n", __FILE__
, __LINE__
); return;
130 case PROTOCOL_BINARY_CMD_VERSION
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_VERSION\n", __FILE__
, __LINE__
); return;
131 case PROTOCOL_BINARY_CMD_GETK
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GETK\n", __FILE__
, __LINE__
); return;
132 case PROTOCOL_BINARY_CMD_GETKQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GETKQ\n", __FILE__
, __LINE__
); return;
133 case PROTOCOL_BINARY_CMD_APPEND
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_APPEND\n", __FILE__
, __LINE__
); return;
134 case PROTOCOL_BINARY_CMD_PREPEND
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_PREPEND\n", __FILE__
, __LINE__
); return;
135 case PROTOCOL_BINARY_CMD_STAT
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_STAT\n", __FILE__
, __LINE__
); return;
136 case PROTOCOL_BINARY_CMD_SETQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SETQ\n", __FILE__
, __LINE__
); return;
137 case PROTOCOL_BINARY_CMD_ADDQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_ADDQ\n", __FILE__
, __LINE__
); return;
138 case PROTOCOL_BINARY_CMD_REPLACEQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_REPLACEQ\n", __FILE__
, __LINE__
); return;
139 case PROTOCOL_BINARY_CMD_DELETEQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DELETEQ\n", __FILE__
, __LINE__
); return;
140 case PROTOCOL_BINARY_CMD_INCREMENTQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_INCREMENTQ\n", __FILE__
, __LINE__
); return;
141 case PROTOCOL_BINARY_CMD_DECREMENTQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DECREMENTQ\n", __FILE__
, __LINE__
); return;
142 case PROTOCOL_BINARY_CMD_QUITQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_QUITQ\n", __FILE__
, __LINE__
); return;
143 case PROTOCOL_BINARY_CMD_FLUSHQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_FLUSHQ\n", __FILE__
, __LINE__
); return;
144 case PROTOCOL_BINARY_CMD_APPENDQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_APPENDQ\n", __FILE__
, __LINE__
); return;
145 case PROTOCOL_BINARY_CMD_PREPENDQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_PREPENDQ\n", __FILE__
, __LINE__
); return;
146 case PROTOCOL_BINARY_CMD_VERBOSITY
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_VERBOSITY\n", __FILE__
, __LINE__
); return;
147 case PROTOCOL_BINARY_CMD_TOUCH
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TOUCH\n", __FILE__
, __LINE__
); return;
148 case PROTOCOL_BINARY_CMD_GAT
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GAT\n", __FILE__
, __LINE__
); return;
149 case PROTOCOL_BINARY_CMD_GATQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GATQ\n", __FILE__
, __LINE__
); return;
150 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SASL_LIST_MECHS\n", __FILE__
, __LINE__
); return;
151 case PROTOCOL_BINARY_CMD_SASL_AUTH
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SASL_AUTH\n", __FILE__
, __LINE__
); return;
152 case PROTOCOL_BINARY_CMD_SASL_STEP
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SASL_STEP\n", __FILE__
, __LINE__
); return;
153 case PROTOCOL_BINARY_CMD_RGET
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RGET\n", __FILE__
, __LINE__
); return;
154 case PROTOCOL_BINARY_CMD_RSET
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RSET\n", __FILE__
, __LINE__
); return;
155 case PROTOCOL_BINARY_CMD_RSETQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RSETQ\n", __FILE__
, __LINE__
); return;
156 case PROTOCOL_BINARY_CMD_RAPPEND
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RAPPEND\n", __FILE__
, __LINE__
); return;
157 case PROTOCOL_BINARY_CMD_RAPPENDQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RAPPENDQ\n", __FILE__
, __LINE__
); return;
158 case PROTOCOL_BINARY_CMD_RPREPEND
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RPREPEND\n", __FILE__
, __LINE__
); return;
159 case PROTOCOL_BINARY_CMD_RPREPENDQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RPREPENDQ\n", __FILE__
, __LINE__
); return;
160 case PROTOCOL_BINARY_CMD_RDELETE
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDELETE\n", __FILE__
, __LINE__
); return;
161 case PROTOCOL_BINARY_CMD_RDELETEQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDELETEQ\n", __FILE__
, __LINE__
); return;
162 case PROTOCOL_BINARY_CMD_RINCR
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RINCR\n", __FILE__
, __LINE__
); return;
163 case PROTOCOL_BINARY_CMD_RINCRQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RINCRQ\n", __FILE__
, __LINE__
); return;
164 case PROTOCOL_BINARY_CMD_RDECR
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDECR\n", __FILE__
, __LINE__
); return;
165 case PROTOCOL_BINARY_CMD_RDECRQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDECRQ\n", __FILE__
, __LINE__
); return;
166 case PROTOCOL_BINARY_CMD_SET_VBUCKET
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SET_VBUCKET\n", __FILE__
, __LINE__
); return;
167 case PROTOCOL_BINARY_CMD_GET_VBUCKET
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GET_VBUCKET\n", __FILE__
, __LINE__
); return;
168 case PROTOCOL_BINARY_CMD_DEL_VBUCKET
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DEL_VBUCKET\n", __FILE__
, __LINE__
); return;
169 case PROTOCOL_BINARY_CMD_TAP_CONNECT
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_CONNECT\n", __FILE__
, __LINE__
); return;
170 case PROTOCOL_BINARY_CMD_TAP_MUTATION
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_MUTATION\n", __FILE__
, __LINE__
); return;
171 case PROTOCOL_BINARY_CMD_TAP_DELETE
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_DELETE\n", __FILE__
, __LINE__
); return;
172 case PROTOCOL_BINARY_CMD_TAP_FLUSH
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_FLUSH\n", __FILE__
, __LINE__
); return;
173 case PROTOCOL_BINARY_CMD_TAP_OPAQUE
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_OPAQUE\n", __FILE__
, __LINE__
); return;
174 case PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET\n", __FILE__
, __LINE__
); return;
175 case PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START\n", __FILE__
, __LINE__
); return;
176 case PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END\n", __FILE__
, __LINE__
); return;
177 case PROTOCOL_BINARY_CMD_LAST_RESERVED
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_LAST_RESERVED\n", __FILE__
, __LINE__
); return;
178 case PROTOCOL_BINARY_CMD_GATK
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GATK\n", __FILE__
, __LINE__
); return;
179 case PROTOCOL_BINARY_CMD_GATKQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GATKQ\n", __FILE__
, __LINE__
); return;
180 case PROTOCOL_BINARY_CMD_SCRUB
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SCRUB\n", __FILE__
, __LINE__
); return;
187 * Version 0 of the interface is really low level and protocol specific,
188 * while the version 1 of the interface is more API focused. We need a
189 * way to translate between the command codes on the wire and the
190 * application level interface in V1, so let's just use the V0 of the
191 * interface as a map instead of creating a huuuge switch :-)
195 * Callback for the GET/GETQ/GETK and GETKQ responses
196 * @param cookie client identifier
197 * @param key the key for the item
198 * @param keylen the length of the key
199 * @param body the length of the body
200 * @param bodylen the length of the body
201 * @param flags the flags for the item
202 * @param cas the CAS id for the item
204 static protocol_binary_response_status
get_response_handler(const void *cookie
,
212 memcached_protocol_client_st
*client
= (void*)cookie
;
213 uint8_t opcode
= client
->current_command
->request
.opcode
;
215 if (opcode
== PROTOCOL_BINARY_CMD_GET
|| opcode
== PROTOCOL_BINARY_CMD_GETQ
)
220 protocol_binary_response_get response
= {
221 .message
.header
.response
= {
222 .magic
= PROTOCOL_BINARY_RES
,
224 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
225 .opaque
= client
->current_command
->request
.opaque
,
226 .cas
= memcached_htonll(cas
),
227 .keylen
= htons(keylen
),
229 .bodylen
= htonl(bodylen
+ keylen
+ 4),
233 response
.message
.body
.flags
= htonl(flags
);
235 protocol_binary_response_status rval
;
236 const protocol_binary_response_status success
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
237 if ((rval
= client
->root
->spool(client
, response
.bytes
, sizeof(response
.bytes
))) != success
||
238 (rval
= client
->root
->spool(client
, key
, keylen
)) != success
||
239 (rval
= client
->root
->spool(client
, body
, bodylen
)) != success
)
244 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
248 * Callback for the STAT responses
249 * @param cookie client identifier
250 * @param key the key for the item
251 * @param keylen the length of the key
252 * @param body the length of the body
253 * @param bodylen the length of the body
255 static protocol_binary_response_status
stat_response_handler(const void *cookie
,
262 memcached_protocol_client_st
*client
= (void*)cookie
;
264 protocol_binary_response_no_extras response
= {
265 .message
.header
.response
= {
266 .magic
= PROTOCOL_BINARY_RES
,
267 .opcode
= client
->current_command
->request
.opcode
,
268 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
269 .opaque
= client
->current_command
->request
.opaque
,
270 .keylen
= htons(keylen
),
271 .bodylen
= htonl(bodylen
+ keylen
),
276 protocol_binary_response_status rval
;
277 const protocol_binary_response_status success
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
278 if ((rval
= client
->root
->spool(client
, response
.bytes
, sizeof(response
.bytes
))) != success
||
279 (rval
= client
->root
->spool(client
, key
, keylen
)) != success
||
280 (rval
= client
->root
->spool(client
, body
, bodylen
)) != success
)
285 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
289 * Callback for the VERSION responses
290 * @param cookie client identifier
291 * @param text the length of the body
292 * @param textlen the length of the body
294 static protocol_binary_response_status
version_response_handler(const void *cookie
,
299 memcached_protocol_client_st
*client
= (void*)cookie
;
301 protocol_binary_response_no_extras response
= {
302 .message
.header
.response
= {
303 .magic
= PROTOCOL_BINARY_RES
,
304 .opcode
= client
->current_command
->request
.opcode
,
305 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
306 .opaque
= client
->current_command
->request
.opaque
,
307 .bodylen
= htonl(textlen
),
312 protocol_binary_response_status rval
;
313 const protocol_binary_response_status success
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
314 if ((rval
= client
->root
->spool(client
, response
.bytes
, sizeof(response
.bytes
))) != success
||
315 (rval
= client
->root
->spool(client
, text
, textlen
)) != success
)
320 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
324 * Callback for ADD and ADDQ
325 * @param cookie the calling client
326 * @param header the add/addq command
327 * @param response_handler not used
328 * @return the result of the operation
330 static protocol_binary_response_status
331 add_command_handler(const void *cookie
,
332 protocol_binary_request_header
*header
,
333 memcached_binary_protocol_raw_response_handler response_handler
)
335 protocol_binary_response_status rval
;
337 memcached_protocol_client_st
*client
= (void*)cookie
;
338 if (client
->root
->callback
->interface
.v1
.add
!= NULL
)
340 uint16_t keylen
= ntohs(header
->request
.keylen
);
341 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
342 protocol_binary_request_add
*request
= (void*)header
;
343 uint32_t flags
= ntohl(request
->message
.body
.flags
);
344 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
345 char *key
= ((char*)header
) + sizeof(*header
) + 8;
346 char *data
= key
+ keylen
;
349 rval
= client
->root
->callback
->interface
.v1
.add(cookie
, key
, keylen
,
350 data
, datalen
, flags
,
353 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
354 header
->request
.opcode
== PROTOCOL_BINARY_CMD_ADD
)
356 /* Send a positive request */
357 protocol_binary_response_no_extras response
= {
360 .magic
= PROTOCOL_BINARY_RES
,
361 .opcode
= PROTOCOL_BINARY_CMD_ADD
,
362 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
363 .opaque
= header
->request
.opaque
,
364 .cas
= memcached_ntohll(cas
)
368 rval
= response_handler(cookie
, header
, (void*)&response
);
373 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
380 * Callback for DECREMENT and DECREMENTQ
381 * @param cookie the calling client
382 * @param header the command
383 * @param response_handler not used
384 * @return the result of the operation
386 static protocol_binary_response_status
387 decrement_command_handler(const void *cookie
,
388 protocol_binary_request_header
*header
,
389 memcached_binary_protocol_raw_response_handler response_handler
)
391 (void)response_handler
;
392 protocol_binary_response_status rval
;
394 memcached_protocol_client_st
*client
= (void*)cookie
;
395 if (client
->root
->callback
->interface
.v1
.decrement
!= NULL
)
397 uint16_t keylen
= ntohs(header
->request
.keylen
);
398 protocol_binary_request_decr
*request
= (void*)header
;
399 uint64_t init
= memcached_ntohll(request
->message
.body
.initial
);
400 uint64_t delta
= memcached_ntohll(request
->message
.body
.delta
);
401 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
402 void *key
= request
->bytes
+ sizeof(request
->bytes
);
406 rval
= client
->root
->callback
->interface
.v1
.decrement(cookie
, key
, keylen
,
407 delta
, init
, timeout
,
409 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
410 header
->request
.opcode
== PROTOCOL_BINARY_CMD_DECREMENT
)
412 /* Send a positive request */
413 protocol_binary_response_decr response
= {
416 .magic
= PROTOCOL_BINARY_RES
,
417 .opcode
= PROTOCOL_BINARY_CMD_DECREMENT
,
418 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
419 .opaque
= header
->request
.opaque
,
420 .cas
= memcached_ntohll(cas
),
423 .body
.value
= memcached_htonll(result
)
426 rval
= response_handler(cookie
, header
, (void*)&response
);
431 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
438 * Callback for DELETE and DELETEQ
439 * @param cookie the calling client
440 * @param header the command
441 * @param response_handler not used
442 * @return the result of the operation
444 static protocol_binary_response_status
delete_command_handler(const void *cookie
,
445 protocol_binary_request_header
*header
,
446 memcached_binary_protocol_raw_response_handler response_handler
)
448 (void)response_handler
;
449 protocol_binary_response_status rval
;
451 memcached_protocol_client_st
*client
= (void*)cookie
;
452 if (client
->root
->callback
->interface
.v1
.delete_object
!= NULL
)
454 uint16_t keylen
= ntohs(header
->request
.keylen
);
455 void *key
= (header
+1);
456 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
457 rval
= client
->root
->callback
->interface
.v1
.delete_object(cookie
, key
, keylen
, cas
);
458 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
459 header
->request
.opcode
== PROTOCOL_BINARY_CMD_DELETE
)
461 /* Send a positive request */
462 protocol_binary_response_no_extras response
= {
465 .magic
= PROTOCOL_BINARY_RES
,
466 .opcode
= PROTOCOL_BINARY_CMD_DELETE
,
467 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
468 .opaque
= header
->request
.opaque
,
472 rval
= response_handler(cookie
, header
, (void*)&response
);
477 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
484 * Callback for FLUSH and FLUSHQ
485 * @param cookie the calling client
486 * @param header the command
487 * @param response_handler not used
488 * @return the result of the operation
490 static protocol_binary_response_status
491 flush_command_handler(const void *cookie
,
492 protocol_binary_request_header
*header
,
493 memcached_binary_protocol_raw_response_handler response_handler
)
495 (void)response_handler
;
496 protocol_binary_response_status rval
;
498 memcached_protocol_client_st
*client
= (void*)cookie
;
499 if (client
->root
->callback
->interface
.v1
.flush_object
!= NULL
)
501 protocol_binary_request_flush
*flush_object
= (void*)header
;
503 if (htonl(header
->request
.bodylen
) == 4)
505 timeout
= ntohl(flush_object
->message
.body
.expiration
);
508 rval
= client
->root
->callback
->interface
.v1
.flush_object(cookie
, timeout
);
509 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
510 header
->request
.opcode
== PROTOCOL_BINARY_CMD_FLUSH
)
512 /* Send a positive request */
513 protocol_binary_response_no_extras response
= {
516 .magic
= PROTOCOL_BINARY_RES
,
517 .opcode
= PROTOCOL_BINARY_CMD_FLUSH
,
518 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
519 .opaque
= header
->request
.opaque
,
523 rval
= response_handler(cookie
, header
, (void*)&response
);
528 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
535 * Callback for GET, GETK, GETQ, GETKQ
536 * @param cookie the calling client
537 * @param header the command
538 * @param response_handler not used
539 * @return the result of the operation
541 static protocol_binary_response_status
542 get_command_handler(const void *cookie
,
543 protocol_binary_request_header
*header
,
544 memcached_binary_protocol_raw_response_handler response_handler
)
546 (void)response_handler
;
547 protocol_binary_response_status rval
;
549 memcached_protocol_client_st
*client
= (void*)cookie
;
550 if (client
->root
->callback
->interface
.v1
.get
!= NULL
)
552 uint16_t keylen
= ntohs(header
->request
.keylen
);
553 void *key
= (header
+ 1);
554 rval
= client
->root
->callback
->interface
.v1
.get(cookie
, key
, keylen
,
555 get_response_handler
);
557 if (rval
== PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
&&
558 (header
->request
.opcode
== PROTOCOL_BINARY_CMD_GETQ
||
559 header
->request
.opcode
== PROTOCOL_BINARY_CMD_GETKQ
))
561 /* Quiet commands shouldn't respond on cache misses */
562 rval
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
567 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
574 * Callback for INCREMENT and INCREMENTQ
575 * @param cookie the calling client
576 * @param header the command
577 * @param response_handler not used
578 * @return the result of the operation
580 static protocol_binary_response_status
581 increment_command_handler(const void *cookie
,
582 protocol_binary_request_header
*header
,
583 memcached_binary_protocol_raw_response_handler response_handler
)
585 (void)response_handler
;
586 protocol_binary_response_status rval
;
588 memcached_protocol_client_st
*client
= (void*)cookie
;
589 if (client
->root
->callback
->interface
.v1
.increment
!= NULL
)
591 uint16_t keylen
= ntohs(header
->request
.keylen
);
592 protocol_binary_request_incr
*request
= (void*)header
;
593 uint64_t init
= memcached_ntohll(request
->message
.body
.initial
);
594 uint64_t delta
= memcached_ntohll(request
->message
.body
.delta
);
595 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
596 void *key
= request
->bytes
+ sizeof(request
->bytes
);
600 rval
= client
->root
->callback
->interface
.v1
.increment(cookie
, key
, keylen
,
601 delta
, init
, timeout
,
603 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
604 header
->request
.opcode
== PROTOCOL_BINARY_CMD_INCREMENT
)
606 /* Send a positive request */
607 protocol_binary_response_incr response
= {
610 .magic
= PROTOCOL_BINARY_RES
,
611 .opcode
= PROTOCOL_BINARY_CMD_INCREMENT
,
612 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
613 .opaque
= header
->request
.opaque
,
614 .cas
= memcached_ntohll(cas
),
617 .body
.value
= memcached_htonll(result
)
621 rval
= response_handler(cookie
, header
, (void*)&response
);
626 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
633 * Callback for noop. Inform the v1 interface about the noop packet, and
634 * create and send a packet back to the client
636 * @param cookie the calling client
637 * @param header the command
638 * @param response_handler the response handler
639 * @return the result of the operation
641 static protocol_binary_response_status
642 noop_command_handler(const void *cookie
,
643 protocol_binary_request_header
*header
,
644 memcached_binary_protocol_raw_response_handler response_handler
)
646 memcached_protocol_client_st
*client
= (void*)cookie
;
647 if (client
->root
->callback
->interface
.v1
.noop
!= NULL
)
649 client
->root
->callback
->interface
.v1
.noop(cookie
);
652 protocol_binary_response_no_extras response
= {
655 .magic
= PROTOCOL_BINARY_RES
,
656 .opcode
= PROTOCOL_BINARY_CMD_NOOP
,
657 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
658 .opaque
= header
->request
.opaque
,
663 return response_handler(cookie
, header
, (void*)&response
);
667 * Callback for APPEND and APPENDQ
668 * @param cookie the calling client
669 * @param header the command
670 * @param response_handler not used
671 * @return the result of the operation
673 static protocol_binary_response_status
674 append_command_handler(const void *cookie
,
675 protocol_binary_request_header
*header
,
676 memcached_binary_protocol_raw_response_handler response_handler
)
678 (void)response_handler
;
679 protocol_binary_response_status rval
;
681 memcached_protocol_client_st
*client
= (void*)cookie
;
682 if (client
->root
->callback
->interface
.v1
.append
!= NULL
)
684 uint16_t keylen
= ntohs(header
->request
.keylen
);
685 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
;
686 char *key
= (void*)(header
+1);
687 char *data
= key
+keylen
;
688 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
691 rval
= client
->root
->callback
->interface
.v1
.append(cookie
, key
, keylen
,
694 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
695 header
->request
.opcode
== PROTOCOL_BINARY_CMD_APPEND
)
697 /* Send a positive request */
698 protocol_binary_response_no_extras response
= {
701 .magic
= PROTOCOL_BINARY_RES
,
702 .opcode
= PROTOCOL_BINARY_CMD_APPEND
,
703 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
704 .opaque
= header
->request
.opaque
,
705 .cas
= memcached_ntohll(result_cas
),
709 rval
= response_handler(cookie
, header
, (void*)&response
);
714 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
721 * Callback for PREPEND and PREPENDQ
722 * @param cookie the calling client
723 * @param header the command
724 * @param response_handler not used
725 * @return the result of the operation
727 static protocol_binary_response_status
728 prepend_command_handler(const void *cookie
,
729 protocol_binary_request_header
*header
,
730 memcached_binary_protocol_raw_response_handler response_handler
)
732 (void)response_handler
;
733 protocol_binary_response_status rval
;
735 memcached_protocol_client_st
*client
= (void*)cookie
;
736 if (client
->root
->callback
->interface
.v1
.prepend
!= NULL
)
738 uint16_t keylen
= ntohs(header
->request
.keylen
);
739 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
;
740 char *key
= (char*)(header
+ 1);
741 char *data
= key
+ keylen
;
742 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
744 rval
= client
->root
->callback
->interface
.v1
.prepend(cookie
, key
, keylen
,
747 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
748 header
->request
.opcode
== PROTOCOL_BINARY_CMD_PREPEND
)
750 /* Send a positive request */
751 protocol_binary_response_no_extras response
= {
754 .magic
= PROTOCOL_BINARY_RES
,
755 .opcode
= PROTOCOL_BINARY_CMD_PREPEND
,
756 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
757 .opaque
= header
->request
.opaque
,
758 .cas
= memcached_ntohll(result_cas
),
762 rval
= response_handler(cookie
, header
, (void*)&response
);
767 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
774 * Callback for QUIT and QUITQ. Notify the client and shut down the connection
775 * @param cookie the calling client
776 * @param header the command
777 * @param response_handler not used
778 * @return the result of the operation
780 static protocol_binary_response_status
781 quit_command_handler(const void *cookie
,
782 protocol_binary_request_header
*header
,
783 memcached_binary_protocol_raw_response_handler response_handler
)
785 memcached_protocol_client_st
*client
= (void*)cookie
;
786 if (client
->root
->callback
->interface
.v1
.quit
!= NULL
)
788 client
->root
->callback
->interface
.v1
.quit(cookie
);
791 protocol_binary_response_no_extras response
= {
794 .magic
= PROTOCOL_BINARY_RES
,
795 .opcode
= PROTOCOL_BINARY_CMD_QUIT
,
796 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
797 .opaque
= header
->request
.opaque
802 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_QUIT
)
804 response_handler(cookie
, header
, (void*)&response
);
807 /* I need a better way to signal to close the connection */
808 return PROTOCOL_BINARY_RESPONSE_EINTERNAL
;
812 * Callback for REPLACE and REPLACEQ
813 * @param cookie the calling client
814 * @param header the command
815 * @param response_handler not used
816 * @return the result of the operation
818 static protocol_binary_response_status
819 replace_command_handler(const void *cookie
,
820 protocol_binary_request_header
*header
,
821 memcached_binary_protocol_raw_response_handler response_handler
)
823 (void)response_handler
;
824 protocol_binary_response_status rval
;
826 memcached_protocol_client_st
*client
= (void*)cookie
;
827 if (client
->root
->callback
->interface
.v1
.replace
!= NULL
)
829 uint16_t keylen
= ntohs(header
->request
.keylen
);
830 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
831 protocol_binary_request_replace
*request
= (void*)header
;
832 uint32_t flags
= ntohl(request
->message
.body
.flags
);
833 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
834 char *key
= ((char*)header
) + sizeof(*header
) + 8;
835 char *data
= key
+ keylen
;
836 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
839 rval
= client
->root
->callback
->interface
.v1
.replace(cookie
, key
, keylen
,
840 data
, datalen
, flags
,
843 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
844 header
->request
.opcode
== PROTOCOL_BINARY_CMD_REPLACE
)
846 /* Send a positive request */
847 protocol_binary_response_no_extras response
= {
850 .magic
= PROTOCOL_BINARY_RES
,
851 .opcode
= PROTOCOL_BINARY_CMD_REPLACE
,
852 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
853 .opaque
= header
->request
.opaque
,
854 .cas
= memcached_ntohll(result_cas
),
858 rval
= response_handler(cookie
, header
, (void*)&response
);
863 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
870 * Callback for SET and SETQ
871 * @param cookie the calling client
872 * @param header the command
873 * @param response_handler not used
874 * @return the result of the operation
876 static protocol_binary_response_status
set_command_handler(const void *cookie
,
877 protocol_binary_request_header
*header
,
878 memcached_binary_protocol_raw_response_handler response_handler
)
880 (void)response_handler
;
881 protocol_binary_response_status rval
;
883 memcached_protocol_client_st
*client
= (void*)cookie
;
884 if (client
->root
->callback
->interface
.v1
.set
!= NULL
)
886 uint16_t keylen
= ntohs(header
->request
.keylen
);
887 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
888 protocol_binary_request_replace
*request
= (void*)header
;
889 uint32_t flags
= ntohl(request
->message
.body
.flags
);
890 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
891 char *key
= ((char*)header
) + sizeof(*header
) + 8;
892 char *data
= key
+ keylen
;
893 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
897 rval
= client
->root
->callback
->interface
.v1
.set(cookie
, key
, keylen
,
898 data
, datalen
, flags
,
899 timeout
, cas
, &result_cas
);
900 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
901 header
->request
.opcode
== PROTOCOL_BINARY_CMD_SET
)
903 /* Send a positive request */
904 protocol_binary_response_no_extras response
= {
907 .magic
= PROTOCOL_BINARY_RES
,
908 .opcode
= PROTOCOL_BINARY_CMD_SET
,
909 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
910 .opaque
= header
->request
.opaque
,
911 .cas
= memcached_ntohll(result_cas
),
915 rval
= response_handler(cookie
, header
, (void*)&response
);
920 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
928 * @param cookie the calling client
929 * @param header the command
930 * @param response_handler not used
931 * @return the result of the operation
933 static protocol_binary_response_status
934 stat_command_handler(const void *cookie
,
935 protocol_binary_request_header
*header
,
936 memcached_binary_protocol_raw_response_handler response_handler
)
938 (void)response_handler
;
939 protocol_binary_response_status rval
;
941 memcached_protocol_client_st
*client
= (void*)cookie
;
942 if (client
->root
->callback
->interface
.v1
.stat
!= NULL
)
944 uint16_t keylen
= ntohs(header
->request
.keylen
);
946 rval
= client
->root
->callback
->interface
.v1
.stat(cookie
,
949 stat_response_handler
);
953 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
960 * Callback for VERSION
961 * @param cookie the calling client
962 * @param header the command
963 * @param response_handler not used
964 * @return the result of the operation
966 static protocol_binary_response_status
967 version_command_handler(const void *cookie
,
968 protocol_binary_request_header
*header
,
969 memcached_binary_protocol_raw_response_handler response_handler
)
971 (void)response_handler
;
973 protocol_binary_response_status rval
;
975 memcached_protocol_client_st
*client
= (void*)cookie
;
976 if (client
->root
->callback
->interface
.v1
.version
!= NULL
)
978 rval
= client
->root
->callback
->interface
.v1
.version(cookie
,
979 version_response_handler
);
983 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
990 * The map to remap between the com codes and the v1 logical setting
992 static memcached_binary_protocol_command_handler comcode_v0_v1_remap
[256]= {
993 [PROTOCOL_BINARY_CMD_ADDQ
]= add_command_handler
,
994 [PROTOCOL_BINARY_CMD_ADD
]= add_command_handler
,
995 [PROTOCOL_BINARY_CMD_APPENDQ
]= append_command_handler
,
996 [PROTOCOL_BINARY_CMD_APPEND
]= append_command_handler
,
997 [PROTOCOL_BINARY_CMD_DECREMENTQ
]= decrement_command_handler
,
998 [PROTOCOL_BINARY_CMD_DECREMENT
]= decrement_command_handler
,
999 [PROTOCOL_BINARY_CMD_DELETEQ
]= delete_command_handler
,
1000 [PROTOCOL_BINARY_CMD_DELETE
]= delete_command_handler
,
1001 [PROTOCOL_BINARY_CMD_FLUSHQ
]= flush_command_handler
,
1002 [PROTOCOL_BINARY_CMD_FLUSH
]= flush_command_handler
,
1003 [PROTOCOL_BINARY_CMD_GETKQ
]= get_command_handler
,
1004 [PROTOCOL_BINARY_CMD_GETK
]= get_command_handler
,
1005 [PROTOCOL_BINARY_CMD_GETQ
]= get_command_handler
,
1006 [PROTOCOL_BINARY_CMD_GET
]= get_command_handler
,
1007 [PROTOCOL_BINARY_CMD_INCREMENTQ
]= increment_command_handler
,
1008 [PROTOCOL_BINARY_CMD_INCREMENT
]= increment_command_handler
,
1009 [PROTOCOL_BINARY_CMD_NOOP
]= noop_command_handler
,
1010 [PROTOCOL_BINARY_CMD_PREPENDQ
]= prepend_command_handler
,
1011 [PROTOCOL_BINARY_CMD_PREPEND
]= prepend_command_handler
,
1012 [PROTOCOL_BINARY_CMD_QUITQ
]= quit_command_handler
,
1013 [PROTOCOL_BINARY_CMD_QUIT
]= quit_command_handler
,
1014 [PROTOCOL_BINARY_CMD_REPLACEQ
]= replace_command_handler
,
1015 [PROTOCOL_BINARY_CMD_REPLACE
]= replace_command_handler
,
1016 [PROTOCOL_BINARY_CMD_SETQ
]= set_command_handler
,
1017 [PROTOCOL_BINARY_CMD_SET
]= set_command_handler
,
1018 [PROTOCOL_BINARY_CMD_STAT
]= stat_command_handler
,
1019 [PROTOCOL_BINARY_CMD_VERSION
]= version_command_handler
,
1023 * Try to execute a command. Fire the pre/post functions and the specialized
1024 * handler function if it's set. If not, the unknown probe should be fired
1026 * @param client the client connection to operate on
1027 * @param header the command to execute
1028 * @return true if success or false if a fatal error occured so that the
1029 * connection should be shut down.
1031 static protocol_binary_response_status
execute_command(memcached_protocol_client_st
*client
, protocol_binary_request_header
*header
)
1033 if (client
->root
->pedantic
&&
1034 memcached_binary_protocol_pedantic_check_request(header
))
1036 /* @todo return invalid command packet */
1039 /* we got all data available, execute the callback! */
1040 if (client
->root
->callback
->pre_execute
!= NULL
)
1042 client
->root
->callback
->pre_execute(client
, header
);
1045 protocol_binary_response_status rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
1046 uint8_t cc
= header
->request
.opcode
;
1048 if (client
->is_verbose
)
1053 switch (client
->root
->callback
->interface_version
)
1056 if (client
->root
->callback
->interface
.v0
.comcode
[cc
] != NULL
)
1058 rval
= client
->root
->callback
->interface
.v0
.comcode
[cc
](client
, header
, raw_response_handler
);
1063 if (comcode_v0_v1_remap
[cc
] != NULL
)
1065 rval
= comcode_v0_v1_remap
[cc
](client
, header
, raw_response_handler
);
1070 /* Unknown interface.
1071 * It should be impossible to get here so I'll just call abort
1072 * to avoid getting a compiler warning :-)
1078 if (rval
== PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
&&
1079 client
->root
->callback
->unknown
!= NULL
)
1081 rval
= client
->root
->callback
->unknown(client
, header
, raw_response_handler
);
1084 if (rval
!= PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
1085 rval
!= PROTOCOL_BINARY_RESPONSE_EINTERNAL
&&
1086 rval
!= PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED
)
1088 protocol_binary_response_no_extras response
= {
1091 .magic
= PROTOCOL_BINARY_RES
,
1093 .status
= htons(rval
),
1094 .opaque
= header
->request
.opaque
,
1098 rval
= raw_response_handler(client
, header
, (void*)&response
);
1101 if (client
->root
->callback
->post_execute
!= NULL
)
1103 client
->root
->callback
->post_execute(client
, header
);
1110 ** **********************************************************************
1111 ** "PROTOECTED" INTERFACE
1112 ** **********************************************************************
1114 memcached_protocol_event_t
memcached_binary_protocol_process_data(memcached_protocol_client_st
*client
, ssize_t
*length
, void **endptr
)
1116 /* try to parse all of the received packets */
1117 protocol_binary_request_header
*header
;
1118 header
= (void*)client
->root
->input_buffer
;
1119 if (header
->request
.magic
!= (uint8_t)PROTOCOL_BINARY_REQ
)
1121 client
->error
= EINVAL
;
1122 return MEMCACHED_PROTOCOL_ERROR_EVENT
;
1124 ssize_t len
= *length
;
1126 while (len
>= (ssize_t
)sizeof(*header
) &&
1127 (len
>= (ssize_t
)(sizeof(*header
) + ntohl(header
->request
.bodylen
))))
1129 /* I have the complete package */
1130 client
->current_command
= header
;
1131 protocol_binary_response_status rv
= execute_command(client
, header
);
1133 if (rv
== PROTOCOL_BINARY_RESPONSE_EINTERNAL
)
1136 *endptr
= (void*)header
;
1137 return MEMCACHED_PROTOCOL_ERROR_EVENT
;
1139 else if (rv
== PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED
)
1141 return MEMCACHED_PROTOCOL_PAUSE_EVENT
;
1144 ssize_t total
= (ssize_t
)(sizeof(*header
) + ntohl(header
->request
.bodylen
));
1148 intptr_t ptr
= (intptr_t)header
;
1157 memmove(client
->root
->input_buffer
, (void*)ptr
, (size_t)len
);
1158 header
= (void*)client
->root
->input_buffer
;
1162 *endptr
= (void*)header
;
1165 return MEMCACHED_PROTOCOL_READ_EVENT
;
1169 ** **********************************************************************
1171 ** **********************************************************************
1173 memcached_binary_protocol_callback_st
*memcached_binary_protocol_get_callbacks(memcached_protocol_st
*instance
)
1175 return instance
->callback
;
1178 void memcached_binary_protocol_set_callbacks(memcached_protocol_st
*instance
, memcached_binary_protocol_callback_st
*callback
)
1180 instance
->callback
= callback
;
1183 memcached_binary_protocol_raw_response_handler
memcached_binary_protocol_get_raw_response_handler(const void *cookie
)
1186 return raw_response_handler
;
1189 void memcached_binary_protocol_set_pedantic(memcached_protocol_st
*instance
, bool enable
)
1191 instance
->pedantic
= enable
;
1194 bool memcached_binary_protocol_get_pedantic(memcached_protocol_st
*instance
)
1196 return instance
->pedantic
;