2 +--------------------------------------------------------------------+
3 | libmemcached - C/C++ Client Library for memcached |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted under the terms of the BSD license. |
7 | You should have received a copy of the license in a bundled file |
8 | named LICENSE; in case you did not receive a copy you can review |
9 | the terms online at: https://opensource.org/licenses/BSD-3-Clause |
10 +--------------------------------------------------------------------+
11 | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ |
12 | Copyright (c) 2020 Michael Wallner <mike@php.net> |
13 +--------------------------------------------------------------------+
16 #include "libmemcachedprotocol/common.h"
19 #include <sys/types.h>
26 ** **********************************************************************
28 ** **********************************************************************
32 * Send a preformatted packet back to the client. If the connection is in
33 * pedantic mode, it will validate the packet and refuse to send it if it
34 * breaks the specification.
36 * @param cookie client identification
37 * @param request the original request packet
38 * @param response the packet to send
39 * @return The status of the operation
41 static protocol_binary_response_status
42 binary_raw_response_handler(const void *cookie
, protocol_binary_request_header
*request
,
43 protocol_binary_response_header
*response
) {
44 memcached_protocol_client_st
*client
= (void *) cookie
;
46 if (client
->root
->pedantic
47 && !memcached_binary_protocol_pedantic_check_response(request
, response
)) {
48 return PROTOCOL_BINARY_RESPONSE_EINVAL
;
51 if (client
->root
->drain(client
) == false) {
52 return PROTOCOL_BINARY_RESPONSE_EINTERNAL
;
55 size_t len
= sizeof(protocol_binary_response_header
) + htonl(response
->response
.bodylen
);
57 char *ptr
= (void *) response
;
59 if (client
->output
== NULL
) {
60 /* I can write directly to the socket.... */
62 size_t num_bytes
= len
- offset
;
63 ssize_t nw
= client
->root
->send(client
, client
->sock
, ptr
+ offset
, num_bytes
);
65 if (get_socket_errno() == EWOULDBLOCK
) {
67 } else if (get_socket_errno() != EINTR
) {
68 client
->error
= errno
;
69 return PROTOCOL_BINARY_RESPONSE_EINTERNAL
;
72 offset
+= (size_t) nw
;
74 } while (offset
< len
);
77 return client
->root
->spool(client
, ptr
, len
- offset
);
80 static void print_cmd(protocol_binary_command cmd
) {
82 case PROTOCOL_BINARY_CMD_GET
:
83 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GET\n", __FILE__
, __LINE__
);
85 case PROTOCOL_BINARY_CMD_SET
:
86 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SET\n", __FILE__
, __LINE__
);
88 case PROTOCOL_BINARY_CMD_ADD
:
89 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_ADD\n", __FILE__
, __LINE__
);
91 case PROTOCOL_BINARY_CMD_REPLACE
:
92 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_REPLACE\n", __FILE__
, __LINE__
);
94 case PROTOCOL_BINARY_CMD_DELETE
:
95 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DELETE\n", __FILE__
, __LINE__
);
97 case PROTOCOL_BINARY_CMD_INCREMENT
:
98 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_INCREMENT\n", __FILE__
, __LINE__
);
100 case PROTOCOL_BINARY_CMD_DECREMENT
:
101 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DECREMENT\n", __FILE__
, __LINE__
);
103 case PROTOCOL_BINARY_CMD_QUIT
:
104 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_QUIT\n", __FILE__
, __LINE__
);
106 case PROTOCOL_BINARY_CMD_FLUSH
:
107 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_FLUSH\n", __FILE__
, __LINE__
);
109 case PROTOCOL_BINARY_CMD_GETQ
:
110 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GETQ\n", __FILE__
, __LINE__
);
112 case PROTOCOL_BINARY_CMD_NOOP
:
113 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_NOOP\n", __FILE__
, __LINE__
);
115 case PROTOCOL_BINARY_CMD_VERSION
:
116 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_VERSION\n", __FILE__
, __LINE__
);
118 case PROTOCOL_BINARY_CMD_GETK
:
119 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GETK\n", __FILE__
, __LINE__
);
121 case PROTOCOL_BINARY_CMD_GETKQ
:
122 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GETKQ\n", __FILE__
, __LINE__
);
124 case PROTOCOL_BINARY_CMD_APPEND
:
125 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_APPEND\n", __FILE__
, __LINE__
);
127 case PROTOCOL_BINARY_CMD_PREPEND
:
128 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_PREPEND\n", __FILE__
, __LINE__
);
130 case PROTOCOL_BINARY_CMD_STAT
:
131 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_STAT\n", __FILE__
, __LINE__
);
133 case PROTOCOL_BINARY_CMD_SETQ
:
134 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SETQ\n", __FILE__
, __LINE__
);
136 case PROTOCOL_BINARY_CMD_ADDQ
:
137 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_ADDQ\n", __FILE__
, __LINE__
);
139 case PROTOCOL_BINARY_CMD_REPLACEQ
:
140 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_REPLACEQ\n", __FILE__
, __LINE__
);
142 case PROTOCOL_BINARY_CMD_DELETEQ
:
143 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DELETEQ\n", __FILE__
, __LINE__
);
145 case PROTOCOL_BINARY_CMD_INCREMENTQ
:
146 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_INCREMENTQ\n", __FILE__
, __LINE__
);
148 case PROTOCOL_BINARY_CMD_DECREMENTQ
:
149 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DECREMENTQ\n", __FILE__
, __LINE__
);
151 case PROTOCOL_BINARY_CMD_QUITQ
:
152 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_QUITQ\n", __FILE__
, __LINE__
);
154 case PROTOCOL_BINARY_CMD_FLUSHQ
:
155 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_FLUSHQ\n", __FILE__
, __LINE__
);
157 case PROTOCOL_BINARY_CMD_APPENDQ
:
158 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_APPENDQ\n", __FILE__
, __LINE__
);
160 case PROTOCOL_BINARY_CMD_PREPENDQ
:
161 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_PREPENDQ\n", __FILE__
, __LINE__
);
163 case PROTOCOL_BINARY_CMD_VERBOSITY
:
164 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_VERBOSITY\n", __FILE__
, __LINE__
);
166 case PROTOCOL_BINARY_CMD_TOUCH
:
167 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TOUCH\n", __FILE__
, __LINE__
);
169 case PROTOCOL_BINARY_CMD_GAT
:
170 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GAT\n", __FILE__
, __LINE__
);
172 case PROTOCOL_BINARY_CMD_GATQ
:
173 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GATQ\n", __FILE__
, __LINE__
);
175 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
176 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SASL_LIST_MECHS\n", __FILE__
, __LINE__
);
178 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
179 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SASL_AUTH\n", __FILE__
, __LINE__
);
181 case PROTOCOL_BINARY_CMD_SASL_STEP
:
182 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SASL_STEP\n", __FILE__
, __LINE__
);
184 case PROTOCOL_BINARY_CMD_RGET
:
185 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RGET\n", __FILE__
, __LINE__
);
187 case PROTOCOL_BINARY_CMD_RSET
:
188 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RSET\n", __FILE__
, __LINE__
);
190 case PROTOCOL_BINARY_CMD_RSETQ
:
191 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RSETQ\n", __FILE__
, __LINE__
);
193 case PROTOCOL_BINARY_CMD_RAPPEND
:
194 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RAPPEND\n", __FILE__
, __LINE__
);
196 case PROTOCOL_BINARY_CMD_RAPPENDQ
:
197 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RAPPENDQ\n", __FILE__
, __LINE__
);
199 case PROTOCOL_BINARY_CMD_RPREPEND
:
200 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RPREPEND\n", __FILE__
, __LINE__
);
202 case PROTOCOL_BINARY_CMD_RPREPENDQ
:
203 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RPREPENDQ\n", __FILE__
, __LINE__
);
205 case PROTOCOL_BINARY_CMD_RDELETE
:
206 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDELETE\n", __FILE__
, __LINE__
);
208 case PROTOCOL_BINARY_CMD_RDELETEQ
:
209 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDELETEQ\n", __FILE__
, __LINE__
);
211 case PROTOCOL_BINARY_CMD_RINCR
:
212 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RINCR\n", __FILE__
, __LINE__
);
214 case PROTOCOL_BINARY_CMD_RINCRQ
:
215 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RINCRQ\n", __FILE__
, __LINE__
);
217 case PROTOCOL_BINARY_CMD_RDECR
:
218 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDECR\n", __FILE__
, __LINE__
);
220 case PROTOCOL_BINARY_CMD_RDECRQ
:
221 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDECRQ\n", __FILE__
, __LINE__
);
223 case PROTOCOL_BINARY_CMD_SET_VBUCKET
:
224 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SET_VBUCKET\n", __FILE__
, __LINE__
);
226 case PROTOCOL_BINARY_CMD_GET_VBUCKET
:
227 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GET_VBUCKET\n", __FILE__
, __LINE__
);
229 case PROTOCOL_BINARY_CMD_DEL_VBUCKET
:
230 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DEL_VBUCKET\n", __FILE__
, __LINE__
);
232 case PROTOCOL_BINARY_CMD_TAP_CONNECT
:
233 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_CONNECT\n", __FILE__
, __LINE__
);
235 case PROTOCOL_BINARY_CMD_TAP_MUTATION
:
236 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_MUTATION\n", __FILE__
, __LINE__
);
238 case PROTOCOL_BINARY_CMD_TAP_DELETE
:
239 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_DELETE\n", __FILE__
, __LINE__
);
241 case PROTOCOL_BINARY_CMD_TAP_FLUSH
:
242 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_FLUSH\n", __FILE__
, __LINE__
);
244 case PROTOCOL_BINARY_CMD_TAP_OPAQUE
:
245 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_OPAQUE\n", __FILE__
, __LINE__
);
247 case PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET
:
248 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET\n", __FILE__
, __LINE__
);
250 case PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START
:
251 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START\n", __FILE__
, __LINE__
);
253 case PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END
:
254 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END\n", __FILE__
, __LINE__
);
256 case PROTOCOL_BINARY_CMD_LAST_RESERVED
:
257 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_LAST_RESERVED\n", __FILE__
, __LINE__
);
259 case PROTOCOL_BINARY_CMD_GATK
:
260 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GATK\n", __FILE__
, __LINE__
);
262 case PROTOCOL_BINARY_CMD_GATKQ
:
263 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GATKQ\n", __FILE__
, __LINE__
);
265 case PROTOCOL_BINARY_CMD_SCRUB
:
266 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SCRUB\n", __FILE__
, __LINE__
);
274 * Version 0 of the interface is really low level and protocol specific,
275 * while the version 1 of the interface is more API focused. We need a
276 * way to translate between the command codes on the wire and the
277 * application level interface in V1, so let's just use the V0 of the
278 * interface as a map instead of creating a huuuge switch :-)
282 * Callback for the GET/GETQ/GETK and GETKQ responses
283 * @param cookie client identifier
284 * @param key the key for the item
285 * @param keylen the length of the key
286 * @param body the length of the body
287 * @param bodylen the length of the body
288 * @param flags the flags for the item
289 * @param cas the CAS id for the item
291 static protocol_binary_response_status
get_response_handler(const void *cookie
, const void *key
,
292 uint16_t keylen
, const void *body
,
293 uint32_t bodylen
, uint32_t flags
,
295 memcached_protocol_client_st
*client
= (void *) cookie
;
296 uint8_t opcode
= client
->current_command
->request
.opcode
;
298 if (opcode
== PROTOCOL_BINARY_CMD_GET
|| opcode
== PROTOCOL_BINARY_CMD_GETQ
) {
302 protocol_binary_response_get response
= {
303 .message
.header
.response
=
305 .magic
= PROTOCOL_BINARY_RES
,
307 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
308 .opaque
= client
->current_command
->request
.opaque
,
309 .cas
= memcached_htonll(cas
),
310 .keylen
= htons(keylen
),
312 .bodylen
= htonl(bodylen
+ keylen
+ 4),
316 response
.message
.body
.flags
= htonl(flags
);
318 protocol_binary_response_status rval
;
319 const protocol_binary_response_status success
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
320 if ((rval
= client
->root
->spool(client
, response
.bytes
, sizeof(response
.bytes
))) != success
321 || (rval
= client
->root
->spool(client
, key
, keylen
)) != success
322 || (rval
= client
->root
->spool(client
, body
, bodylen
)) != success
)
327 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
331 * Callback for the STAT responses
332 * @param cookie client identifier
333 * @param key the key for the item
334 * @param keylen the length of the key
335 * @param body the length of the body
336 * @param bodylen the length of the body
338 static protocol_binary_response_status
stat_response_handler(const void *cookie
, const void *key
,
339 uint16_t keylen
, const void *body
,
341 memcached_protocol_client_st
*client
= (void *) cookie
;
343 protocol_binary_response_no_extras response
= {
344 .message
.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
345 .opcode
= client
->current_command
->request
.opcode
,
346 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
347 .opaque
= client
->current_command
->request
.opaque
,
348 .keylen
= htons(keylen
),
349 .bodylen
= htonl(bodylen
+ keylen
),
353 protocol_binary_response_status rval
;
354 const protocol_binary_response_status success
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
355 if ((rval
= client
->root
->spool(client
, response
.bytes
, sizeof(response
.bytes
))) != success
356 || (rval
= client
->root
->spool(client
, key
, keylen
)) != success
357 || (rval
= client
->root
->spool(client
, body
, bodylen
)) != success
)
362 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
366 * Callback for the VERSION responses
367 * @param cookie client identifier
368 * @param text the length of the body
369 * @param textlen the length of the body
371 static protocol_binary_response_status
372 version_response_handler(const void *cookie
, const void *text
, uint32_t textlen
) {
373 memcached_protocol_client_st
*client
= (void *) cookie
;
375 protocol_binary_response_no_extras response
= {
376 .message
.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
377 .opcode
= client
->current_command
->request
.opcode
,
378 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
379 .opaque
= client
->current_command
->request
.opaque
,
380 .bodylen
= htonl(textlen
),
384 protocol_binary_response_status rval
;
385 const protocol_binary_response_status success
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
386 if ((rval
= client
->root
->spool(client
, response
.bytes
, sizeof(response
.bytes
))) != success
387 || (rval
= client
->root
->spool(client
, text
, textlen
)) != success
)
392 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
396 * Callback for ADD and ADDQ
397 * @param cookie the calling client
398 * @param header the add/addq command
399 * @param response_handler not used
400 * @return the result of the operation
402 static protocol_binary_response_status
403 add_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
404 memcached_binary_protocol_raw_response_handler response_handler
) {
405 protocol_binary_response_status rval
;
407 memcached_protocol_client_st
*client
= (void *) cookie
;
408 if (client
->root
->callback
->interface
.v1
.add
) {
409 uint16_t keylen
= ntohs(header
->request
.keylen
);
410 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
411 protocol_binary_request_add
*request
= (void *) header
;
412 uint32_t flags
= ntohl(request
->message
.body
.flags
);
413 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
414 char *key
= ((char *) header
) + sizeof(*header
) + 8;
415 char *data
= key
+ keylen
;
418 rval
= client
->root
->callback
->interface
.v1
.add(cookie
, key
, keylen
, data
, datalen
, flags
,
421 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
422 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_ADD
) {
423 /* Send a positive request */
424 protocol_binary_response_no_extras response
= {
425 .message
= {.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
426 .opcode
= PROTOCOL_BINARY_CMD_ADD
,
427 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
428 .opaque
= header
->request
.opaque
,
429 .cas
= memcached_ntohll(cas
)}}};
430 rval
= response_handler(cookie
, header
, (void *) &response
);
433 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
440 * Callback for DECREMENT and DECREMENTQ
441 * @param cookie the calling client
442 * @param header the command
443 * @param response_handler not used
444 * @return the result of the operation
446 static protocol_binary_response_status
447 decrement_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
448 memcached_binary_protocol_raw_response_handler response_handler
) {
449 (void) response_handler
;
450 protocol_binary_response_status rval
;
452 memcached_protocol_client_st
*client
= (void *) cookie
;
453 if (client
->root
->callback
->interface
.v1
.decrement
) {
454 uint16_t keylen
= ntohs(header
->request
.keylen
);
455 protocol_binary_request_decr
*request
= (void *) header
;
456 uint64_t init
= memcached_ntohll(request
->message
.body
.initial
);
457 uint64_t delta
= memcached_ntohll(request
->message
.body
.delta
);
458 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
459 void *key
= request
->bytes
+ sizeof(request
->bytes
);
463 rval
= client
->root
->callback
->interface
.v1
.decrement(cookie
, key
, keylen
, delta
, init
, timeout
,
465 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
466 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_DECREMENT
)
468 /* Send a positive request */
469 protocol_binary_response_decr response
= {
470 .message
= {.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
471 .opcode
= PROTOCOL_BINARY_CMD_DECREMENT
,
472 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
473 .opaque
= header
->request
.opaque
,
474 .cas
= memcached_ntohll(cas
),
475 .bodylen
= htonl(8)},
476 .body
.value
= memcached_htonll(result
)}};
477 rval
= response_handler(cookie
, header
, (void *) &response
);
480 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
487 * Callback for DELETE and DELETEQ
488 * @param cookie the calling client
489 * @param header the command
490 * @param response_handler not used
491 * @return the result of the operation
493 static protocol_binary_response_status
494 delete_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
495 memcached_binary_protocol_raw_response_handler response_handler
) {
496 (void) response_handler
;
497 protocol_binary_response_status rval
;
499 memcached_protocol_client_st
*client
= (void *) cookie
;
500 if (client
->root
->callback
->interface
.v1
.delete_object
) {
501 uint16_t keylen
= ntohs(header
->request
.keylen
);
502 void *key
= (header
+ 1);
503 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
504 rval
= client
->root
->callback
->interface
.v1
.delete_object(cookie
, key
, keylen
, cas
);
505 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
506 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_DELETE
)
508 /* Send a positive request */
509 protocol_binary_response_no_extras response
= {
510 .message
= {.header
.response
= {
511 .magic
= PROTOCOL_BINARY_RES
,
512 .opcode
= PROTOCOL_BINARY_CMD_DELETE
,
513 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
514 .opaque
= header
->request
.opaque
,
516 rval
= response_handler(cookie
, header
, (void *) &response
);
519 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
526 * Callback for FLUSH and FLUSHQ
527 * @param cookie the calling client
528 * @param header the command
529 * @param response_handler not used
530 * @return the result of the operation
532 static protocol_binary_response_status
533 flush_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
534 memcached_binary_protocol_raw_response_handler response_handler
) {
535 (void) response_handler
;
536 protocol_binary_response_status rval
;
538 memcached_protocol_client_st
*client
= (void *) cookie
;
539 if (client
->root
->callback
->interface
.v1
.flush_object
) {
540 protocol_binary_request_flush
*flush_object
= (void *) header
;
541 uint32_t timeout
= 0;
542 if (htonl(header
->request
.bodylen
) == 4) {
543 timeout
= ntohl(flush_object
->message
.body
.expiration
);
546 rval
= client
->root
->callback
->interface
.v1
.flush_object(cookie
, timeout
);
547 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
548 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_FLUSH
) {
549 /* Send a positive request */
550 protocol_binary_response_no_extras response
= {
551 .message
= {.header
.response
= {
552 .magic
= PROTOCOL_BINARY_RES
,
553 .opcode
= PROTOCOL_BINARY_CMD_FLUSH
,
554 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
555 .opaque
= header
->request
.opaque
,
557 rval
= response_handler(cookie
, header
, (void *) &response
);
560 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
567 * Callback for GET, GETK, GETQ, GETKQ
568 * @param cookie the calling client
569 * @param header the command
570 * @param response_handler not used
571 * @return the result of the operation
573 static protocol_binary_response_status
574 get_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
575 memcached_binary_protocol_raw_response_handler response_handler
) {
576 (void) response_handler
;
577 protocol_binary_response_status rval
;
579 memcached_protocol_client_st
*client
= (void *) cookie
;
580 if (client
->root
->callback
->interface
.v1
.get
) {
581 uint16_t keylen
= ntohs(header
->request
.keylen
);
582 void *key
= (header
+ 1);
583 rval
= client
->root
->callback
->interface
.v1
.get(cookie
, key
, keylen
, get_response_handler
);
585 if (rval
== PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
586 && (header
->request
.opcode
== PROTOCOL_BINARY_CMD_GETQ
587 || header
->request
.opcode
== PROTOCOL_BINARY_CMD_GETKQ
))
589 /* Quiet commands shouldn't respond on cache misses */
590 rval
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
593 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
600 * Callback for INCREMENT and INCREMENTQ
601 * @param cookie the calling client
602 * @param header the command
603 * @param response_handler not used
604 * @return the result of the operation
606 static protocol_binary_response_status
607 increment_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
608 memcached_binary_protocol_raw_response_handler response_handler
) {
609 (void) response_handler
;
610 protocol_binary_response_status rval
;
612 memcached_protocol_client_st
*client
= (void *) cookie
;
613 if (client
->root
->callback
->interface
.v1
.increment
) {
614 uint16_t keylen
= ntohs(header
->request
.keylen
);
615 protocol_binary_request_incr
*request
= (void *) header
;
616 uint64_t init
= memcached_ntohll(request
->message
.body
.initial
);
617 uint64_t delta
= memcached_ntohll(request
->message
.body
.delta
);
618 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
619 void *key
= request
->bytes
+ sizeof(request
->bytes
);
623 rval
= client
->root
->callback
->interface
.v1
.increment(cookie
, key
, keylen
, delta
, init
, timeout
,
625 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
626 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_INCREMENT
)
628 /* Send a positive request */
629 protocol_binary_response_incr response
= {
630 .message
= {.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
631 .opcode
= PROTOCOL_BINARY_CMD_INCREMENT
,
632 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
633 .opaque
= header
->request
.opaque
,
634 .cas
= memcached_ntohll(cas
),
635 .bodylen
= htonl(8)},
636 .body
.value
= memcached_htonll(result
)}};
638 rval
= response_handler(cookie
, header
, (void *) &response
);
641 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
648 * Callback for noop. Inform the v1 interface about the noop packet, and
649 * create and send a packet back to the client
651 * @param cookie the calling client
652 * @param header the command
653 * @param response_handler the response handler
654 * @return the result of the operation
656 static protocol_binary_response_status
657 noop_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
658 memcached_binary_protocol_raw_response_handler response_handler
) {
659 memcached_protocol_client_st
*client
= (void *) cookie
;
660 if (client
->root
->callback
->interface
.v1
.noop
) {
661 client
->root
->callback
->interface
.v1
.noop(cookie
);
664 protocol_binary_response_no_extras response
= {
665 .message
= {.header
.response
= {
666 .magic
= PROTOCOL_BINARY_RES
,
667 .opcode
= PROTOCOL_BINARY_CMD_NOOP
,
668 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
669 .opaque
= header
->request
.opaque
,
672 return response_handler(cookie
, header
, (void *) &response
);
676 * Callback for APPEND and APPENDQ
677 * @param cookie the calling client
678 * @param header the command
679 * @param response_handler not used
680 * @return the result of the operation
682 static protocol_binary_response_status
683 append_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
684 memcached_binary_protocol_raw_response_handler response_handler
) {
685 (void) response_handler
;
686 protocol_binary_response_status rval
;
688 memcached_protocol_client_st
*client
= (void *) cookie
;
689 if (client
->root
->callback
->interface
.v1
.append
) {
690 uint16_t keylen
= ntohs(header
->request
.keylen
);
691 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
;
692 char *key
= (void *) (header
+ 1);
693 char *data
= key
+ keylen
;
694 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
697 rval
= client
->root
->callback
->interface
.v1
.append(cookie
, key
, keylen
, data
, datalen
, cas
,
699 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
700 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_APPEND
)
702 /* Send a positive request */
703 protocol_binary_response_no_extras response
= {
707 .magic
= PROTOCOL_BINARY_RES
,
708 .opcode
= PROTOCOL_BINARY_CMD_APPEND
,
709 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
710 .opaque
= header
->request
.opaque
,
711 .cas
= memcached_ntohll(result_cas
),
714 rval
= response_handler(cookie
, header
, (void *) &response
);
717 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
724 * Callback for PREPEND and PREPENDQ
725 * @param cookie the calling client
726 * @param header the command
727 * @param response_handler not used
728 * @return the result of the operation
730 static protocol_binary_response_status
731 prepend_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
732 memcached_binary_protocol_raw_response_handler response_handler
) {
733 (void) response_handler
;
734 protocol_binary_response_status rval
;
736 memcached_protocol_client_st
*client
= (void *) cookie
;
737 if (client
->root
->callback
->interface
.v1
.prepend
) {
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
, data
, datalen
, cas
,
746 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
747 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_PREPEND
)
749 /* Send a positive request */
750 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
),
761 rval
= response_handler(cookie
, header
, (void *) &response
);
764 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
771 * Callback for QUIT and QUITQ. Notify the client and shut down the connection
772 * @param cookie the calling client
773 * @param header the command
774 * @param response_handler not used
775 * @return the result of the operation
777 static protocol_binary_response_status
778 quit_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
779 memcached_binary_protocol_raw_response_handler response_handler
) {
780 memcached_protocol_client_st
*client
= (void *) cookie
;
781 if (client
->root
->callback
->interface
.v1
.quit
) {
782 client
->root
->callback
->interface
.v1
.quit(cookie
);
785 protocol_binary_response_no_extras response
= {
786 .message
= {.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
787 .opcode
= PROTOCOL_BINARY_CMD_QUIT
,
788 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
789 .opaque
= header
->request
.opaque
}}};
791 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_QUIT
) {
792 response_handler(cookie
, header
, (void *) &response
);
795 /* I need a better way to signal to close the connection */
796 return PROTOCOL_BINARY_RESPONSE_EINTERNAL
;
800 * Callback for REPLACE and REPLACEQ
801 * @param cookie the calling client
802 * @param header the command
803 * @param response_handler not used
804 * @return the result of the operation
806 static protocol_binary_response_status
807 replace_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
808 memcached_binary_protocol_raw_response_handler response_handler
) {
809 (void) response_handler
;
810 protocol_binary_response_status rval
;
812 memcached_protocol_client_st
*client
= (void *) cookie
;
813 if (client
->root
->callback
->interface
.v1
.replace
) {
814 uint16_t keylen
= ntohs(header
->request
.keylen
);
815 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
816 protocol_binary_request_replace
*request
= (void *) header
;
817 uint32_t flags
= ntohl(request
->message
.body
.flags
);
818 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
819 char *key
= ((char *) header
) + sizeof(*header
) + 8;
820 char *data
= key
+ keylen
;
821 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
824 rval
= client
->root
->callback
->interface
.v1
.replace(cookie
, key
, keylen
, data
, datalen
, flags
,
825 timeout
, cas
, &result_cas
);
826 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
827 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_REPLACE
)
829 /* Send a positive request */
830 protocol_binary_response_no_extras response
= {
834 .magic
= PROTOCOL_BINARY_RES
,
835 .opcode
= PROTOCOL_BINARY_CMD_REPLACE
,
836 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
837 .opaque
= header
->request
.opaque
,
838 .cas
= memcached_ntohll(result_cas
),
841 rval
= response_handler(cookie
, header
, (void *) &response
);
844 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
851 * Callback for SET and SETQ
852 * @param cookie the calling client
853 * @param header the command
854 * @param response_handler not used
855 * @return the result of the operation
857 static protocol_binary_response_status
858 set_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
859 memcached_binary_protocol_raw_response_handler response_handler
) {
860 (void) response_handler
;
861 protocol_binary_response_status rval
;
863 memcached_protocol_client_st
*client
= (void *) cookie
;
864 if (client
->root
->callback
->interface
.v1
.set
) {
865 uint16_t keylen
= ntohs(header
->request
.keylen
);
866 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
867 protocol_binary_request_replace
*request
= (void *) header
;
868 uint32_t flags
= ntohl(request
->message
.body
.flags
);
869 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
870 char *key
= ((char *) header
) + sizeof(*header
) + 8;
871 char *data
= key
+ keylen
;
872 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
875 rval
= client
->root
->callback
->interface
.v1
.set(cookie
, key
, keylen
, data
, datalen
, flags
,
876 timeout
, cas
, &result_cas
);
877 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
878 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_SET
) {
879 /* Send a positive request */
880 protocol_binary_response_no_extras response
= {
884 .magic
= PROTOCOL_BINARY_RES
,
885 .opcode
= PROTOCOL_BINARY_CMD_SET
,
886 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
887 .opaque
= header
->request
.opaque
,
888 .cas
= memcached_ntohll(result_cas
),
891 rval
= response_handler(cookie
, header
, (void *) &response
);
894 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
902 * @param cookie the calling client
903 * @param header the command
904 * @param response_handler not used
905 * @return the result of the operation
907 static protocol_binary_response_status
908 stat_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
909 memcached_binary_protocol_raw_response_handler response_handler
) {
910 (void) response_handler
;
911 protocol_binary_response_status rval
;
913 memcached_protocol_client_st
*client
= (void *) cookie
;
914 if (client
->root
->callback
->interface
.v1
.stat
) {
915 uint16_t keylen
= ntohs(header
->request
.keylen
);
917 rval
= client
->root
->callback
->interface
.v1
.stat(cookie
, (void *) (header
+ 1), keylen
,
918 stat_response_handler
);
920 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
927 * Callback for VERSION
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 version_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
935 memcached_binary_protocol_raw_response_handler response_handler
) {
936 (void) response_handler
;
938 protocol_binary_response_status rval
;
940 memcached_protocol_client_st
*client
= (void *) cookie
;
941 if (client
->root
->callback
->interface
.v1
.version
) {
942 rval
= client
->root
->callback
->interface
.v1
.version(cookie
, version_response_handler
);
944 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
951 * The map to remap between the com codes and the v1 logical setting
953 static memcached_binary_protocol_command_handler comcode_v0_v1_remap
[256] = {
954 [PROTOCOL_BINARY_CMD_ADDQ
] = add_command_handler
,
955 [PROTOCOL_BINARY_CMD_ADD
] = add_command_handler
,
956 [PROTOCOL_BINARY_CMD_APPENDQ
] = append_command_handler
,
957 [PROTOCOL_BINARY_CMD_APPEND
] = append_command_handler
,
958 [PROTOCOL_BINARY_CMD_DECREMENTQ
] = decrement_command_handler
,
959 [PROTOCOL_BINARY_CMD_DECREMENT
] = decrement_command_handler
,
960 [PROTOCOL_BINARY_CMD_DELETEQ
] = delete_command_handler
,
961 [PROTOCOL_BINARY_CMD_DELETE
] = delete_command_handler
,
962 [PROTOCOL_BINARY_CMD_FLUSHQ
] = flush_command_handler
,
963 [PROTOCOL_BINARY_CMD_FLUSH
] = flush_command_handler
,
964 [PROTOCOL_BINARY_CMD_GETKQ
] = get_command_handler
,
965 [PROTOCOL_BINARY_CMD_GETK
] = get_command_handler
,
966 [PROTOCOL_BINARY_CMD_GETQ
] = get_command_handler
,
967 [PROTOCOL_BINARY_CMD_GET
] = get_command_handler
,
968 [PROTOCOL_BINARY_CMD_INCREMENTQ
] = increment_command_handler
,
969 [PROTOCOL_BINARY_CMD_INCREMENT
] = increment_command_handler
,
970 [PROTOCOL_BINARY_CMD_NOOP
] = noop_command_handler
,
971 [PROTOCOL_BINARY_CMD_PREPENDQ
] = prepend_command_handler
,
972 [PROTOCOL_BINARY_CMD_PREPEND
] = prepend_command_handler
,
973 [PROTOCOL_BINARY_CMD_QUITQ
] = quit_command_handler
,
974 [PROTOCOL_BINARY_CMD_QUIT
] = quit_command_handler
,
975 [PROTOCOL_BINARY_CMD_REPLACEQ
] = replace_command_handler
,
976 [PROTOCOL_BINARY_CMD_REPLACE
] = replace_command_handler
,
977 [PROTOCOL_BINARY_CMD_SETQ
] = set_command_handler
,
978 [PROTOCOL_BINARY_CMD_SET
] = set_command_handler
,
979 [PROTOCOL_BINARY_CMD_STAT
] = stat_command_handler
,
980 [PROTOCOL_BINARY_CMD_VERSION
] = version_command_handler
,
984 * Try to execute a command. Fire the pre/post functions and the specialized
985 * handler function if it's set. If not, the unknown probe should be fired
987 * @param client the client connection to operate on
988 * @param header the command to execute
989 * @return true if success or false if a fatal error occured so that the
990 * connection should be shut down.
992 static protocol_binary_response_status
execute_command(memcached_protocol_client_st
*client
,
993 protocol_binary_request_header
*header
) {
994 if (client
->root
->pedantic
&& memcached_binary_protocol_pedantic_check_request(header
)) {
995 /* @todo return invalid command packet */
998 /* we got all data available, execute the callback! */
999 if (client
->root
->callback
->pre_execute
) {
1000 client
->root
->callback
->pre_execute(client
, header
);
1003 protocol_binary_response_status rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
1004 uint8_t cc
= header
->request
.opcode
;
1006 if (client
->is_verbose
) {
1010 switch (client
->root
->callback
->interface_version
) {
1012 if (client
->root
->callback
->interface
.v0
.comcode
[cc
]) {
1013 rval
= client
->root
->callback
->interface
.v0
.comcode
[cc
](client
, header
,
1014 binary_raw_response_handler
);
1019 if (comcode_v0_v1_remap
[cc
]) {
1020 rval
= comcode_v0_v1_remap
[cc
](client
, header
, binary_raw_response_handler
);
1025 /* Unknown interface.
1026 * It should be impossible to get here so I'll just call abort
1027 * to avoid getting a compiler warning :-)
1032 if (rval
== PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
&& client
->root
->callback
->unknown
) {
1033 rval
= client
->root
->callback
->unknown(client
, header
, binary_raw_response_handler
);
1036 if (rval
!= PROTOCOL_BINARY_RESPONSE_SUCCESS
&& rval
!= PROTOCOL_BINARY_RESPONSE_EINTERNAL
1037 && rval
!= PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED
)
1039 protocol_binary_response_no_extras response
= {.message
= {
1042 .magic
= PROTOCOL_BINARY_RES
,
1044 .status
= htons(rval
),
1045 .opaque
= header
->request
.opaque
,
1048 rval
= binary_raw_response_handler(client
, header
, (void *) &response
);
1051 if (client
->root
->callback
->post_execute
) {
1052 client
->root
->callback
->post_execute(client
, header
);
1059 ** **********************************************************************
1060 ** "PROTOECTED" INTERFACE
1061 ** **********************************************************************
1063 memcached_protocol_event_t
1064 memcached_binary_protocol_process_data(memcached_protocol_client_st
*client
, ssize_t
*length
,
1066 /* try to parse all of the received packets */
1067 protocol_binary_request_header
*header
;
1068 header
= (void *) client
->root
->input_buffer
;
1069 if (header
->request
.magic
!= (uint8_t) PROTOCOL_BINARY_REQ
) {
1070 client
->error
= EINVAL
;
1071 return MEMCACHED_PROTOCOL_ERROR_EVENT
;
1073 ssize_t len
= *length
;
1075 while (len
>= (ssize_t
) sizeof(*header
)
1076 && (len
>= (ssize_t
)(sizeof(*header
) + ntohl(header
->request
.bodylen
))))
1078 /* I have the complete package */
1079 client
->current_command
= header
;
1080 protocol_binary_response_status rv
= execute_command(client
, header
);
1082 if (rv
== PROTOCOL_BINARY_RESPONSE_EINTERNAL
) {
1084 *endptr
= (void *) header
;
1085 return MEMCACHED_PROTOCOL_ERROR_EVENT
;
1086 } else if (rv
== PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED
) {
1087 return MEMCACHED_PROTOCOL_PAUSE_EVENT
;
1090 ssize_t total
= (ssize_t
)(sizeof(*header
) + ntohl(header
->request
.bodylen
));
1093 intptr_t ptr
= (intptr_t) header
;
1095 if ((ptr
% 8) == 0) {
1096 header
= (void *) ptr
;
1099 memmove(client
->root
->input_buffer
, (void *) ptr
, (size_t) len
);
1100 header
= (void *) client
->root
->input_buffer
;
1104 *endptr
= (void *) header
;
1107 return MEMCACHED_PROTOCOL_READ_EVENT
;
1111 ** **********************************************************************
1113 ** **********************************************************************
1115 memcached_binary_protocol_callback_st
*
1116 memcached_binary_protocol_get_callbacks(memcached_protocol_st
*instance
) {
1117 return instance
->callback
;
1120 void memcached_binary_protocol_set_callbacks(memcached_protocol_st
*instance
,
1121 memcached_binary_protocol_callback_st
*callback
) {
1122 instance
->callback
= callback
;
1125 memcached_binary_protocol_raw_response_handler
1126 memcached_binary_protocol_get_raw_response_handler(const void *cookie
) {
1128 return binary_raw_response_handler
;
1131 void memcached_binary_protocol_set_pedantic(memcached_protocol_st
*instance
, bool enable
) {
1132 instance
->pedantic
= enable
;
1135 bool memcached_binary_protocol_get_pedantic(memcached_protocol_st
*instance
) {
1136 return instance
->pedantic
;