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"
17 #include "p9y/socket.hpp"
20 #include <sys/types.h>
27 ** **********************************************************************
29 ** **********************************************************************
33 * Send a preformatted packet back to the client. If the connection is in
34 * pedantic mode, it will validate the packet and refuse to send it if it
35 * breaks the specification.
37 * @param cookie client identification
38 * @param request the original request packet
39 * @param response the packet to send
40 * @return The status of the operation
42 static protocol_binary_response_status
43 binary_raw_response_handler(const void *cookie
, protocol_binary_request_header
*request
,
44 protocol_binary_response_header
*response
) {
45 memcached_protocol_client_st
*client
= (void *) cookie
;
47 if (client
->root
->pedantic
48 && !memcached_binary_protocol_pedantic_check_response(request
, response
)) {
49 return PROTOCOL_BINARY_RESPONSE_EINVAL
;
52 if (client
->root
->drain(client
) == false) {
53 return PROTOCOL_BINARY_RESPONSE_EINTERNAL
;
56 size_t len
= sizeof(protocol_binary_response_header
) + htonl(response
->response
.bodylen
);
58 char *ptr
= (void *) response
;
60 if (client
->output
== NULL
) {
61 /* I can write directly to the socket.... */
63 size_t num_bytes
= len
- offset
;
64 ssize_t nw
= client
->root
->send(client
, client
->sock
, ptr
+ offset
, num_bytes
);
66 if (get_socket_errno() == EWOULDBLOCK
) {
68 } else if (get_socket_errno() != EINTR
) {
69 client
->error
= errno
;
70 return PROTOCOL_BINARY_RESPONSE_EINTERNAL
;
73 offset
+= (size_t) nw
;
75 } while (offset
< len
);
78 return client
->root
->spool(client
, ptr
, len
- offset
);
81 static void print_cmd(protocol_binary_command cmd
) {
83 case PROTOCOL_BINARY_CMD_GET
:
84 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GET\n", __FILE__
, __LINE__
);
86 case PROTOCOL_BINARY_CMD_SET
:
87 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SET\n", __FILE__
, __LINE__
);
89 case PROTOCOL_BINARY_CMD_ADD
:
90 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_ADD\n", __FILE__
, __LINE__
);
92 case PROTOCOL_BINARY_CMD_REPLACE
:
93 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_REPLACE\n", __FILE__
, __LINE__
);
95 case PROTOCOL_BINARY_CMD_DELETE
:
96 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DELETE\n", __FILE__
, __LINE__
);
98 case PROTOCOL_BINARY_CMD_INCREMENT
:
99 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_INCREMENT\n", __FILE__
, __LINE__
);
101 case PROTOCOL_BINARY_CMD_DECREMENT
:
102 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DECREMENT\n", __FILE__
, __LINE__
);
104 case PROTOCOL_BINARY_CMD_QUIT
:
105 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_QUIT\n", __FILE__
, __LINE__
);
107 case PROTOCOL_BINARY_CMD_FLUSH
:
108 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_FLUSH\n", __FILE__
, __LINE__
);
110 case PROTOCOL_BINARY_CMD_GETQ
:
111 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GETQ\n", __FILE__
, __LINE__
);
113 case PROTOCOL_BINARY_CMD_NOOP
:
114 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_NOOP\n", __FILE__
, __LINE__
);
116 case PROTOCOL_BINARY_CMD_VERSION
:
117 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_VERSION\n", __FILE__
, __LINE__
);
119 case PROTOCOL_BINARY_CMD_GETK
:
120 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GETK\n", __FILE__
, __LINE__
);
122 case PROTOCOL_BINARY_CMD_GETKQ
:
123 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GETKQ\n", __FILE__
, __LINE__
);
125 case PROTOCOL_BINARY_CMD_APPEND
:
126 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_APPEND\n", __FILE__
, __LINE__
);
128 case PROTOCOL_BINARY_CMD_PREPEND
:
129 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_PREPEND\n", __FILE__
, __LINE__
);
131 case PROTOCOL_BINARY_CMD_STAT
:
132 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_STAT\n", __FILE__
, __LINE__
);
134 case PROTOCOL_BINARY_CMD_SETQ
:
135 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SETQ\n", __FILE__
, __LINE__
);
137 case PROTOCOL_BINARY_CMD_ADDQ
:
138 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_ADDQ\n", __FILE__
, __LINE__
);
140 case PROTOCOL_BINARY_CMD_REPLACEQ
:
141 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_REPLACEQ\n", __FILE__
, __LINE__
);
143 case PROTOCOL_BINARY_CMD_DELETEQ
:
144 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DELETEQ\n", __FILE__
, __LINE__
);
146 case PROTOCOL_BINARY_CMD_INCREMENTQ
:
147 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_INCREMENTQ\n", __FILE__
, __LINE__
);
149 case PROTOCOL_BINARY_CMD_DECREMENTQ
:
150 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DECREMENTQ\n", __FILE__
, __LINE__
);
152 case PROTOCOL_BINARY_CMD_QUITQ
:
153 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_QUITQ\n", __FILE__
, __LINE__
);
155 case PROTOCOL_BINARY_CMD_FLUSHQ
:
156 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_FLUSHQ\n", __FILE__
, __LINE__
);
158 case PROTOCOL_BINARY_CMD_APPENDQ
:
159 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_APPENDQ\n", __FILE__
, __LINE__
);
161 case PROTOCOL_BINARY_CMD_PREPENDQ
:
162 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_PREPENDQ\n", __FILE__
, __LINE__
);
164 case PROTOCOL_BINARY_CMD_VERBOSITY
:
165 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_VERBOSITY\n", __FILE__
, __LINE__
);
167 case PROTOCOL_BINARY_CMD_TOUCH
:
168 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TOUCH\n", __FILE__
, __LINE__
);
170 case PROTOCOL_BINARY_CMD_GAT
:
171 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GAT\n", __FILE__
, __LINE__
);
173 case PROTOCOL_BINARY_CMD_GATQ
:
174 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GATQ\n", __FILE__
, __LINE__
);
176 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
177 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SASL_LIST_MECHS\n", __FILE__
, __LINE__
);
179 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
180 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SASL_AUTH\n", __FILE__
, __LINE__
);
182 case PROTOCOL_BINARY_CMD_SASL_STEP
:
183 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SASL_STEP\n", __FILE__
, __LINE__
);
185 case PROTOCOL_BINARY_CMD_RGET
:
186 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RGET\n", __FILE__
, __LINE__
);
188 case PROTOCOL_BINARY_CMD_RSET
:
189 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RSET\n", __FILE__
, __LINE__
);
191 case PROTOCOL_BINARY_CMD_RSETQ
:
192 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RSETQ\n", __FILE__
, __LINE__
);
194 case PROTOCOL_BINARY_CMD_RAPPEND
:
195 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RAPPEND\n", __FILE__
, __LINE__
);
197 case PROTOCOL_BINARY_CMD_RAPPENDQ
:
198 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RAPPENDQ\n", __FILE__
, __LINE__
);
200 case PROTOCOL_BINARY_CMD_RPREPEND
:
201 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RPREPEND\n", __FILE__
, __LINE__
);
203 case PROTOCOL_BINARY_CMD_RPREPENDQ
:
204 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RPREPENDQ\n", __FILE__
, __LINE__
);
206 case PROTOCOL_BINARY_CMD_RDELETE
:
207 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDELETE\n", __FILE__
, __LINE__
);
209 case PROTOCOL_BINARY_CMD_RDELETEQ
:
210 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDELETEQ\n", __FILE__
, __LINE__
);
212 case PROTOCOL_BINARY_CMD_RINCR
:
213 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RINCR\n", __FILE__
, __LINE__
);
215 case PROTOCOL_BINARY_CMD_RINCRQ
:
216 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RINCRQ\n", __FILE__
, __LINE__
);
218 case PROTOCOL_BINARY_CMD_RDECR
:
219 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDECR\n", __FILE__
, __LINE__
);
221 case PROTOCOL_BINARY_CMD_RDECRQ
:
222 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDECRQ\n", __FILE__
, __LINE__
);
224 case PROTOCOL_BINARY_CMD_SET_VBUCKET
:
225 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SET_VBUCKET\n", __FILE__
, __LINE__
);
227 case PROTOCOL_BINARY_CMD_GET_VBUCKET
:
228 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GET_VBUCKET\n", __FILE__
, __LINE__
);
230 case PROTOCOL_BINARY_CMD_DEL_VBUCKET
:
231 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DEL_VBUCKET\n", __FILE__
, __LINE__
);
233 case PROTOCOL_BINARY_CMD_TAP_CONNECT
:
234 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_CONNECT\n", __FILE__
, __LINE__
);
236 case PROTOCOL_BINARY_CMD_TAP_MUTATION
:
237 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_MUTATION\n", __FILE__
, __LINE__
);
239 case PROTOCOL_BINARY_CMD_TAP_DELETE
:
240 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_DELETE\n", __FILE__
, __LINE__
);
242 case PROTOCOL_BINARY_CMD_TAP_FLUSH
:
243 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_FLUSH\n", __FILE__
, __LINE__
);
245 case PROTOCOL_BINARY_CMD_TAP_OPAQUE
:
246 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_OPAQUE\n", __FILE__
, __LINE__
);
248 case PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET
:
249 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET\n", __FILE__
, __LINE__
);
251 case PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START
:
252 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START\n", __FILE__
, __LINE__
);
254 case PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END
:
255 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END\n", __FILE__
, __LINE__
);
257 case PROTOCOL_BINARY_CMD_LAST_RESERVED
:
258 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_LAST_RESERVED\n", __FILE__
, __LINE__
);
260 case PROTOCOL_BINARY_CMD_GATK
:
261 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GATK\n", __FILE__
, __LINE__
);
263 case PROTOCOL_BINARY_CMD_GATKQ
:
264 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GATKQ\n", __FILE__
, __LINE__
);
266 case PROTOCOL_BINARY_CMD_SCRUB
:
267 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SCRUB\n", __FILE__
, __LINE__
);
275 * Version 0 of the interface is really low level and protocol specific,
276 * while the version 1 of the interface is more API focused. We need a
277 * way to translate between the command codes on the wire and the
278 * application level interface in V1, so let's just use the V0 of the
279 * interface as a map instead of creating a huuuge switch :-)
283 * Callback for the GET/GETQ/GETK and GETKQ responses
284 * @param cookie client identifier
285 * @param key the key for the item
286 * @param keylen the length of the key
287 * @param body the length of the body
288 * @param bodylen the length of the body
289 * @param flags the flags for the item
290 * @param cas the CAS id for the item
292 static protocol_binary_response_status
get_response_handler(const void *cookie
, const void *key
,
293 uint16_t keylen
, const void *body
,
294 uint32_t bodylen
, uint32_t flags
,
296 memcached_protocol_client_st
*client
= (void *) cookie
;
297 uint8_t opcode
= client
->current_command
->request
.opcode
;
299 if (opcode
== PROTOCOL_BINARY_CMD_GET
|| opcode
== PROTOCOL_BINARY_CMD_GETQ
) {
303 protocol_binary_response_get response
= {
304 .message
.header
.response
=
306 .magic
= PROTOCOL_BINARY_RES
,
308 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
309 .opaque
= client
->current_command
->request
.opaque
,
310 .cas
= memcached_htonll(cas
),
311 .keylen
= htons(keylen
),
313 .bodylen
= htonl(bodylen
+ keylen
+ 4),
317 response
.message
.body
.flags
= htonl(flags
);
319 protocol_binary_response_status rval
;
320 const protocol_binary_response_status success
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
321 if ((rval
= client
->root
->spool(client
, response
.bytes
, sizeof(response
.bytes
))) != success
322 || (rval
= client
->root
->spool(client
, key
, keylen
)) != success
323 || (rval
= client
->root
->spool(client
, body
, bodylen
)) != success
)
328 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
332 * Callback for the STAT responses
333 * @param cookie client identifier
334 * @param key the key for the item
335 * @param keylen the length of the key
336 * @param body the length of the body
337 * @param bodylen the length of the body
339 static protocol_binary_response_status
stat_response_handler(const void *cookie
, const void *key
,
340 uint16_t keylen
, const void *body
,
342 memcached_protocol_client_st
*client
= (void *) cookie
;
344 protocol_binary_response_no_extras response
= {
345 .message
.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
346 .opcode
= client
->current_command
->request
.opcode
,
347 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
348 .opaque
= client
->current_command
->request
.opaque
,
349 .keylen
= htons(keylen
),
350 .bodylen
= htonl(bodylen
+ keylen
),
354 protocol_binary_response_status rval
;
355 const protocol_binary_response_status success
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
356 if ((rval
= client
->root
->spool(client
, response
.bytes
, sizeof(response
.bytes
))) != success
357 || (rval
= client
->root
->spool(client
, key
, keylen
)) != success
358 || (rval
= client
->root
->spool(client
, body
, bodylen
)) != success
)
363 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
367 * Callback for the VERSION responses
368 * @param cookie client identifier
369 * @param text the length of the body
370 * @param textlen the length of the body
372 static protocol_binary_response_status
373 version_response_handler(const void *cookie
, const void *text
, uint32_t textlen
) {
374 memcached_protocol_client_st
*client
= (void *) cookie
;
376 protocol_binary_response_no_extras response
= {
377 .message
.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
378 .opcode
= client
->current_command
->request
.opcode
,
379 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
380 .opaque
= client
->current_command
->request
.opaque
,
381 .bodylen
= htonl(textlen
),
385 protocol_binary_response_status rval
;
386 const protocol_binary_response_status success
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
387 if ((rval
= client
->root
->spool(client
, response
.bytes
, sizeof(response
.bytes
))) != success
388 || (rval
= client
->root
->spool(client
, text
, textlen
)) != success
)
393 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
397 * Callback for ADD and ADDQ
398 * @param cookie the calling client
399 * @param header the add/addq command
400 * @param response_handler not used
401 * @return the result of the operation
403 static protocol_binary_response_status
404 add_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
405 memcached_binary_protocol_raw_response_handler response_handler
) {
406 protocol_binary_response_status rval
;
408 memcached_protocol_client_st
*client
= (void *) cookie
;
409 if (client
->root
->callback
->interface
.v1
.add
) {
410 uint16_t keylen
= ntohs(header
->request
.keylen
);
411 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
412 protocol_binary_request_add
*request
= (void *) header
;
413 uint32_t flags
= ntohl(request
->message
.body
.flags
);
414 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
415 char *key
= ((char *) header
) + sizeof(*header
) + 8;
416 char *data
= key
+ keylen
;
419 rval
= client
->root
->callback
->interface
.v1
.add(cookie
, key
, keylen
, data
, datalen
, flags
,
422 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
423 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_ADD
) {
424 /* Send a positive request */
425 protocol_binary_response_no_extras response
= {
426 .message
= {.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
427 .opcode
= PROTOCOL_BINARY_CMD_ADD
,
428 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
429 .opaque
= header
->request
.opaque
,
430 .cas
= memcached_ntohll(cas
)}}};
431 rval
= response_handler(cookie
, header
, (void *) &response
);
434 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
441 * Callback for DECREMENT and DECREMENTQ
442 * @param cookie the calling client
443 * @param header the command
444 * @param response_handler not used
445 * @return the result of the operation
447 static protocol_binary_response_status
448 decrement_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
449 memcached_binary_protocol_raw_response_handler response_handler
) {
450 (void) response_handler
;
451 protocol_binary_response_status rval
;
453 memcached_protocol_client_st
*client
= (void *) cookie
;
454 if (client
->root
->callback
->interface
.v1
.decrement
) {
455 uint16_t keylen
= ntohs(header
->request
.keylen
);
456 protocol_binary_request_decr
*request
= (void *) header
;
457 uint64_t init
= memcached_ntohll(request
->message
.body
.initial
);
458 uint64_t delta
= memcached_ntohll(request
->message
.body
.delta
);
459 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
460 void *key
= request
->bytes
+ sizeof(request
->bytes
);
464 rval
= client
->root
->callback
->interface
.v1
.decrement(cookie
, key
, keylen
, delta
, init
, timeout
,
466 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
467 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_DECREMENT
)
469 /* Send a positive request */
470 protocol_binary_response_decr response
= {
471 .message
= {.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
472 .opcode
= PROTOCOL_BINARY_CMD_DECREMENT
,
473 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
474 .opaque
= header
->request
.opaque
,
475 .cas
= memcached_ntohll(cas
),
476 .bodylen
= htonl(8)},
477 .body
.value
= memcached_htonll(result
)}};
478 rval
= response_handler(cookie
, header
, (void *) &response
);
481 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
488 * Callback for DELETE and DELETEQ
489 * @param cookie the calling client
490 * @param header the command
491 * @param response_handler not used
492 * @return the result of the operation
494 static protocol_binary_response_status
495 delete_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
496 memcached_binary_protocol_raw_response_handler response_handler
) {
497 (void) response_handler
;
498 protocol_binary_response_status rval
;
500 memcached_protocol_client_st
*client
= (void *) cookie
;
501 if (client
->root
->callback
->interface
.v1
.delete_object
) {
502 uint16_t keylen
= ntohs(header
->request
.keylen
);
503 void *key
= (header
+ 1);
504 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
505 rval
= client
->root
->callback
->interface
.v1
.delete_object(cookie
, key
, keylen
, cas
);
506 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
507 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_DELETE
)
509 /* Send a positive request */
510 protocol_binary_response_no_extras response
= {
511 .message
= {.header
.response
= {
512 .magic
= PROTOCOL_BINARY_RES
,
513 .opcode
= PROTOCOL_BINARY_CMD_DELETE
,
514 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
515 .opaque
= header
->request
.opaque
,
517 rval
= response_handler(cookie
, header
, (void *) &response
);
520 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
527 * Callback for FLUSH and FLUSHQ
528 * @param cookie the calling client
529 * @param header the command
530 * @param response_handler not used
531 * @return the result of the operation
533 static protocol_binary_response_status
534 flush_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
535 memcached_binary_protocol_raw_response_handler response_handler
) {
536 (void) response_handler
;
537 protocol_binary_response_status rval
;
539 memcached_protocol_client_st
*client
= (void *) cookie
;
540 if (client
->root
->callback
->interface
.v1
.flush_object
) {
541 protocol_binary_request_flush
*flush_object
= (void *) header
;
542 uint32_t timeout
= 0;
543 if (htonl(header
->request
.bodylen
) == 4) {
544 timeout
= ntohl(flush_object
->message
.body
.expiration
);
547 rval
= client
->root
->callback
->interface
.v1
.flush_object(cookie
, timeout
);
548 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
549 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_FLUSH
) {
550 /* Send a positive request */
551 protocol_binary_response_no_extras response
= {
552 .message
= {.header
.response
= {
553 .magic
= PROTOCOL_BINARY_RES
,
554 .opcode
= PROTOCOL_BINARY_CMD_FLUSH
,
555 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
556 .opaque
= header
->request
.opaque
,
558 rval
= response_handler(cookie
, header
, (void *) &response
);
561 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
568 * Callback for GET, GETK, GETQ, GETKQ
569 * @param cookie the calling client
570 * @param header the command
571 * @param response_handler not used
572 * @return the result of the operation
574 static protocol_binary_response_status
575 get_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
576 memcached_binary_protocol_raw_response_handler response_handler
) {
577 (void) response_handler
;
578 protocol_binary_response_status rval
;
580 memcached_protocol_client_st
*client
= (void *) cookie
;
581 if (client
->root
->callback
->interface
.v1
.get
) {
582 uint16_t keylen
= ntohs(header
->request
.keylen
);
583 void *key
= (header
+ 1);
584 rval
= client
->root
->callback
->interface
.v1
.get(cookie
, key
, keylen
, get_response_handler
);
586 if (rval
== PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
587 && (header
->request
.opcode
== PROTOCOL_BINARY_CMD_GETQ
588 || header
->request
.opcode
== PROTOCOL_BINARY_CMD_GETKQ
))
590 /* Quiet commands shouldn't respond on cache misses */
591 rval
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
594 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
601 * Callback for INCREMENT and INCREMENTQ
602 * @param cookie the calling client
603 * @param header the command
604 * @param response_handler not used
605 * @return the result of the operation
607 static protocol_binary_response_status
608 increment_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
609 memcached_binary_protocol_raw_response_handler response_handler
) {
610 (void) response_handler
;
611 protocol_binary_response_status rval
;
613 memcached_protocol_client_st
*client
= (void *) cookie
;
614 if (client
->root
->callback
->interface
.v1
.increment
) {
615 uint16_t keylen
= ntohs(header
->request
.keylen
);
616 protocol_binary_request_incr
*request
= (void *) header
;
617 uint64_t init
= memcached_ntohll(request
->message
.body
.initial
);
618 uint64_t delta
= memcached_ntohll(request
->message
.body
.delta
);
619 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
620 void *key
= request
->bytes
+ sizeof(request
->bytes
);
624 rval
= client
->root
->callback
->interface
.v1
.increment(cookie
, key
, keylen
, delta
, init
, timeout
,
626 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
627 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_INCREMENT
)
629 /* Send a positive request */
630 protocol_binary_response_incr response
= {
631 .message
= {.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
632 .opcode
= PROTOCOL_BINARY_CMD_INCREMENT
,
633 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
634 .opaque
= header
->request
.opaque
,
635 .cas
= memcached_ntohll(cas
),
636 .bodylen
= htonl(8)},
637 .body
.value
= memcached_htonll(result
)}};
639 rval
= response_handler(cookie
, header
, (void *) &response
);
642 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
649 * Callback for noop. Inform the v1 interface about the noop packet, and
650 * create and send a packet back to the client
652 * @param cookie the calling client
653 * @param header the command
654 * @param response_handler the response handler
655 * @return the result of the operation
657 static protocol_binary_response_status
658 noop_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
659 memcached_binary_protocol_raw_response_handler response_handler
) {
660 memcached_protocol_client_st
*client
= (void *) cookie
;
661 if (client
->root
->callback
->interface
.v1
.noop
) {
662 client
->root
->callback
->interface
.v1
.noop(cookie
);
665 protocol_binary_response_no_extras response
= {
666 .message
= {.header
.response
= {
667 .magic
= PROTOCOL_BINARY_RES
,
668 .opcode
= PROTOCOL_BINARY_CMD_NOOP
,
669 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
670 .opaque
= header
->request
.opaque
,
673 return response_handler(cookie
, header
, (void *) &response
);
677 * Callback for APPEND and APPENDQ
678 * @param cookie the calling client
679 * @param header the command
680 * @param response_handler not used
681 * @return the result of the operation
683 static protocol_binary_response_status
684 append_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
685 memcached_binary_protocol_raw_response_handler response_handler
) {
686 (void) response_handler
;
687 protocol_binary_response_status rval
;
689 memcached_protocol_client_st
*client
= (void *) cookie
;
690 if (client
->root
->callback
->interface
.v1
.append
) {
691 uint16_t keylen
= ntohs(header
->request
.keylen
);
692 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
;
693 char *key
= (void *) (header
+ 1);
694 char *data
= key
+ keylen
;
695 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
698 rval
= client
->root
->callback
->interface
.v1
.append(cookie
, key
, keylen
, data
, datalen
, cas
,
700 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
701 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_APPEND
)
703 /* Send a positive request */
704 protocol_binary_response_no_extras response
= {
708 .magic
= PROTOCOL_BINARY_RES
,
709 .opcode
= PROTOCOL_BINARY_CMD_APPEND
,
710 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
711 .opaque
= header
->request
.opaque
,
712 .cas
= memcached_ntohll(result_cas
),
715 rval
= response_handler(cookie
, header
, (void *) &response
);
718 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
725 * Callback for PREPEND and PREPENDQ
726 * @param cookie the calling client
727 * @param header the command
728 * @param response_handler not used
729 * @return the result of the operation
731 static protocol_binary_response_status
732 prepend_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
733 memcached_binary_protocol_raw_response_handler response_handler
) {
734 (void) response_handler
;
735 protocol_binary_response_status rval
;
737 memcached_protocol_client_st
*client
= (void *) cookie
;
738 if (client
->root
->callback
->interface
.v1
.prepend
) {
739 uint16_t keylen
= ntohs(header
->request
.keylen
);
740 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
;
741 char *key
= (char *) (header
+ 1);
742 char *data
= key
+ keylen
;
743 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
745 rval
= client
->root
->callback
->interface
.v1
.prepend(cookie
, key
, keylen
, data
, datalen
, cas
,
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
= {
755 .magic
= PROTOCOL_BINARY_RES
,
756 .opcode
= PROTOCOL_BINARY_CMD_PREPEND
,
757 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
758 .opaque
= header
->request
.opaque
,
759 .cas
= memcached_ntohll(result_cas
),
762 rval
= response_handler(cookie
, header
, (void *) &response
);
765 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
772 * Callback for QUIT and QUITQ. Notify the client and shut down the connection
773 * @param cookie the calling client
774 * @param header the command
775 * @param response_handler not used
776 * @return the result of the operation
778 static protocol_binary_response_status
779 quit_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
780 memcached_binary_protocol_raw_response_handler response_handler
) {
781 memcached_protocol_client_st
*client
= (void *) cookie
;
782 if (client
->root
->callback
->interface
.v1
.quit
) {
783 client
->root
->callback
->interface
.v1
.quit(cookie
);
786 protocol_binary_response_no_extras response
= {
787 .message
= {.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
788 .opcode
= PROTOCOL_BINARY_CMD_QUIT
,
789 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
790 .opaque
= header
->request
.opaque
}}};
792 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_QUIT
) {
793 response_handler(cookie
, header
, (void *) &response
);
796 /* I need a better way to signal to close the connection */
797 return PROTOCOL_BINARY_RESPONSE_EINTERNAL
;
801 * Callback for REPLACE and REPLACEQ
802 * @param cookie the calling client
803 * @param header the command
804 * @param response_handler not used
805 * @return the result of the operation
807 static protocol_binary_response_status
808 replace_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
809 memcached_binary_protocol_raw_response_handler response_handler
) {
810 (void) response_handler
;
811 protocol_binary_response_status rval
;
813 memcached_protocol_client_st
*client
= (void *) cookie
;
814 if (client
->root
->callback
->interface
.v1
.replace
) {
815 uint16_t keylen
= ntohs(header
->request
.keylen
);
816 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
817 protocol_binary_request_replace
*request
= (void *) header
;
818 uint32_t flags
= ntohl(request
->message
.body
.flags
);
819 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
820 char *key
= ((char *) header
) + sizeof(*header
) + 8;
821 char *data
= key
+ keylen
;
822 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
825 rval
= client
->root
->callback
->interface
.v1
.replace(cookie
, key
, keylen
, data
, datalen
, flags
,
826 timeout
, cas
, &result_cas
);
827 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
828 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_REPLACE
)
830 /* Send a positive request */
831 protocol_binary_response_no_extras response
= {
835 .magic
= PROTOCOL_BINARY_RES
,
836 .opcode
= PROTOCOL_BINARY_CMD_REPLACE
,
837 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
838 .opaque
= header
->request
.opaque
,
839 .cas
= memcached_ntohll(result_cas
),
842 rval
= response_handler(cookie
, header
, (void *) &response
);
845 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
852 * Callback for SET and SETQ
853 * @param cookie the calling client
854 * @param header the command
855 * @param response_handler not used
856 * @return the result of the operation
858 static protocol_binary_response_status
859 set_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
860 memcached_binary_protocol_raw_response_handler response_handler
) {
861 (void) response_handler
;
862 protocol_binary_response_status rval
;
864 memcached_protocol_client_st
*client
= (void *) cookie
;
865 if (client
->root
->callback
->interface
.v1
.set
) {
866 uint16_t keylen
= ntohs(header
->request
.keylen
);
867 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
868 protocol_binary_request_replace
*request
= (void *) header
;
869 uint32_t flags
= ntohl(request
->message
.body
.flags
);
870 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
871 char *key
= ((char *) header
) + sizeof(*header
) + 8;
872 char *data
= key
+ keylen
;
873 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
876 rval
= client
->root
->callback
->interface
.v1
.set(cookie
, key
, keylen
, data
, datalen
, flags
,
877 timeout
, cas
, &result_cas
);
878 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
879 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_SET
) {
880 /* Send a positive request */
881 protocol_binary_response_no_extras response
= {
885 .magic
= PROTOCOL_BINARY_RES
,
886 .opcode
= PROTOCOL_BINARY_CMD_SET
,
887 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
888 .opaque
= header
->request
.opaque
,
889 .cas
= memcached_ntohll(result_cas
),
892 rval
= response_handler(cookie
, header
, (void *) &response
);
895 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
903 * @param cookie the calling client
904 * @param header the command
905 * @param response_handler not used
906 * @return the result of the operation
908 static protocol_binary_response_status
909 stat_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
910 memcached_binary_protocol_raw_response_handler response_handler
) {
911 (void) response_handler
;
912 protocol_binary_response_status rval
;
914 memcached_protocol_client_st
*client
= (void *) cookie
;
915 if (client
->root
->callback
->interface
.v1
.stat
) {
916 uint16_t keylen
= ntohs(header
->request
.keylen
);
918 rval
= client
->root
->callback
->interface
.v1
.stat(cookie
, (void *) (header
+ 1), keylen
,
919 stat_response_handler
);
921 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
928 * Callback for VERSION
929 * @param cookie the calling client
930 * @param header the command
931 * @param response_handler not used
932 * @return the result of the operation
934 static protocol_binary_response_status
935 version_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
936 memcached_binary_protocol_raw_response_handler response_handler
) {
937 (void) response_handler
;
939 protocol_binary_response_status rval
;
941 memcached_protocol_client_st
*client
= (void *) cookie
;
942 if (client
->root
->callback
->interface
.v1
.version
) {
943 rval
= client
->root
->callback
->interface
.v1
.version(cookie
, version_response_handler
);
945 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
952 * The map to remap between the com codes and the v1 logical setting
954 static memcached_binary_protocol_command_handler comcode_v0_v1_remap
[256] = {
955 [PROTOCOL_BINARY_CMD_ADDQ
] = add_command_handler
,
956 [PROTOCOL_BINARY_CMD_ADD
] = add_command_handler
,
957 [PROTOCOL_BINARY_CMD_APPENDQ
] = append_command_handler
,
958 [PROTOCOL_BINARY_CMD_APPEND
] = append_command_handler
,
959 [PROTOCOL_BINARY_CMD_DECREMENTQ
] = decrement_command_handler
,
960 [PROTOCOL_BINARY_CMD_DECREMENT
] = decrement_command_handler
,
961 [PROTOCOL_BINARY_CMD_DELETEQ
] = delete_command_handler
,
962 [PROTOCOL_BINARY_CMD_DELETE
] = delete_command_handler
,
963 [PROTOCOL_BINARY_CMD_FLUSHQ
] = flush_command_handler
,
964 [PROTOCOL_BINARY_CMD_FLUSH
] = flush_command_handler
,
965 [PROTOCOL_BINARY_CMD_GETKQ
] = get_command_handler
,
966 [PROTOCOL_BINARY_CMD_GETK
] = get_command_handler
,
967 [PROTOCOL_BINARY_CMD_GETQ
] = get_command_handler
,
968 [PROTOCOL_BINARY_CMD_GET
] = get_command_handler
,
969 [PROTOCOL_BINARY_CMD_INCREMENTQ
] = increment_command_handler
,
970 [PROTOCOL_BINARY_CMD_INCREMENT
] = increment_command_handler
,
971 [PROTOCOL_BINARY_CMD_NOOP
] = noop_command_handler
,
972 [PROTOCOL_BINARY_CMD_PREPENDQ
] = prepend_command_handler
,
973 [PROTOCOL_BINARY_CMD_PREPEND
] = prepend_command_handler
,
974 [PROTOCOL_BINARY_CMD_QUITQ
] = quit_command_handler
,
975 [PROTOCOL_BINARY_CMD_QUIT
] = quit_command_handler
,
976 [PROTOCOL_BINARY_CMD_REPLACEQ
] = replace_command_handler
,
977 [PROTOCOL_BINARY_CMD_REPLACE
] = replace_command_handler
,
978 [PROTOCOL_BINARY_CMD_SETQ
] = set_command_handler
,
979 [PROTOCOL_BINARY_CMD_SET
] = set_command_handler
,
980 [PROTOCOL_BINARY_CMD_STAT
] = stat_command_handler
,
981 [PROTOCOL_BINARY_CMD_VERSION
] = version_command_handler
,
985 * Try to execute a command. Fire the pre/post functions and the specialized
986 * handler function if it's set. If not, the unknown probe should be fired
988 * @param client the client connection to operate on
989 * @param header the command to execute
990 * @return true if success or false if a fatal error occured so that the
991 * connection should be shut down.
993 static protocol_binary_response_status
execute_command(memcached_protocol_client_st
*client
,
994 protocol_binary_request_header
*header
) {
995 if (client
->root
->pedantic
&& memcached_binary_protocol_pedantic_check_request(header
)) {
996 /* @todo return invalid command packet */
999 /* we got all data available, execute the callback! */
1000 if (client
->root
->callback
->pre_execute
) {
1001 client
->root
->callback
->pre_execute(client
, header
);
1004 protocol_binary_response_status rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
1005 uint8_t cc
= header
->request
.opcode
;
1007 if (client
->is_verbose
) {
1011 switch (client
->root
->callback
->interface_version
) {
1013 if (client
->root
->callback
->interface
.v0
.comcode
[cc
]) {
1014 rval
= client
->root
->callback
->interface
.v0
.comcode
[cc
](client
, header
,
1015 binary_raw_response_handler
);
1020 if (comcode_v0_v1_remap
[cc
]) {
1021 rval
= comcode_v0_v1_remap
[cc
](client
, header
, binary_raw_response_handler
);
1026 /* Unknown interface.
1027 * It should be impossible to get here so I'll just call abort
1028 * to avoid getting a compiler warning :-)
1033 if (rval
== PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
&& client
->root
->callback
->unknown
) {
1034 rval
= client
->root
->callback
->unknown(client
, header
, binary_raw_response_handler
);
1037 if (rval
!= PROTOCOL_BINARY_RESPONSE_SUCCESS
&& rval
!= PROTOCOL_BINARY_RESPONSE_EINTERNAL
1038 && rval
!= PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED
)
1040 protocol_binary_response_no_extras response
= {.message
= {
1043 .magic
= PROTOCOL_BINARY_RES
,
1045 .status
= htons(rval
),
1046 .opaque
= header
->request
.opaque
,
1049 rval
= binary_raw_response_handler(client
, header
, (void *) &response
);
1052 if (client
->root
->callback
->post_execute
) {
1053 client
->root
->callback
->post_execute(client
, header
);
1060 ** **********************************************************************
1061 ** "PROTOECTED" INTERFACE
1062 ** **********************************************************************
1064 memcached_protocol_event_t
1065 memcached_binary_protocol_process_data(memcached_protocol_client_st
*client
, ssize_t
*length
,
1067 /* try to parse all of the received packets */
1068 protocol_binary_request_header
*header
;
1069 header
= (void *) client
->root
->input_buffer
;
1070 if (header
->request
.magic
!= (uint8_t) PROTOCOL_BINARY_REQ
) {
1071 client
->error
= EINVAL
;
1072 return MEMCACHED_PROTOCOL_ERROR_EVENT
;
1074 ssize_t len
= *length
;
1076 while (len
>= (ssize_t
) sizeof(*header
)
1077 && (len
>= (ssize_t
)(sizeof(*header
) + ntohl(header
->request
.bodylen
))))
1079 /* I have the complete package */
1080 client
->current_command
= header
;
1081 protocol_binary_response_status rv
= execute_command(client
, header
);
1083 if (rv
== PROTOCOL_BINARY_RESPONSE_EINTERNAL
) {
1085 *endptr
= (void *) header
;
1086 return MEMCACHED_PROTOCOL_ERROR_EVENT
;
1087 } else if (rv
== PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED
) {
1088 return MEMCACHED_PROTOCOL_PAUSE_EVENT
;
1091 ssize_t total
= (ssize_t
)(sizeof(*header
) + ntohl(header
->request
.bodylen
));
1094 intptr_t ptr
= (intptr_t) header
;
1096 if ((ptr
% 8) == 0) {
1097 header
= (void *) ptr
;
1100 memmove(client
->root
->input_buffer
, (void *) ptr
, (size_t) len
);
1101 header
= (void *) client
->root
->input_buffer
;
1105 *endptr
= (void *) header
;
1108 return MEMCACHED_PROTOCOL_READ_EVENT
;
1112 ** **********************************************************************
1114 ** **********************************************************************
1116 memcached_binary_protocol_callback_st
*
1117 memcached_binary_protocol_get_callbacks(memcached_protocol_st
*instance
) {
1118 return instance
->callback
;
1121 void memcached_binary_protocol_set_callbacks(memcached_protocol_st
*instance
,
1122 memcached_binary_protocol_callback_st
*callback
) {
1123 instance
->callback
= callback
;
1126 memcached_binary_protocol_raw_response_handler
1127 memcached_binary_protocol_get_raw_response_handler(const void *cookie
) {
1129 return binary_raw_response_handler
;
1132 void memcached_binary_protocol_set_pedantic(memcached_protocol_st
*instance
, bool enable
) {
1133 instance
->pedantic
= enable
;
1136 bool memcached_binary_protocol_get_pedantic(memcached_protocol_st
*instance
) {
1137 return instance
->pedantic
;