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__
);
273 * Version 0 of the interface is really low level and protocol specific,
274 * while the version 1 of the interface is more API focused. We need a
275 * way to translate between the command codes on the wire and the
276 * application level interface in V1, so let's just use the V0 of the
277 * interface as a map instead of creating a huuuge switch :-)
281 * Callback for the GET/GETQ/GETK and GETKQ responses
282 * @param cookie client identifier
283 * @param key the key for the item
284 * @param keylen the length of the key
285 * @param body the length of the body
286 * @param bodylen the length of the body
287 * @param flags the flags for the item
288 * @param cas the CAS id for the item
290 static protocol_binary_response_status
get_response_handler(const void *cookie
, const void *key
,
291 uint16_t keylen
, const void *body
,
292 uint32_t bodylen
, uint32_t flags
,
294 memcached_protocol_client_st
*client
= (void *) cookie
;
295 uint8_t opcode
= client
->current_command
->request
.opcode
;
297 if (opcode
== PROTOCOL_BINARY_CMD_GET
|| opcode
== PROTOCOL_BINARY_CMD_GETQ
) {
301 protocol_binary_response_get response
= {
302 .message
.header
.response
=
304 .magic
= PROTOCOL_BINARY_RES
,
306 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
307 .opaque
= client
->current_command
->request
.opaque
,
308 .cas
= memcached_htonll(cas
),
309 .keylen
= htons(keylen
),
311 .bodylen
= htonl(bodylen
+ keylen
+ 4),
315 response
.message
.body
.flags
= htonl(flags
);
317 protocol_binary_response_status rval
;
318 const protocol_binary_response_status success
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
319 if ((rval
= client
->root
->spool(client
, response
.bytes
, sizeof(response
.bytes
))) != success
320 || (rval
= client
->root
->spool(client
, key
, keylen
)) != success
321 || (rval
= client
->root
->spool(client
, body
, bodylen
)) != success
)
326 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
330 * Callback for the STAT responses
331 * @param cookie client identifier
332 * @param key the key for the item
333 * @param keylen the length of the key
334 * @param body the length of the body
335 * @param bodylen the length of the body
337 static protocol_binary_response_status
stat_response_handler(const void *cookie
, const void *key
,
338 uint16_t keylen
, const void *body
,
340 memcached_protocol_client_st
*client
= (void *) cookie
;
342 protocol_binary_response_no_extras response
= {
343 .message
.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
344 .opcode
= client
->current_command
->request
.opcode
,
345 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
346 .opaque
= client
->current_command
->request
.opaque
,
347 .keylen
= htons(keylen
),
348 .bodylen
= htonl(bodylen
+ keylen
),
352 protocol_binary_response_status rval
;
353 const protocol_binary_response_status success
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
354 if ((rval
= client
->root
->spool(client
, response
.bytes
, sizeof(response
.bytes
))) != success
355 || (rval
= client
->root
->spool(client
, key
, keylen
)) != success
356 || (rval
= client
->root
->spool(client
, body
, bodylen
)) != success
)
361 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
365 * Callback for the VERSION responses
366 * @param cookie client identifier
367 * @param text the length of the body
368 * @param textlen the length of the body
370 static protocol_binary_response_status
371 version_response_handler(const void *cookie
, const void *text
, uint32_t textlen
) {
372 memcached_protocol_client_st
*client
= (void *) cookie
;
374 protocol_binary_response_no_extras response
= {
375 .message
.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
376 .opcode
= client
->current_command
->request
.opcode
,
377 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
378 .opaque
= client
->current_command
->request
.opaque
,
379 .bodylen
= htonl(textlen
),
383 protocol_binary_response_status rval
;
384 const protocol_binary_response_status success
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
385 if ((rval
= client
->root
->spool(client
, response
.bytes
, sizeof(response
.bytes
))) != success
386 || (rval
= client
->root
->spool(client
, text
, textlen
)) != success
)
391 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
395 * Callback for ADD and ADDQ
396 * @param cookie the calling client
397 * @param header the add/addq command
398 * @param response_handler not used
399 * @return the result of the operation
401 static protocol_binary_response_status
402 add_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
403 memcached_binary_protocol_raw_response_handler response_handler
) {
404 protocol_binary_response_status rval
;
406 memcached_protocol_client_st
*client
= (void *) cookie
;
407 if (client
->root
->callback
->interface
.v1
.add
!= NULL
) {
408 uint16_t keylen
= ntohs(header
->request
.keylen
);
409 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
410 protocol_binary_request_add
*request
= (void *) header
;
411 uint32_t flags
= ntohl(request
->message
.body
.flags
);
412 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
413 char *key
= ((char *) header
) + sizeof(*header
) + 8;
414 char *data
= key
+ keylen
;
417 rval
= client
->root
->callback
->interface
.v1
.add(cookie
, key
, keylen
, data
, datalen
, flags
,
420 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
421 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_ADD
) {
422 /* Send a positive request */
423 protocol_binary_response_no_extras response
= {
424 .message
= {.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
425 .opcode
= PROTOCOL_BINARY_CMD_ADD
,
426 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
427 .opaque
= header
->request
.opaque
,
428 .cas
= memcached_ntohll(cas
)}}};
429 rval
= response_handler(cookie
, header
, (void *) &response
);
432 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
439 * Callback for DECREMENT and DECREMENTQ
440 * @param cookie the calling client
441 * @param header the command
442 * @param response_handler not used
443 * @return the result of the operation
445 static protocol_binary_response_status
446 decrement_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
447 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
.decrement
!= NULL
) {
453 uint16_t keylen
= ntohs(header
->request
.keylen
);
454 protocol_binary_request_decr
*request
= (void *) header
;
455 uint64_t init
= memcached_ntohll(request
->message
.body
.initial
);
456 uint64_t delta
= memcached_ntohll(request
->message
.body
.delta
);
457 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
458 void *key
= request
->bytes
+ sizeof(request
->bytes
);
462 rval
= client
->root
->callback
->interface
.v1
.decrement(cookie
, key
, keylen
, delta
, init
, timeout
,
464 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
465 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_DECREMENT
)
467 /* Send a positive request */
468 protocol_binary_response_decr response
= {
469 .message
= {.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
470 .opcode
= PROTOCOL_BINARY_CMD_DECREMENT
,
471 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
472 .opaque
= header
->request
.opaque
,
473 .cas
= memcached_ntohll(cas
),
474 .bodylen
= htonl(8)},
475 .body
.value
= memcached_htonll(result
)}};
476 rval
= response_handler(cookie
, header
, (void *) &response
);
479 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
486 * Callback for DELETE and DELETEQ
487 * @param cookie the calling client
488 * @param header the command
489 * @param response_handler not used
490 * @return the result of the operation
492 static protocol_binary_response_status
493 delete_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
494 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
.delete_object
!= NULL
) {
500 uint16_t keylen
= ntohs(header
->request
.keylen
);
501 void *key
= (header
+ 1);
502 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
503 rval
= client
->root
->callback
->interface
.v1
.delete_object(cookie
, key
, keylen
, cas
);
504 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
505 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_DELETE
)
507 /* Send a positive request */
508 protocol_binary_response_no_extras response
= {
509 .message
= {.header
.response
= {
510 .magic
= PROTOCOL_BINARY_RES
,
511 .opcode
= PROTOCOL_BINARY_CMD_DELETE
,
512 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
513 .opaque
= header
->request
.opaque
,
515 rval
= response_handler(cookie
, header
, (void *) &response
);
518 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
525 * Callback for FLUSH and FLUSHQ
526 * @param cookie the calling client
527 * @param header the command
528 * @param response_handler not used
529 * @return the result of the operation
531 static protocol_binary_response_status
532 flush_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
533 memcached_binary_protocol_raw_response_handler response_handler
) {
534 (void) response_handler
;
535 protocol_binary_response_status rval
;
537 memcached_protocol_client_st
*client
= (void *) cookie
;
538 if (client
->root
->callback
->interface
.v1
.flush_object
!= NULL
) {
539 protocol_binary_request_flush
*flush_object
= (void *) header
;
540 uint32_t timeout
= 0;
541 if (htonl(header
->request
.bodylen
) == 4) {
542 timeout
= ntohl(flush_object
->message
.body
.expiration
);
545 rval
= client
->root
->callback
->interface
.v1
.flush_object(cookie
, timeout
);
546 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
547 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_FLUSH
) {
548 /* Send a positive request */
549 protocol_binary_response_no_extras response
= {
550 .message
= {.header
.response
= {
551 .magic
= PROTOCOL_BINARY_RES
,
552 .opcode
= PROTOCOL_BINARY_CMD_FLUSH
,
553 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
554 .opaque
= header
->request
.opaque
,
556 rval
= response_handler(cookie
, header
, (void *) &response
);
559 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
566 * Callback for GET, GETK, GETQ, GETKQ
567 * @param cookie the calling client
568 * @param header the command
569 * @param response_handler not used
570 * @return the result of the operation
572 static protocol_binary_response_status
573 get_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
574 memcached_binary_protocol_raw_response_handler response_handler
) {
575 (void) response_handler
;
576 protocol_binary_response_status rval
;
578 memcached_protocol_client_st
*client
= (void *) cookie
;
579 if (client
->root
->callback
->interface
.v1
.get
!= NULL
) {
580 uint16_t keylen
= ntohs(header
->request
.keylen
);
581 void *key
= (header
+ 1);
582 rval
= client
->root
->callback
->interface
.v1
.get(cookie
, key
, keylen
, get_response_handler
);
584 if (rval
== PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
585 && (header
->request
.opcode
== PROTOCOL_BINARY_CMD_GETQ
586 || header
->request
.opcode
== PROTOCOL_BINARY_CMD_GETKQ
))
588 /* Quiet commands shouldn't respond on cache misses */
589 rval
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
592 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
599 * Callback for INCREMENT and INCREMENTQ
600 * @param cookie the calling client
601 * @param header the command
602 * @param response_handler not used
603 * @return the result of the operation
605 static protocol_binary_response_status
606 increment_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
607 memcached_binary_protocol_raw_response_handler response_handler
) {
608 (void) response_handler
;
609 protocol_binary_response_status rval
;
611 memcached_protocol_client_st
*client
= (void *) cookie
;
612 if (client
->root
->callback
->interface
.v1
.increment
!= NULL
) {
613 uint16_t keylen
= ntohs(header
->request
.keylen
);
614 protocol_binary_request_incr
*request
= (void *) header
;
615 uint64_t init
= memcached_ntohll(request
->message
.body
.initial
);
616 uint64_t delta
= memcached_ntohll(request
->message
.body
.delta
);
617 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
618 void *key
= request
->bytes
+ sizeof(request
->bytes
);
622 rval
= client
->root
->callback
->interface
.v1
.increment(cookie
, key
, keylen
, delta
, init
, timeout
,
624 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
625 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_INCREMENT
)
627 /* Send a positive request */
628 protocol_binary_response_incr response
= {
629 .message
= {.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
630 .opcode
= PROTOCOL_BINARY_CMD_INCREMENT
,
631 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
632 .opaque
= header
->request
.opaque
,
633 .cas
= memcached_ntohll(cas
),
634 .bodylen
= htonl(8)},
635 .body
.value
= memcached_htonll(result
)}};
637 rval
= response_handler(cookie
, header
, (void *) &response
);
640 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
647 * Callback for noop. Inform the v1 interface about the noop packet, and
648 * create and send a packet back to the client
650 * @param cookie the calling client
651 * @param header the command
652 * @param response_handler the response handler
653 * @return the result of the operation
655 static protocol_binary_response_status
656 noop_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
657 memcached_binary_protocol_raw_response_handler response_handler
) {
658 memcached_protocol_client_st
*client
= (void *) cookie
;
659 if (client
->root
->callback
->interface
.v1
.noop
!= NULL
) {
660 client
->root
->callback
->interface
.v1
.noop(cookie
);
663 protocol_binary_response_no_extras response
= {
664 .message
= {.header
.response
= {
665 .magic
= PROTOCOL_BINARY_RES
,
666 .opcode
= PROTOCOL_BINARY_CMD_NOOP
,
667 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
668 .opaque
= header
->request
.opaque
,
671 return response_handler(cookie
, header
, (void *) &response
);
675 * Callback for APPEND and APPENDQ
676 * @param cookie the calling client
677 * @param header the command
678 * @param response_handler not used
679 * @return the result of the operation
681 static protocol_binary_response_status
682 append_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
683 memcached_binary_protocol_raw_response_handler response_handler
) {
684 (void) response_handler
;
685 protocol_binary_response_status rval
;
687 memcached_protocol_client_st
*client
= (void *) cookie
;
688 if (client
->root
->callback
->interface
.v1
.append
!= NULL
) {
689 uint16_t keylen
= ntohs(header
->request
.keylen
);
690 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
;
691 char *key
= (void *) (header
+ 1);
692 char *data
= key
+ keylen
;
693 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
696 rval
= client
->root
->callback
->interface
.v1
.append(cookie
, key
, keylen
, data
, datalen
, cas
,
698 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
699 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_APPEND
)
701 /* Send a positive request */
702 protocol_binary_response_no_extras response
= {
706 .magic
= PROTOCOL_BINARY_RES
,
707 .opcode
= PROTOCOL_BINARY_CMD_APPEND
,
708 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
709 .opaque
= header
->request
.opaque
,
710 .cas
= memcached_ntohll(result_cas
),
713 rval
= response_handler(cookie
, header
, (void *) &response
);
716 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
723 * Callback for PREPEND and PREPENDQ
724 * @param cookie the calling client
725 * @param header the command
726 * @param response_handler not used
727 * @return the result of the operation
729 static protocol_binary_response_status
730 prepend_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
731 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
) {
737 uint16_t keylen
= ntohs(header
->request
.keylen
);
738 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
;
739 char *key
= (char *) (header
+ 1);
740 char *data
= key
+ keylen
;
741 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
743 rval
= client
->root
->callback
->interface
.v1
.prepend(cookie
, key
, keylen
, data
, datalen
, cas
,
745 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
746 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_PREPEND
)
748 /* Send a positive request */
749 protocol_binary_response_no_extras response
= {
753 .magic
= PROTOCOL_BINARY_RES
,
754 .opcode
= PROTOCOL_BINARY_CMD_PREPEND
,
755 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
756 .opaque
= header
->request
.opaque
,
757 .cas
= memcached_ntohll(result_cas
),
760 rval
= response_handler(cookie
, header
, (void *) &response
);
763 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
770 * Callback for QUIT and QUITQ. Notify the client and shut down the connection
771 * @param cookie the calling client
772 * @param header the command
773 * @param response_handler not used
774 * @return the result of the operation
776 static protocol_binary_response_status
777 quit_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
778 memcached_binary_protocol_raw_response_handler response_handler
) {
779 memcached_protocol_client_st
*client
= (void *) cookie
;
780 if (client
->root
->callback
->interface
.v1
.quit
!= NULL
) {
781 client
->root
->callback
->interface
.v1
.quit(cookie
);
784 protocol_binary_response_no_extras response
= {
785 .message
= {.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
786 .opcode
= PROTOCOL_BINARY_CMD_QUIT
,
787 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
788 .opaque
= header
->request
.opaque
}}};
790 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_QUIT
) {
791 response_handler(cookie
, header
, (void *) &response
);
794 /* I need a better way to signal to close the connection */
795 return PROTOCOL_BINARY_RESPONSE_EINTERNAL
;
799 * Callback for REPLACE and REPLACEQ
800 * @param cookie the calling client
801 * @param header the command
802 * @param response_handler not used
803 * @return the result of the operation
805 static protocol_binary_response_status
806 replace_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
807 memcached_binary_protocol_raw_response_handler response_handler
) {
808 (void) response_handler
;
809 protocol_binary_response_status rval
;
811 memcached_protocol_client_st
*client
= (void *) cookie
;
812 if (client
->root
->callback
->interface
.v1
.replace
!= NULL
) {
813 uint16_t keylen
= ntohs(header
->request
.keylen
);
814 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
815 protocol_binary_request_replace
*request
= (void *) header
;
816 uint32_t flags
= ntohl(request
->message
.body
.flags
);
817 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
818 char *key
= ((char *) header
) + sizeof(*header
) + 8;
819 char *data
= key
+ keylen
;
820 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
823 rval
= client
->root
->callback
->interface
.v1
.replace(cookie
, key
, keylen
, data
, datalen
, flags
,
824 timeout
, cas
, &result_cas
);
825 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
826 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_REPLACE
)
828 /* Send a positive request */
829 protocol_binary_response_no_extras response
= {
833 .magic
= PROTOCOL_BINARY_RES
,
834 .opcode
= PROTOCOL_BINARY_CMD_REPLACE
,
835 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
836 .opaque
= header
->request
.opaque
,
837 .cas
= memcached_ntohll(result_cas
),
840 rval
= response_handler(cookie
, header
, (void *) &response
);
843 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
850 * Callback for SET and SETQ
851 * @param cookie the calling client
852 * @param header the command
853 * @param response_handler not used
854 * @return the result of the operation
856 static protocol_binary_response_status
857 set_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
858 memcached_binary_protocol_raw_response_handler response_handler
) {
859 (void) response_handler
;
860 protocol_binary_response_status rval
;
862 memcached_protocol_client_st
*client
= (void *) cookie
;
863 if (client
->root
->callback
->interface
.v1
.set
!= NULL
) {
864 uint16_t keylen
= ntohs(header
->request
.keylen
);
865 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
866 protocol_binary_request_replace
*request
= (void *) header
;
867 uint32_t flags
= ntohl(request
->message
.body
.flags
);
868 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
869 char *key
= ((char *) header
) + sizeof(*header
) + 8;
870 char *data
= key
+ keylen
;
871 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
874 rval
= client
->root
->callback
->interface
.v1
.set(cookie
, key
, keylen
, data
, datalen
, flags
,
875 timeout
, cas
, &result_cas
);
876 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
877 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_SET
) {
878 /* Send a positive request */
879 protocol_binary_response_no_extras response
= {
883 .magic
= PROTOCOL_BINARY_RES
,
884 .opcode
= PROTOCOL_BINARY_CMD_SET
,
885 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
886 .opaque
= header
->request
.opaque
,
887 .cas
= memcached_ntohll(result_cas
),
890 rval
= response_handler(cookie
, header
, (void *) &response
);
893 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
901 * @param cookie the calling client
902 * @param header the command
903 * @param response_handler not used
904 * @return the result of the operation
906 static protocol_binary_response_status
907 stat_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
908 memcached_binary_protocol_raw_response_handler response_handler
) {
909 (void) response_handler
;
910 protocol_binary_response_status rval
;
912 memcached_protocol_client_st
*client
= (void *) cookie
;
913 if (client
->root
->callback
->interface
.v1
.stat
!= NULL
) {
914 uint16_t keylen
= ntohs(header
->request
.keylen
);
916 rval
= client
->root
->callback
->interface
.v1
.stat(cookie
, (void *) (header
+ 1), keylen
,
917 stat_response_handler
);
919 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
926 * Callback for VERSION
927 * @param cookie the calling client
928 * @param header the command
929 * @param response_handler not used
930 * @return the result of the operation
932 static protocol_binary_response_status
933 version_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
934 memcached_binary_protocol_raw_response_handler response_handler
) {
935 (void) response_handler
;
937 protocol_binary_response_status rval
;
939 memcached_protocol_client_st
*client
= (void *) cookie
;
940 if (client
->root
->callback
->interface
.v1
.version
!= NULL
) {
941 rval
= client
->root
->callback
->interface
.v1
.version(cookie
, version_response_handler
);
943 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
950 * The map to remap between the com codes and the v1 logical setting
952 static memcached_binary_protocol_command_handler comcode_v0_v1_remap
[256] = {
953 [PROTOCOL_BINARY_CMD_ADDQ
] = add_command_handler
,
954 [PROTOCOL_BINARY_CMD_ADD
] = add_command_handler
,
955 [PROTOCOL_BINARY_CMD_APPENDQ
] = append_command_handler
,
956 [PROTOCOL_BINARY_CMD_APPEND
] = append_command_handler
,
957 [PROTOCOL_BINARY_CMD_DECREMENTQ
] = decrement_command_handler
,
958 [PROTOCOL_BINARY_CMD_DECREMENT
] = decrement_command_handler
,
959 [PROTOCOL_BINARY_CMD_DELETEQ
] = delete_command_handler
,
960 [PROTOCOL_BINARY_CMD_DELETE
] = delete_command_handler
,
961 [PROTOCOL_BINARY_CMD_FLUSHQ
] = flush_command_handler
,
962 [PROTOCOL_BINARY_CMD_FLUSH
] = flush_command_handler
,
963 [PROTOCOL_BINARY_CMD_GETKQ
] = get_command_handler
,
964 [PROTOCOL_BINARY_CMD_GETK
] = get_command_handler
,
965 [PROTOCOL_BINARY_CMD_GETQ
] = get_command_handler
,
966 [PROTOCOL_BINARY_CMD_GET
] = get_command_handler
,
967 [PROTOCOL_BINARY_CMD_INCREMENTQ
] = increment_command_handler
,
968 [PROTOCOL_BINARY_CMD_INCREMENT
] = increment_command_handler
,
969 [PROTOCOL_BINARY_CMD_NOOP
] = noop_command_handler
,
970 [PROTOCOL_BINARY_CMD_PREPENDQ
] = prepend_command_handler
,
971 [PROTOCOL_BINARY_CMD_PREPEND
] = prepend_command_handler
,
972 [PROTOCOL_BINARY_CMD_QUITQ
] = quit_command_handler
,
973 [PROTOCOL_BINARY_CMD_QUIT
] = quit_command_handler
,
974 [PROTOCOL_BINARY_CMD_REPLACEQ
] = replace_command_handler
,
975 [PROTOCOL_BINARY_CMD_REPLACE
] = replace_command_handler
,
976 [PROTOCOL_BINARY_CMD_SETQ
] = set_command_handler
,
977 [PROTOCOL_BINARY_CMD_SET
] = set_command_handler
,
978 [PROTOCOL_BINARY_CMD_STAT
] = stat_command_handler
,
979 [PROTOCOL_BINARY_CMD_VERSION
] = version_command_handler
,
983 * Try to execute a command. Fire the pre/post functions and the specialized
984 * handler function if it's set. If not, the unknown probe should be fired
986 * @param client the client connection to operate on
987 * @param header the command to execute
988 * @return true if success or false if a fatal error occured so that the
989 * connection should be shut down.
991 static protocol_binary_response_status
execute_command(memcached_protocol_client_st
*client
,
992 protocol_binary_request_header
*header
) {
993 if (client
->root
->pedantic
&& memcached_binary_protocol_pedantic_check_request(header
)) {
994 /* @todo return invalid command packet */
997 /* we got all data available, execute the callback! */
998 if (client
->root
->callback
->pre_execute
!= NULL
) {
999 client
->root
->callback
->pre_execute(client
, header
);
1002 protocol_binary_response_status rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
1003 uint8_t cc
= header
->request
.opcode
;
1005 if (client
->is_verbose
) {
1009 switch (client
->root
->callback
->interface_version
) {
1011 if (client
->root
->callback
->interface
.v0
.comcode
[cc
] != NULL
) {
1012 rval
= client
->root
->callback
->interface
.v0
.comcode
[cc
](client
, header
,
1013 binary_raw_response_handler
);
1018 if (comcode_v0_v1_remap
[cc
] != NULL
) {
1019 rval
= comcode_v0_v1_remap
[cc
](client
, header
, binary_raw_response_handler
);
1024 /* Unknown interface.
1025 * It should be impossible to get here so I'll just call abort
1026 * to avoid getting a compiler warning :-)
1031 if (rval
== PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
&& client
->root
->callback
->unknown
!= NULL
) {
1032 rval
= client
->root
->callback
->unknown(client
, header
, binary_raw_response_handler
);
1035 if (rval
!= PROTOCOL_BINARY_RESPONSE_SUCCESS
&& rval
!= PROTOCOL_BINARY_RESPONSE_EINTERNAL
1036 && rval
!= PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED
)
1038 protocol_binary_response_no_extras response
= {.message
= {
1041 .magic
= PROTOCOL_BINARY_RES
,
1043 .status
= htons(rval
),
1044 .opaque
= header
->request
.opaque
,
1047 rval
= binary_raw_response_handler(client
, header
, (void *) &response
);
1050 if (client
->root
->callback
->post_execute
!= NULL
) {
1051 client
->root
->callback
->post_execute(client
, header
);
1058 ** **********************************************************************
1059 ** "PROTOECTED" INTERFACE
1060 ** **********************************************************************
1062 memcached_protocol_event_t
1063 memcached_binary_protocol_process_data(memcached_protocol_client_st
*client
, ssize_t
*length
,
1065 /* try to parse all of the received packets */
1066 protocol_binary_request_header
*header
;
1067 header
= (void *) client
->root
->input_buffer
;
1068 if (header
->request
.magic
!= (uint8_t) PROTOCOL_BINARY_REQ
) {
1069 client
->error
= EINVAL
;
1070 return MEMCACHED_PROTOCOL_ERROR_EVENT
;
1072 ssize_t len
= *length
;
1074 while (len
>= (ssize_t
) sizeof(*header
)
1075 && (len
>= (ssize_t
)(sizeof(*header
) + ntohl(header
->request
.bodylen
))))
1077 /* I have the complete package */
1078 client
->current_command
= header
;
1079 protocol_binary_response_status rv
= execute_command(client
, header
);
1081 if (rv
== PROTOCOL_BINARY_RESPONSE_EINTERNAL
) {
1083 *endptr
= (void *) header
;
1084 return MEMCACHED_PROTOCOL_ERROR_EVENT
;
1085 } else if (rv
== PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED
) {
1086 return MEMCACHED_PROTOCOL_PAUSE_EVENT
;
1089 ssize_t total
= (ssize_t
)(sizeof(*header
) + ntohl(header
->request
.bodylen
));
1092 intptr_t ptr
= (intptr_t) header
;
1094 if ((ptr
% 8) == 0) {
1095 header
= (void *) ptr
;
1098 memmove(client
->root
->input_buffer
, (void *) ptr
, (size_t) len
);
1099 header
= (void *) client
->root
->input_buffer
;
1103 *endptr
= (void *) header
;
1106 return MEMCACHED_PROTOCOL_READ_EVENT
;
1110 ** **********************************************************************
1112 ** **********************************************************************
1114 memcached_binary_protocol_callback_st
*
1115 memcached_binary_protocol_get_callbacks(memcached_protocol_st
*instance
) {
1116 return instance
->callback
;
1119 void memcached_binary_protocol_set_callbacks(memcached_protocol_st
*instance
,
1120 memcached_binary_protocol_callback_st
*callback
) {
1121 instance
->callback
= callback
;
1124 memcached_binary_protocol_raw_response_handler
1125 memcached_binary_protocol_get_raw_response_handler(const void *cookie
) {
1127 return binary_raw_response_handler
;
1130 void memcached_binary_protocol_set_pedantic(memcached_protocol_st
*instance
, bool enable
) {
1131 instance
->pedantic
= enable
;
1134 bool memcached_binary_protocol_get_pedantic(memcached_protocol_st
*instance
) {
1135 return instance
->pedantic
;