2 +--------------------------------------------------------------------+
3 | libmemcached-awesome - 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-2021 Michael Wallner https://awesome.co/ |
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 (response
&& 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
;
57 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
60 size_t len
= sizeof(protocol_binary_response_header
) + htonl(response
->response
.bodylen
);
62 char *ptr
= (void *) response
;
64 if (client
->output
== NULL
) {
65 /* I can write directly to the socket.... */
67 size_t num_bytes
= len
- offset
;
68 ssize_t nw
= client
->root
->send(client
, client
->sock
, ptr
+ offset
, num_bytes
);
70 if (get_socket_errno() == EWOULDBLOCK
) {
72 } else if (get_socket_errno() != EINTR
) {
73 client
->error
= errno
;
74 return PROTOCOL_BINARY_RESPONSE_EINTERNAL
;
77 offset
+= (size_t) nw
;
79 } while (offset
< len
);
82 return client
->root
->spool(client
, ptr
, len
- offset
);
85 static void print_cmd(protocol_binary_command cmd
) {
87 case PROTOCOL_BINARY_CMD_GET
:
88 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GET\n", __FILE__
, __LINE__
);
90 case PROTOCOL_BINARY_CMD_SET
:
91 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SET\n", __FILE__
, __LINE__
);
93 case PROTOCOL_BINARY_CMD_ADD
:
94 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_ADD\n", __FILE__
, __LINE__
);
96 case PROTOCOL_BINARY_CMD_REPLACE
:
97 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_REPLACE\n", __FILE__
, __LINE__
);
99 case PROTOCOL_BINARY_CMD_DELETE
:
100 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DELETE\n", __FILE__
, __LINE__
);
102 case PROTOCOL_BINARY_CMD_INCREMENT
:
103 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_INCREMENT\n", __FILE__
, __LINE__
);
105 case PROTOCOL_BINARY_CMD_DECREMENT
:
106 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DECREMENT\n", __FILE__
, __LINE__
);
108 case PROTOCOL_BINARY_CMD_QUIT
:
109 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_QUIT\n", __FILE__
, __LINE__
);
111 case PROTOCOL_BINARY_CMD_FLUSH
:
112 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_FLUSH\n", __FILE__
, __LINE__
);
114 case PROTOCOL_BINARY_CMD_GETQ
:
115 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GETQ\n", __FILE__
, __LINE__
);
117 case PROTOCOL_BINARY_CMD_NOOP
:
118 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_NOOP\n", __FILE__
, __LINE__
);
120 case PROTOCOL_BINARY_CMD_VERSION
:
121 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_VERSION\n", __FILE__
, __LINE__
);
123 case PROTOCOL_BINARY_CMD_GETK
:
124 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GETK\n", __FILE__
, __LINE__
);
126 case PROTOCOL_BINARY_CMD_GETKQ
:
127 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GETKQ\n", __FILE__
, __LINE__
);
129 case PROTOCOL_BINARY_CMD_APPEND
:
130 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_APPEND\n", __FILE__
, __LINE__
);
132 case PROTOCOL_BINARY_CMD_PREPEND
:
133 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_PREPEND\n", __FILE__
, __LINE__
);
135 case PROTOCOL_BINARY_CMD_STAT
:
136 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_STAT\n", __FILE__
, __LINE__
);
138 case PROTOCOL_BINARY_CMD_SETQ
:
139 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SETQ\n", __FILE__
, __LINE__
);
141 case PROTOCOL_BINARY_CMD_ADDQ
:
142 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_ADDQ\n", __FILE__
, __LINE__
);
144 case PROTOCOL_BINARY_CMD_REPLACEQ
:
145 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_REPLACEQ\n", __FILE__
, __LINE__
);
147 case PROTOCOL_BINARY_CMD_DELETEQ
:
148 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DELETEQ\n", __FILE__
, __LINE__
);
150 case PROTOCOL_BINARY_CMD_INCREMENTQ
:
151 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_INCREMENTQ\n", __FILE__
, __LINE__
);
153 case PROTOCOL_BINARY_CMD_DECREMENTQ
:
154 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DECREMENTQ\n", __FILE__
, __LINE__
);
156 case PROTOCOL_BINARY_CMD_QUITQ
:
157 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_QUITQ\n", __FILE__
, __LINE__
);
159 case PROTOCOL_BINARY_CMD_FLUSHQ
:
160 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_FLUSHQ\n", __FILE__
, __LINE__
);
162 case PROTOCOL_BINARY_CMD_APPENDQ
:
163 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_APPENDQ\n", __FILE__
, __LINE__
);
165 case PROTOCOL_BINARY_CMD_PREPENDQ
:
166 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_PREPENDQ\n", __FILE__
, __LINE__
);
168 case PROTOCOL_BINARY_CMD_VERBOSITY
:
169 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_VERBOSITY\n", __FILE__
, __LINE__
);
171 case PROTOCOL_BINARY_CMD_TOUCH
:
172 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TOUCH\n", __FILE__
, __LINE__
);
174 case PROTOCOL_BINARY_CMD_GAT
:
175 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GAT\n", __FILE__
, __LINE__
);
177 case PROTOCOL_BINARY_CMD_GATQ
:
178 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GATQ\n", __FILE__
, __LINE__
);
180 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
181 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SASL_LIST_MECHS\n", __FILE__
, __LINE__
);
183 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
184 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SASL_AUTH\n", __FILE__
, __LINE__
);
186 case PROTOCOL_BINARY_CMD_SASL_STEP
:
187 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SASL_STEP\n", __FILE__
, __LINE__
);
189 case PROTOCOL_BINARY_CMD_RGET
:
190 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RGET\n", __FILE__
, __LINE__
);
192 case PROTOCOL_BINARY_CMD_RSET
:
193 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RSET\n", __FILE__
, __LINE__
);
195 case PROTOCOL_BINARY_CMD_RSETQ
:
196 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RSETQ\n", __FILE__
, __LINE__
);
198 case PROTOCOL_BINARY_CMD_RAPPEND
:
199 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RAPPEND\n", __FILE__
, __LINE__
);
201 case PROTOCOL_BINARY_CMD_RAPPENDQ
:
202 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RAPPENDQ\n", __FILE__
, __LINE__
);
204 case PROTOCOL_BINARY_CMD_RPREPEND
:
205 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RPREPEND\n", __FILE__
, __LINE__
);
207 case PROTOCOL_BINARY_CMD_RPREPENDQ
:
208 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RPREPENDQ\n", __FILE__
, __LINE__
);
210 case PROTOCOL_BINARY_CMD_RDELETE
:
211 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDELETE\n", __FILE__
, __LINE__
);
213 case PROTOCOL_BINARY_CMD_RDELETEQ
:
214 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDELETEQ\n", __FILE__
, __LINE__
);
216 case PROTOCOL_BINARY_CMD_RINCR
:
217 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RINCR\n", __FILE__
, __LINE__
);
219 case PROTOCOL_BINARY_CMD_RINCRQ
:
220 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RINCRQ\n", __FILE__
, __LINE__
);
222 case PROTOCOL_BINARY_CMD_RDECR
:
223 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDECR\n", __FILE__
, __LINE__
);
225 case PROTOCOL_BINARY_CMD_RDECRQ
:
226 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDECRQ\n", __FILE__
, __LINE__
);
228 case PROTOCOL_BINARY_CMD_SET_VBUCKET
:
229 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SET_VBUCKET\n", __FILE__
, __LINE__
);
231 case PROTOCOL_BINARY_CMD_GET_VBUCKET
:
232 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GET_VBUCKET\n", __FILE__
, __LINE__
);
234 case PROTOCOL_BINARY_CMD_DEL_VBUCKET
:
235 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DEL_VBUCKET\n", __FILE__
, __LINE__
);
237 case PROTOCOL_BINARY_CMD_TAP_CONNECT
:
238 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_CONNECT\n", __FILE__
, __LINE__
);
240 case PROTOCOL_BINARY_CMD_TAP_MUTATION
:
241 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_MUTATION\n", __FILE__
, __LINE__
);
243 case PROTOCOL_BINARY_CMD_TAP_DELETE
:
244 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_DELETE\n", __FILE__
, __LINE__
);
246 case PROTOCOL_BINARY_CMD_TAP_FLUSH
:
247 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_FLUSH\n", __FILE__
, __LINE__
);
249 case PROTOCOL_BINARY_CMD_TAP_OPAQUE
:
250 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_OPAQUE\n", __FILE__
, __LINE__
);
252 case PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET
:
253 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET\n", __FILE__
, __LINE__
);
255 case PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START
:
256 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START\n", __FILE__
, __LINE__
);
258 case PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END
:
259 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END\n", __FILE__
, __LINE__
);
261 case PROTOCOL_BINARY_CMD_LAST_RESERVED
:
262 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_LAST_RESERVED\n", __FILE__
, __LINE__
);
264 case PROTOCOL_BINARY_CMD_GATK
:
265 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GATK\n", __FILE__
, __LINE__
);
267 case PROTOCOL_BINARY_CMD_GATKQ
:
268 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GATKQ\n", __FILE__
, __LINE__
);
270 case PROTOCOL_BINARY_CMD_SCRUB
:
271 fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SCRUB\n", __FILE__
, __LINE__
);
279 * Version 0 of the interface is really low level and protocol specific,
280 * while the version 1 of the interface is more API focused. We need a
281 * way to translate between the command codes on the wire and the
282 * application level interface in V1, so let's just use the V0 of the
283 * interface as a map instead of creating a huuuge switch :-)
287 * Callback for the GET/GETQ/GETK and GETKQ responses
288 * @param cookie client identifier
289 * @param key the key for the item
290 * @param keylen the length of the key
291 * @param body the length of the body
292 * @param bodylen the length of the body
293 * @param flags the flags for the item
294 * @param cas the CAS id for the item
296 static protocol_binary_response_status
get_response_handler(const void *cookie
, const void *key
,
297 uint16_t keylen
, const void *body
,
298 uint32_t bodylen
, uint32_t flags
,
300 memcached_protocol_client_st
*client
= (void *) cookie
;
301 uint8_t opcode
= client
->current_command
->request
.opcode
;
303 if (opcode
== PROTOCOL_BINARY_CMD_GET
|| opcode
== PROTOCOL_BINARY_CMD_GETQ
) {
307 protocol_binary_response_get response
= {
308 .message
.header
.response
=
310 .magic
= PROTOCOL_BINARY_RES
,
312 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
313 .opaque
= client
->current_command
->request
.opaque
,
314 .cas
= memcached_htonll(cas
),
315 .keylen
= htons(keylen
),
317 .bodylen
= htonl(bodylen
+ keylen
+ 4),
321 response
.message
.body
.flags
= htonl(flags
);
323 protocol_binary_response_status rval
;
324 const protocol_binary_response_status success
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
325 if ((rval
= client
->root
->spool(client
, response
.bytes
, sizeof(response
.bytes
))) != success
326 || (rval
= client
->root
->spool(client
, key
, keylen
)) != success
327 || (rval
= client
->root
->spool(client
, body
, bodylen
)) != success
)
332 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
336 * Callback for the STAT responses
337 * @param cookie client identifier
338 * @param key the key for the item
339 * @param keylen the length of the key
340 * @param body the length of the body
341 * @param bodylen the length of the body
343 static protocol_binary_response_status
stat_response_handler(const void *cookie
, const void *key
,
344 uint16_t keylen
, const void *body
,
346 memcached_protocol_client_st
*client
= (void *) cookie
;
348 protocol_binary_response_no_extras response
= {
349 .message
.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
350 .opcode
= client
->current_command
->request
.opcode
,
351 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
352 .opaque
= client
->current_command
->request
.opaque
,
353 .keylen
= htons(keylen
),
354 .bodylen
= htonl(bodylen
+ keylen
),
358 protocol_binary_response_status rval
;
359 const protocol_binary_response_status success
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
360 if ((rval
= client
->root
->spool(client
, response
.bytes
, sizeof(response
.bytes
))) != success
361 || (rval
= client
->root
->spool(client
, key
, keylen
)) != success
362 || (rval
= client
->root
->spool(client
, body
, bodylen
)) != success
)
367 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
371 * Callback for the VERSION responses
372 * @param cookie client identifier
373 * @param text the length of the body
374 * @param textlen the length of the body
376 static protocol_binary_response_status
377 version_response_handler(const void *cookie
, const void *text
, uint32_t textlen
) {
378 memcached_protocol_client_st
*client
= (void *) cookie
;
380 protocol_binary_response_no_extras response
= {
381 .message
.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
382 .opcode
= client
->current_command
->request
.opcode
,
383 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
384 .opaque
= client
->current_command
->request
.opaque
,
385 .bodylen
= htonl(textlen
),
389 protocol_binary_response_status rval
;
390 const protocol_binary_response_status success
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
391 if ((rval
= client
->root
->spool(client
, response
.bytes
, sizeof(response
.bytes
))) != success
392 || (rval
= client
->root
->spool(client
, text
, textlen
)) != success
)
397 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
401 * Callback for ADD and ADDQ
402 * @param cookie the calling client
403 * @param header the add/addq command
404 * @param response_handler not used
405 * @return the result of the operation
407 static protocol_binary_response_status
408 add_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
409 memcached_binary_protocol_raw_response_handler response_handler
) {
410 protocol_binary_response_status rval
;
412 memcached_protocol_client_st
*client
= (void *) cookie
;
413 if (client
->root
->callback
->interface
.v1
.add
) {
414 uint16_t keylen
= ntohs(header
->request
.keylen
);
415 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
416 protocol_binary_request_add
*request
= (void *) header
;
417 uint32_t flags
= ntohl(request
->message
.body
.flags
);
418 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
419 char *key
= ((char *) header
) + sizeof(*header
) + 8;
420 char *data
= key
+ keylen
;
423 rval
= client
->root
->callback
->interface
.v1
.add(cookie
, key
, keylen
, data
, datalen
, flags
,
426 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
427 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_ADD
) {
428 /* Send a positive request */
429 protocol_binary_response_no_extras response
= {
430 .message
= {.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
431 .opcode
= PROTOCOL_BINARY_CMD_ADD
,
432 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
433 .opaque
= header
->request
.opaque
,
434 .cas
= memcached_ntohll(cas
)}}};
435 rval
= response_handler(cookie
, header
, (void *) &response
);
438 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
445 * Callback for DECREMENT and DECREMENTQ
446 * @param cookie the calling client
447 * @param header the command
448 * @param response_handler not used
449 * @return the result of the operation
451 static protocol_binary_response_status
452 decrement_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
453 memcached_binary_protocol_raw_response_handler response_handler
) {
454 (void) response_handler
;
455 protocol_binary_response_status rval
;
457 memcached_protocol_client_st
*client
= (void *) cookie
;
458 if (client
->root
->callback
->interface
.v1
.decrement
) {
459 uint16_t keylen
= ntohs(header
->request
.keylen
);
460 protocol_binary_request_decr
*request
= (void *) header
;
461 uint64_t init
= memcached_ntohll(request
->message
.body
.initial
);
462 uint64_t delta
= memcached_ntohll(request
->message
.body
.delta
);
463 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
464 void *key
= request
->bytes
+ sizeof(request
->bytes
);
468 rval
= client
->root
->callback
->interface
.v1
.decrement(cookie
, key
, keylen
, delta
, init
, timeout
,
470 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
471 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_DECREMENT
)
473 /* Send a positive request */
474 protocol_binary_response_decr response
= {
475 .message
= {.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
476 .opcode
= PROTOCOL_BINARY_CMD_DECREMENT
,
477 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
478 .opaque
= header
->request
.opaque
,
479 .cas
= memcached_ntohll(cas
),
480 .bodylen
= htonl(8)},
481 .body
.value
= memcached_htonll(result
)}};
482 rval
= response_handler(cookie
, header
, (void *) &response
);
485 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
492 * Callback for DELETE and DELETEQ
493 * @param cookie the calling client
494 * @param header the command
495 * @param response_handler not used
496 * @return the result of the operation
498 static protocol_binary_response_status
499 delete_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
500 memcached_binary_protocol_raw_response_handler response_handler
) {
501 (void) response_handler
;
502 protocol_binary_response_status rval
;
504 memcached_protocol_client_st
*client
= (void *) cookie
;
505 if (client
->root
->callback
->interface
.v1
.delete_object
) {
506 uint16_t keylen
= ntohs(header
->request
.keylen
);
507 void *key
= (header
+ 1);
508 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
509 rval
= client
->root
->callback
->interface
.v1
.delete_object(cookie
, key
, keylen
, cas
);
510 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
511 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_DELETE
)
513 /* Send a positive request */
514 protocol_binary_response_no_extras response
= {
515 .message
= {.header
.response
= {
516 .magic
= PROTOCOL_BINARY_RES
,
517 .opcode
= PROTOCOL_BINARY_CMD_DELETE
,
518 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
519 .opaque
= header
->request
.opaque
,
521 rval
= response_handler(cookie
, header
, (void *) &response
);
524 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
531 * Callback for FLUSH and FLUSHQ
532 * @param cookie the calling client
533 * @param header the command
534 * @param response_handler not used
535 * @return the result of the operation
537 static protocol_binary_response_status
538 flush_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
539 memcached_binary_protocol_raw_response_handler response_handler
) {
540 (void) response_handler
;
541 protocol_binary_response_status rval
;
543 memcached_protocol_client_st
*client
= (void *) cookie
;
544 if (client
->root
->callback
->interface
.v1
.flush_object
) {
545 protocol_binary_request_flush
*flush_object
= (void *) header
;
546 uint32_t timeout
= 0;
547 if (htonl(header
->request
.bodylen
) == 4) {
548 timeout
= ntohl(flush_object
->message
.body
.expiration
);
551 rval
= client
->root
->callback
->interface
.v1
.flush_object(cookie
, timeout
);
552 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
553 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_FLUSH
) {
554 /* Send a positive request */
555 protocol_binary_response_no_extras response
= {
556 .message
= {.header
.response
= {
557 .magic
= PROTOCOL_BINARY_RES
,
558 .opcode
= PROTOCOL_BINARY_CMD_FLUSH
,
559 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
560 .opaque
= header
->request
.opaque
,
562 rval
= response_handler(cookie
, header
, (void *) &response
);
565 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
572 * Callback for GET, GETK, GETQ, GETKQ
573 * @param cookie the calling client
574 * @param header the command
575 * @param response_handler not used
576 * @return the result of the operation
578 static protocol_binary_response_status
579 get_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
580 memcached_binary_protocol_raw_response_handler response_handler
) {
581 (void) response_handler
;
582 protocol_binary_response_status rval
;
584 memcached_protocol_client_st
*client
= (void *) cookie
;
585 if (client
->root
->callback
->interface
.v1
.get
) {
586 uint16_t keylen
= ntohs(header
->request
.keylen
);
587 void *key
= (header
+ 1);
588 rval
= client
->root
->callback
->interface
.v1
.get(cookie
, key
, keylen
, get_response_handler
);
590 if (rval
== PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
591 && (header
->request
.opcode
== PROTOCOL_BINARY_CMD_GETQ
592 || header
->request
.opcode
== PROTOCOL_BINARY_CMD_GETKQ
))
594 /* Quiet commands shouldn't respond on cache misses */
595 rval
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
598 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
605 * Callback for INCREMENT and INCREMENTQ
606 * @param cookie the calling client
607 * @param header the command
608 * @param response_handler not used
609 * @return the result of the operation
611 static protocol_binary_response_status
612 increment_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
613 memcached_binary_protocol_raw_response_handler response_handler
) {
614 (void) response_handler
;
615 protocol_binary_response_status rval
;
617 memcached_protocol_client_st
*client
= (void *) cookie
;
618 if (client
->root
->callback
->interface
.v1
.increment
) {
619 uint16_t keylen
= ntohs(header
->request
.keylen
);
620 protocol_binary_request_incr
*request
= (void *) header
;
621 uint64_t init
= memcached_ntohll(request
->message
.body
.initial
);
622 uint64_t delta
= memcached_ntohll(request
->message
.body
.delta
);
623 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
624 void *key
= request
->bytes
+ sizeof(request
->bytes
);
628 rval
= client
->root
->callback
->interface
.v1
.increment(cookie
, key
, keylen
, delta
, init
, timeout
,
630 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
631 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_INCREMENT
)
633 /* Send a positive request */
634 protocol_binary_response_incr response
= {
635 .message
= {.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
636 .opcode
= PROTOCOL_BINARY_CMD_INCREMENT
,
637 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
638 .opaque
= header
->request
.opaque
,
639 .cas
= memcached_ntohll(cas
),
640 .bodylen
= htonl(8)},
641 .body
.value
= memcached_htonll(result
)}};
643 rval
= response_handler(cookie
, header
, (void *) &response
);
646 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
653 * Callback for noop. Inform the v1 interface about the noop packet, and
654 * create and send a packet back to the client
656 * @param cookie the calling client
657 * @param header the command
658 * @param response_handler the response handler
659 * @return the result of the operation
661 static protocol_binary_response_status
662 noop_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
663 memcached_binary_protocol_raw_response_handler response_handler
) {
664 memcached_protocol_client_st
*client
= (void *) cookie
;
665 if (client
->root
->callback
->interface
.v1
.noop
) {
666 client
->root
->callback
->interface
.v1
.noop(cookie
);
669 protocol_binary_response_no_extras response
= {
670 .message
= {.header
.response
= {
671 .magic
= PROTOCOL_BINARY_RES
,
672 .opcode
= PROTOCOL_BINARY_CMD_NOOP
,
673 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
674 .opaque
= header
->request
.opaque
,
677 return response_handler(cookie
, header
, (void *) &response
);
681 * Callback for APPEND and APPENDQ
682 * @param cookie the calling client
683 * @param header the command
684 * @param response_handler not used
685 * @return the result of the operation
687 static protocol_binary_response_status
688 append_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
689 memcached_binary_protocol_raw_response_handler response_handler
) {
690 (void) response_handler
;
691 protocol_binary_response_status rval
;
693 memcached_protocol_client_st
*client
= (void *) cookie
;
694 if (client
->root
->callback
->interface
.v1
.append
) {
695 uint16_t keylen
= ntohs(header
->request
.keylen
);
696 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
;
697 char *key
= (void *) (header
+ 1);
698 char *data
= key
+ keylen
;
699 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
702 rval
= client
->root
->callback
->interface
.v1
.append(cookie
, key
, keylen
, data
, datalen
, cas
,
704 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
705 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_APPEND
)
707 /* Send a positive request */
708 protocol_binary_response_no_extras response
= {
712 .magic
= PROTOCOL_BINARY_RES
,
713 .opcode
= PROTOCOL_BINARY_CMD_APPEND
,
714 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
715 .opaque
= header
->request
.opaque
,
716 .cas
= memcached_ntohll(result_cas
),
719 rval
= response_handler(cookie
, header
, (void *) &response
);
722 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
729 * Callback for PREPEND and PREPENDQ
730 * @param cookie the calling client
731 * @param header the command
732 * @param response_handler not used
733 * @return the result of the operation
735 static protocol_binary_response_status
736 prepend_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
737 memcached_binary_protocol_raw_response_handler response_handler
) {
738 (void) response_handler
;
739 protocol_binary_response_status rval
;
741 memcached_protocol_client_st
*client
= (void *) cookie
;
742 if (client
->root
->callback
->interface
.v1
.prepend
) {
743 uint16_t keylen
= ntohs(header
->request
.keylen
);
744 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
;
745 char *key
= (char *) (header
+ 1);
746 char *data
= key
+ keylen
;
747 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
749 rval
= client
->root
->callback
->interface
.v1
.prepend(cookie
, key
, keylen
, data
, datalen
, cas
,
751 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
752 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_PREPEND
)
754 /* Send a positive request */
755 protocol_binary_response_no_extras response
= {
759 .magic
= PROTOCOL_BINARY_RES
,
760 .opcode
= PROTOCOL_BINARY_CMD_PREPEND
,
761 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
762 .opaque
= header
->request
.opaque
,
763 .cas
= memcached_ntohll(result_cas
),
766 rval
= response_handler(cookie
, header
, (void *) &response
);
769 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
776 * Callback for QUIT and QUITQ. Notify the client and shut down the connection
777 * @param cookie the calling client
778 * @param header the command
779 * @param response_handler not used
780 * @return the result of the operation
782 static protocol_binary_response_status
783 quit_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
784 memcached_binary_protocol_raw_response_handler response_handler
) {
785 memcached_protocol_client_st
*client
= (void *) cookie
;
786 if (client
->root
->callback
->interface
.v1
.quit
) {
787 client
->root
->callback
->interface
.v1
.quit(cookie
);
790 protocol_binary_response_no_extras response
= {
791 .message
= {.header
.response
= {.magic
= PROTOCOL_BINARY_RES
,
792 .opcode
= PROTOCOL_BINARY_CMD_QUIT
,
793 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
794 .opaque
= header
->request
.opaque
}}};
796 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_QUIT
) {
797 response_handler(cookie
, header
, (void *) &response
);
800 /* I need a better way to signal to close the connection */
801 return PROTOCOL_BINARY_RESPONSE_EINTERNAL
;
805 * Callback for REPLACE and REPLACEQ
806 * @param cookie the calling client
807 * @param header the command
808 * @param response_handler not used
809 * @return the result of the operation
811 static protocol_binary_response_status
812 replace_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
813 memcached_binary_protocol_raw_response_handler response_handler
) {
814 (void) response_handler
;
815 protocol_binary_response_status rval
;
817 memcached_protocol_client_st
*client
= (void *) cookie
;
818 if (client
->root
->callback
->interface
.v1
.replace
) {
819 uint16_t keylen
= ntohs(header
->request
.keylen
);
820 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
821 protocol_binary_request_replace
*request
= (void *) header
;
822 uint32_t flags
= ntohl(request
->message
.body
.flags
);
823 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
824 char *key
= ((char *) header
) + sizeof(*header
) + 8;
825 char *data
= key
+ keylen
;
826 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
829 rval
= client
->root
->callback
->interface
.v1
.replace(cookie
, key
, keylen
, data
, datalen
, flags
,
830 timeout
, cas
, &result_cas
);
831 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
832 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_REPLACE
)
834 /* Send a positive request */
835 protocol_binary_response_no_extras response
= {
839 .magic
= PROTOCOL_BINARY_RES
,
840 .opcode
= PROTOCOL_BINARY_CMD_REPLACE
,
841 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
842 .opaque
= header
->request
.opaque
,
843 .cas
= memcached_ntohll(result_cas
),
846 rval
= response_handler(cookie
, header
, (void *) &response
);
849 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
856 * Callback for SET and SETQ
857 * @param cookie the calling client
858 * @param header the command
859 * @param response_handler not used
860 * @return the result of the operation
862 static protocol_binary_response_status
863 set_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
864 memcached_binary_protocol_raw_response_handler response_handler
) {
865 (void) response_handler
;
866 protocol_binary_response_status rval
;
868 memcached_protocol_client_st
*client
= (void *) cookie
;
869 if (client
->root
->callback
->interface
.v1
.set
) {
870 uint16_t keylen
= ntohs(header
->request
.keylen
);
871 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
872 protocol_binary_request_replace
*request
= (void *) header
;
873 uint32_t flags
= ntohl(request
->message
.body
.flags
);
874 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
875 char *key
= ((char *) header
) + sizeof(*header
) + 8;
876 char *data
= key
+ keylen
;
877 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
880 rval
= client
->root
->callback
->interface
.v1
.set(cookie
, key
, keylen
, data
, datalen
, flags
,
881 timeout
, cas
, &result_cas
);
882 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
883 && header
->request
.opcode
== PROTOCOL_BINARY_CMD_SET
) {
884 /* Send a positive request */
885 protocol_binary_response_no_extras response
= {
889 .magic
= PROTOCOL_BINARY_RES
,
890 .opcode
= PROTOCOL_BINARY_CMD_SET
,
891 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
892 .opaque
= header
->request
.opaque
,
893 .cas
= memcached_ntohll(result_cas
),
896 rval
= response_handler(cookie
, header
, (void *) &response
);
899 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
907 * @param cookie the calling client
908 * @param header the command
909 * @param response_handler not used
910 * @return the result of the operation
912 static protocol_binary_response_status
913 stat_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
914 memcached_binary_protocol_raw_response_handler response_handler
) {
915 (void) response_handler
;
916 protocol_binary_response_status rval
;
918 memcached_protocol_client_st
*client
= (void *) cookie
;
919 if (client
->root
->callback
->interface
.v1
.stat
) {
920 uint16_t keylen
= ntohs(header
->request
.keylen
);
922 rval
= client
->root
->callback
->interface
.v1
.stat(cookie
, (void *) (header
+ 1), keylen
,
923 stat_response_handler
);
924 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
) {
926 protocol_binary_response_no_extras response
= {
930 .magic
= PROTOCOL_BINARY_RES
,
931 .opcode
= PROTOCOL_BINARY_CMD_STAT
,
932 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
933 .opaque
= header
->request
.opaque
,
936 rval
= response_handler(cookie
, header
, (void *) &response
);
939 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
946 * Callback for VERSION
947 * @param cookie the calling client
948 * @param header the command
949 * @param response_handler not used
950 * @return the result of the operation
952 static protocol_binary_response_status
953 version_command_handler(const void *cookie
, protocol_binary_request_header
*header
,
954 memcached_binary_protocol_raw_response_handler response_handler
) {
955 (void) response_handler
;
957 protocol_binary_response_status rval
;
959 memcached_protocol_client_st
*client
= (void *) cookie
;
960 if (client
->root
->callback
->interface
.v1
.version
) {
961 rval
= client
->root
->callback
->interface
.v1
.version(cookie
, version_response_handler
);
962 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
) {
963 rval
= response_handler(cookie
, header
, NULL
);
966 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
973 * The map to remap between the com codes and the v1 logical setting
975 static memcached_binary_protocol_command_handler comcode_v0_v1_remap
[256] = {
976 [PROTOCOL_BINARY_CMD_ADDQ
] = add_command_handler
,
977 [PROTOCOL_BINARY_CMD_ADD
] = add_command_handler
,
978 [PROTOCOL_BINARY_CMD_APPENDQ
] = append_command_handler
,
979 [PROTOCOL_BINARY_CMD_APPEND
] = append_command_handler
,
980 [PROTOCOL_BINARY_CMD_DECREMENTQ
] = decrement_command_handler
,
981 [PROTOCOL_BINARY_CMD_DECREMENT
] = decrement_command_handler
,
982 [PROTOCOL_BINARY_CMD_DELETEQ
] = delete_command_handler
,
983 [PROTOCOL_BINARY_CMD_DELETE
] = delete_command_handler
,
984 [PROTOCOL_BINARY_CMD_FLUSHQ
] = flush_command_handler
,
985 [PROTOCOL_BINARY_CMD_FLUSH
] = flush_command_handler
,
986 [PROTOCOL_BINARY_CMD_GETKQ
] = get_command_handler
,
987 [PROTOCOL_BINARY_CMD_GETK
] = get_command_handler
,
988 [PROTOCOL_BINARY_CMD_GETQ
] = get_command_handler
,
989 [PROTOCOL_BINARY_CMD_GET
] = get_command_handler
,
990 [PROTOCOL_BINARY_CMD_INCREMENTQ
] = increment_command_handler
,
991 [PROTOCOL_BINARY_CMD_INCREMENT
] = increment_command_handler
,
992 [PROTOCOL_BINARY_CMD_NOOP
] = noop_command_handler
,
993 [PROTOCOL_BINARY_CMD_PREPENDQ
] = prepend_command_handler
,
994 [PROTOCOL_BINARY_CMD_PREPEND
] = prepend_command_handler
,
995 [PROTOCOL_BINARY_CMD_QUITQ
] = quit_command_handler
,
996 [PROTOCOL_BINARY_CMD_QUIT
] = quit_command_handler
,
997 [PROTOCOL_BINARY_CMD_REPLACEQ
] = replace_command_handler
,
998 [PROTOCOL_BINARY_CMD_REPLACE
] = replace_command_handler
,
999 [PROTOCOL_BINARY_CMD_SETQ
] = set_command_handler
,
1000 [PROTOCOL_BINARY_CMD_SET
] = set_command_handler
,
1001 [PROTOCOL_BINARY_CMD_STAT
] = stat_command_handler
,
1002 [PROTOCOL_BINARY_CMD_VERSION
] = version_command_handler
,
1006 * Try to execute a command. Fire the pre/post functions and the specialized
1007 * handler function if it's set. If not, the unknown probe should be fired
1009 * @param client the client connection to operate on
1010 * @param header the command to execute
1011 * @return true if success or false if a fatal error occured so that the
1012 * connection should be shut down.
1014 static protocol_binary_response_status
execute_command(memcached_protocol_client_st
*client
,
1015 protocol_binary_request_header
*header
) {
1016 if (client
->root
->pedantic
&& memcached_binary_protocol_pedantic_check_request(header
)) {
1017 /* @todo return invalid command packet */
1020 /* we got all data available, execute the callback! */
1021 if (client
->root
->callback
->pre_execute
) {
1022 client
->root
->callback
->pre_execute(client
, header
);
1025 protocol_binary_response_status rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
1026 uint8_t cc
= header
->request
.opcode
;
1028 if (client
->is_verbose
) {
1032 switch (client
->root
->callback
->interface_version
) {
1034 if (client
->root
->callback
->interface
.v0
.comcode
[cc
]) {
1035 rval
= client
->root
->callback
->interface
.v0
.comcode
[cc
](client
, header
,
1036 binary_raw_response_handler
);
1041 if (comcode_v0_v1_remap
[cc
]) {
1042 rval
= comcode_v0_v1_remap
[cc
](client
, header
, binary_raw_response_handler
);
1047 /* Unknown interface.
1048 * It should be impossible to get here so I'll just call abort
1049 * to avoid getting a compiler warning :-)
1054 if (rval
== PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
&& client
->root
->callback
->unknown
) {
1055 rval
= client
->root
->callback
->unknown(client
, header
, binary_raw_response_handler
);
1058 if (rval
!= PROTOCOL_BINARY_RESPONSE_SUCCESS
&& rval
!= PROTOCOL_BINARY_RESPONSE_EINTERNAL
1059 && rval
!= PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED
)
1061 protocol_binary_response_no_extras response
= {.message
= {
1064 .magic
= PROTOCOL_BINARY_RES
,
1066 .status
= htons(rval
),
1067 .opaque
= header
->request
.opaque
,
1070 rval
= binary_raw_response_handler(client
, header
, (void *) &response
);
1073 if (client
->root
->callback
->post_execute
) {
1074 client
->root
->callback
->post_execute(client
, header
);
1081 ** **********************************************************************
1082 ** "PROTOECTED" INTERFACE
1083 ** **********************************************************************
1085 memcached_protocol_event_t
1086 memcached_binary_protocol_process_data(memcached_protocol_client_st
*client
, ssize_t
*length
,
1088 /* try to parse all of the received packets */
1089 protocol_binary_request_header
*header
;
1090 header
= (void *) client
->root
->input_buffer
;
1091 if (header
->request
.magic
!= (uint8_t) PROTOCOL_BINARY_REQ
) {
1092 client
->error
= EINVAL
;
1093 return MEMCACHED_PROTOCOL_ERROR_EVENT
;
1095 ssize_t len
= *length
;
1097 while (len
>= (ssize_t
) sizeof(*header
)
1098 && (len
>= (ssize_t
)(sizeof(*header
) + ntohl(header
->request
.bodylen
))))
1100 /* I have the complete package */
1101 client
->current_command
= header
;
1102 protocol_binary_response_status rv
= execute_command(client
, header
);
1104 if (rv
== PROTOCOL_BINARY_RESPONSE_EINTERNAL
) {
1106 *endptr
= (void *) header
;
1107 return MEMCACHED_PROTOCOL_ERROR_EVENT
;
1108 } else if (rv
== PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED
) {
1109 return MEMCACHED_PROTOCOL_PAUSE_EVENT
;
1112 ssize_t total
= (ssize_t
)(sizeof(*header
) + ntohl(header
->request
.bodylen
));
1115 intptr_t ptr
= (intptr_t) header
;
1117 if ((ptr
% 8) == 0) {
1118 header
= (void *) ptr
;
1121 memmove(client
->root
->input_buffer
, (void *) ptr
, (size_t) len
);
1122 header
= (void *) client
->root
->input_buffer
;
1126 *endptr
= (void *) header
;
1129 return MEMCACHED_PROTOCOL_READ_EVENT
;
1133 ** **********************************************************************
1135 ** **********************************************************************
1137 memcached_binary_protocol_callback_st
*
1138 memcached_binary_protocol_get_callbacks(memcached_protocol_st
*instance
) {
1139 return instance
->callback
;
1142 void memcached_binary_protocol_set_callbacks(memcached_protocol_st
*instance
,
1143 memcached_binary_protocol_callback_st
*callback
) {
1144 instance
->callback
= callback
;
1147 memcached_binary_protocol_raw_response_handler
1148 memcached_binary_protocol_get_raw_response_handler(const void *cookie
) {
1150 return binary_raw_response_handler
;
1153 void memcached_binary_protocol_set_pedantic(memcached_protocol_st
*instance
, bool enable
) {
1154 instance
->pedantic
= enable
;
1157 bool memcached_binary_protocol_get_pedantic(memcached_protocol_st
*instance
) {
1158 return instance
->pedantic
;