1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
19 * * The names of its contributors may not be used to endorse or
20 * promote products derived from this software without specific prior
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <libmemcachedprotocol/common.h>
40 #include <sys/types.h>
47 ** **********************************************************************
49 ** **********************************************************************
53 * Send a preformatted packet back to the client. If the connection is in
54 * pedantic mode, it will validate the packet and refuse to send it if it
55 * breaks the specification.
57 * @param cookie client identification
58 * @param request the original request packet
59 * @param response the packet to send
60 * @return The status of the operation
62 static protocol_binary_response_status
raw_response_handler(const void *cookie
,
63 protocol_binary_request_header
*request
,
64 protocol_binary_response_header
*response
)
66 memcached_protocol_client_st
*client
= (void*)cookie
;
68 if (client
->root
->pedantic
&&
69 !memcached_binary_protocol_pedantic_check_response(request
, response
))
71 return PROTOCOL_BINARY_RESPONSE_EINVAL
;
74 if (client
->root
->drain(client
) == false)
76 return PROTOCOL_BINARY_RESPONSE_EINTERNAL
;
79 size_t len
= sizeof(protocol_binary_response_header
) + htonl(response
->response
.bodylen
);
81 char *ptr
= (void*)response
;
83 if (client
->output
== NULL
)
85 /* I can write directly to the socket.... */
88 size_t num_bytes
= len
- offset
;
89 ssize_t nw
= client
->root
->send(client
,
95 if (get_socket_errno() == EWOULDBLOCK
)
99 else if (get_socket_errno() != EINTR
)
101 client
->error
= errno
;
102 return PROTOCOL_BINARY_RESPONSE_EINTERNAL
;
107 offset
+= (size_t)nw
;
109 } while (offset
< len
);
112 return client
->root
->spool(client
, ptr
, len
- offset
);
115 static void print_cmd(protocol_binary_command cmd
)
119 case PROTOCOL_BINARY_CMD_GET
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GET\n", __FILE__
, __LINE__
); return;
120 case PROTOCOL_BINARY_CMD_SET
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SET\n", __FILE__
, __LINE__
); return;
121 case PROTOCOL_BINARY_CMD_ADD
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_ADD\n", __FILE__
, __LINE__
); return;
122 case PROTOCOL_BINARY_CMD_REPLACE
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_REPLACE\n", __FILE__
, __LINE__
); return;
123 case PROTOCOL_BINARY_CMD_DELETE
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DELETE\n", __FILE__
, __LINE__
); return;
124 case PROTOCOL_BINARY_CMD_INCREMENT
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_INCREMENT\n", __FILE__
, __LINE__
); return;
125 case PROTOCOL_BINARY_CMD_DECREMENT
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DECREMENT\n", __FILE__
, __LINE__
); return;
126 case PROTOCOL_BINARY_CMD_QUIT
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_QUIT\n", __FILE__
, __LINE__
); return;
127 case PROTOCOL_BINARY_CMD_FLUSH
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_FLUSH\n", __FILE__
, __LINE__
); return;
128 case PROTOCOL_BINARY_CMD_GETQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GETQ\n", __FILE__
, __LINE__
); return;
129 case PROTOCOL_BINARY_CMD_NOOP
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_NOOP\n", __FILE__
, __LINE__
); return;
130 case PROTOCOL_BINARY_CMD_VERSION
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_VERSION\n", __FILE__
, __LINE__
); return;
131 case PROTOCOL_BINARY_CMD_GETK
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GETK\n", __FILE__
, __LINE__
); return;
132 case PROTOCOL_BINARY_CMD_GETKQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GETKQ\n", __FILE__
, __LINE__
); return;
133 case PROTOCOL_BINARY_CMD_APPEND
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_APPEND\n", __FILE__
, __LINE__
); return;
134 case PROTOCOL_BINARY_CMD_PREPEND
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_PREPEND\n", __FILE__
, __LINE__
); return;
135 case PROTOCOL_BINARY_CMD_STAT
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_STAT\n", __FILE__
, __LINE__
); return;
136 case PROTOCOL_BINARY_CMD_SETQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SETQ\n", __FILE__
, __LINE__
); return;
137 case PROTOCOL_BINARY_CMD_ADDQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_ADDQ\n", __FILE__
, __LINE__
); return;
138 case PROTOCOL_BINARY_CMD_REPLACEQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_REPLACEQ\n", __FILE__
, __LINE__
); return;
139 case PROTOCOL_BINARY_CMD_DELETEQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DELETEQ\n", __FILE__
, __LINE__
); return;
140 case PROTOCOL_BINARY_CMD_INCREMENTQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_INCREMENTQ\n", __FILE__
, __LINE__
); return;
141 case PROTOCOL_BINARY_CMD_DECREMENTQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DECREMENTQ\n", __FILE__
, __LINE__
); return;
142 case PROTOCOL_BINARY_CMD_QUITQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_QUITQ\n", __FILE__
, __LINE__
); return;
143 case PROTOCOL_BINARY_CMD_FLUSHQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_FLUSHQ\n", __FILE__
, __LINE__
); return;
144 case PROTOCOL_BINARY_CMD_APPENDQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_APPENDQ\n", __FILE__
, __LINE__
); return;
145 case PROTOCOL_BINARY_CMD_PREPENDQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_PREPENDQ\n", __FILE__
, __LINE__
); return;
146 case PROTOCOL_BINARY_CMD_VERBOSITY
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_VERBOSITY\n", __FILE__
, __LINE__
); return;
147 case PROTOCOL_BINARY_CMD_TOUCH
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TOUCH\n", __FILE__
, __LINE__
); return;
148 case PROTOCOL_BINARY_CMD_GAT
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GAT\n", __FILE__
, __LINE__
); return;
149 case PROTOCOL_BINARY_CMD_GATQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GATQ\n", __FILE__
, __LINE__
); return;
150 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SASL_LIST_MECHS\n", __FILE__
, __LINE__
); return;
151 case PROTOCOL_BINARY_CMD_SASL_AUTH
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SASL_AUTH\n", __FILE__
, __LINE__
); return;
152 case PROTOCOL_BINARY_CMD_SASL_STEP
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SASL_STEP\n", __FILE__
, __LINE__
); return;
153 case PROTOCOL_BINARY_CMD_RGET
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RGET\n", __FILE__
, __LINE__
); return;
154 case PROTOCOL_BINARY_CMD_RSET
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RSET\n", __FILE__
, __LINE__
); return;
155 case PROTOCOL_BINARY_CMD_RSETQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RSETQ\n", __FILE__
, __LINE__
); return;
156 case PROTOCOL_BINARY_CMD_RAPPEND
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RAPPEND\n", __FILE__
, __LINE__
); return;
157 case PROTOCOL_BINARY_CMD_RAPPENDQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RAPPENDQ\n", __FILE__
, __LINE__
); return;
158 case PROTOCOL_BINARY_CMD_RPREPEND
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RPREPEND\n", __FILE__
, __LINE__
); return;
159 case PROTOCOL_BINARY_CMD_RPREPENDQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RPREPENDQ\n", __FILE__
, __LINE__
); return;
160 case PROTOCOL_BINARY_CMD_RDELETE
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDELETE\n", __FILE__
, __LINE__
); return;
161 case PROTOCOL_BINARY_CMD_RDELETEQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDELETEQ\n", __FILE__
, __LINE__
); return;
162 case PROTOCOL_BINARY_CMD_RINCR
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RINCR\n", __FILE__
, __LINE__
); return;
163 case PROTOCOL_BINARY_CMD_RINCRQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RINCRQ\n", __FILE__
, __LINE__
); return;
164 case PROTOCOL_BINARY_CMD_RDECR
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDECR\n", __FILE__
, __LINE__
); return;
165 case PROTOCOL_BINARY_CMD_RDECRQ
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_RDECRQ\n", __FILE__
, __LINE__
); return;
166 case PROTOCOL_BINARY_CMD_SET_VBUCKET
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SET_VBUCKET\n", __FILE__
, __LINE__
); return;
167 case PROTOCOL_BINARY_CMD_GET_VBUCKET
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_GET_VBUCKET\n", __FILE__
, __LINE__
); return;
168 case PROTOCOL_BINARY_CMD_DEL_VBUCKET
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_DEL_VBUCKET\n", __FILE__
, __LINE__
); return;
169 case PROTOCOL_BINARY_CMD_TAP_CONNECT
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_CONNECT\n", __FILE__
, __LINE__
); return;
170 case PROTOCOL_BINARY_CMD_TAP_MUTATION
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_MUTATION\n", __FILE__
, __LINE__
); return;
171 case PROTOCOL_BINARY_CMD_TAP_DELETE
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_DELETE\n", __FILE__
, __LINE__
); return;
172 case PROTOCOL_BINARY_CMD_TAP_FLUSH
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_FLUSH\n", __FILE__
, __LINE__
); return;
173 case PROTOCOL_BINARY_CMD_TAP_OPAQUE
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_OPAQUE\n", __FILE__
, __LINE__
); return;
174 case PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET\n", __FILE__
, __LINE__
); return;
175 case PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START\n", __FILE__
, __LINE__
); return;
176 case PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END\n", __FILE__
, __LINE__
); return;
177 case PROTOCOL_BINARY_CMD_LAST_RESERVED
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_LAST_RESERVED\n", __FILE__
, __LINE__
); return;
178 case PROTOCOL_BINARY_CMD_SCRUB
: fprintf(stderr
, "%s:%d PROTOCOL_BINARY_CMD_SCRUB\n", __FILE__
, __LINE__
); return;
185 * Version 0 of the interface is really low level and protocol specific,
186 * while the version 1 of the interface is more API focused. We need a
187 * way to translate between the command codes on the wire and the
188 * application level interface in V1, so let's just use the V0 of the
189 * interface as a map instead of creating a huuuge switch :-)
193 * Callback for the GET/GETQ/GETK and GETKQ responses
194 * @param cookie client identifier
195 * @param key the key for the item
196 * @param keylen the length of the key
197 * @param body the length of the body
198 * @param bodylen the length of the body
199 * @param flags the flags for the item
200 * @param cas the CAS id for the item
202 static protocol_binary_response_status
get_response_handler(const void *cookie
,
210 memcached_protocol_client_st
*client
= (void*)cookie
;
211 uint8_t opcode
= client
->current_command
->request
.opcode
;
213 if (opcode
== PROTOCOL_BINARY_CMD_GET
|| opcode
== PROTOCOL_BINARY_CMD_GETQ
)
218 protocol_binary_response_get response
= {
219 .message
.header
.response
= {
220 .magic
= PROTOCOL_BINARY_RES
,
222 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
223 .opaque
= client
->current_command
->request
.opaque
,
224 .cas
= memcached_htonll(cas
),
225 .keylen
= htons(keylen
),
227 .bodylen
= htonl(bodylen
+ keylen
+ 4),
231 response
.message
.body
.flags
= htonl(flags
);
233 protocol_binary_response_status rval
;
234 const protocol_binary_response_status success
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
235 if ((rval
= client
->root
->spool(client
, response
.bytes
, sizeof(response
.bytes
))) != success
||
236 (rval
= client
->root
->spool(client
, key
, keylen
)) != success
||
237 (rval
= client
->root
->spool(client
, body
, bodylen
)) != success
)
242 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
246 * Callback for the STAT responses
247 * @param cookie client identifier
248 * @param key the key for the item
249 * @param keylen the length of the key
250 * @param body the length of the body
251 * @param bodylen the length of the body
253 static protocol_binary_response_status
stat_response_handler(const void *cookie
,
260 memcached_protocol_client_st
*client
= (void*)cookie
;
262 protocol_binary_response_no_extras response
= {
263 .message
.header
.response
= {
264 .magic
= PROTOCOL_BINARY_RES
,
265 .opcode
= client
->current_command
->request
.opcode
,
266 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
267 .opaque
= client
->current_command
->request
.opaque
,
268 .keylen
= htons(keylen
),
269 .bodylen
= htonl(bodylen
+ keylen
),
274 protocol_binary_response_status rval
;
275 const protocol_binary_response_status success
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
276 if ((rval
= client
->root
->spool(client
, response
.bytes
, sizeof(response
.bytes
))) != success
||
277 (rval
= client
->root
->spool(client
, key
, keylen
)) != success
||
278 (rval
= client
->root
->spool(client
, body
, bodylen
)) != success
)
283 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
287 * Callback for the VERSION responses
288 * @param cookie client identifier
289 * @param text the length of the body
290 * @param textlen the length of the body
292 static protocol_binary_response_status
version_response_handler(const void *cookie
,
297 memcached_protocol_client_st
*client
= (void*)cookie
;
299 protocol_binary_response_no_extras response
= {
300 .message
.header
.response
= {
301 .magic
= PROTOCOL_BINARY_RES
,
302 .opcode
= client
->current_command
->request
.opcode
,
303 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
304 .opaque
= client
->current_command
->request
.opaque
,
305 .bodylen
= htonl(textlen
),
310 protocol_binary_response_status rval
;
311 const protocol_binary_response_status success
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
312 if ((rval
= client
->root
->spool(client
, response
.bytes
, sizeof(response
.bytes
))) != success
||
313 (rval
= client
->root
->spool(client
, text
, textlen
)) != success
)
318 return PROTOCOL_BINARY_RESPONSE_SUCCESS
;
322 * Callback for ADD and ADDQ
323 * @param cookie the calling client
324 * @param header the add/addq command
325 * @param response_handler not used
326 * @return the result of the operation
328 static protocol_binary_response_status
329 add_command_handler(const void *cookie
,
330 protocol_binary_request_header
*header
,
331 memcached_binary_protocol_raw_response_handler response_handler
)
333 protocol_binary_response_status rval
;
335 memcached_protocol_client_st
*client
= (void*)cookie
;
336 if (client
->root
->callback
->interface
.v1
.add
!= NULL
)
338 uint16_t keylen
= ntohs(header
->request
.keylen
);
339 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
340 protocol_binary_request_add
*request
= (void*)header
;
341 uint32_t flags
= ntohl(request
->message
.body
.flags
);
342 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
343 char *key
= ((char*)header
) + sizeof(*header
) + 8;
344 char *data
= key
+ keylen
;
347 rval
= client
->root
->callback
->interface
.v1
.add(cookie
, key
, keylen
,
348 data
, datalen
, flags
,
351 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
352 header
->request
.opcode
== PROTOCOL_BINARY_CMD_ADD
)
354 /* Send a positive request */
355 protocol_binary_response_no_extras response
= {
358 .magic
= PROTOCOL_BINARY_RES
,
359 .opcode
= PROTOCOL_BINARY_CMD_ADD
,
360 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
361 .opaque
= header
->request
.opaque
,
362 .cas
= memcached_ntohll(cas
)
366 rval
= response_handler(cookie
, header
, (void*)&response
);
371 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
378 * Callback for DECREMENT and DECREMENTQ
379 * @param cookie the calling client
380 * @param header the command
381 * @param response_handler not used
382 * @return the result of the operation
384 static protocol_binary_response_status
385 decrement_command_handler(const void *cookie
,
386 protocol_binary_request_header
*header
,
387 memcached_binary_protocol_raw_response_handler response_handler
)
389 (void)response_handler
;
390 protocol_binary_response_status rval
;
392 memcached_protocol_client_st
*client
= (void*)cookie
;
393 if (client
->root
->callback
->interface
.v1
.decrement
!= NULL
)
395 uint16_t keylen
= ntohs(header
->request
.keylen
);
396 protocol_binary_request_decr
*request
= (void*)header
;
397 uint64_t init
= memcached_ntohll(request
->message
.body
.initial
);
398 uint64_t delta
= memcached_ntohll(request
->message
.body
.delta
);
399 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
400 void *key
= request
->bytes
+ sizeof(request
->bytes
);
404 rval
= client
->root
->callback
->interface
.v1
.decrement(cookie
, key
, keylen
,
405 delta
, init
, timeout
,
407 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
408 header
->request
.opcode
== PROTOCOL_BINARY_CMD_DECREMENT
)
410 /* Send a positive request */
411 protocol_binary_response_decr response
= {
414 .magic
= PROTOCOL_BINARY_RES
,
415 .opcode
= PROTOCOL_BINARY_CMD_DECREMENT
,
416 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
417 .opaque
= header
->request
.opaque
,
418 .cas
= memcached_ntohll(cas
),
421 .body
.value
= memcached_htonll(result
)
424 rval
= response_handler(cookie
, header
, (void*)&response
);
429 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
436 * Callback for DELETE and DELETEQ
437 * @param cookie the calling client
438 * @param header the command
439 * @param response_handler not used
440 * @return the result of the operation
442 static protocol_binary_response_status
delete_command_handler(const void *cookie
,
443 protocol_binary_request_header
*header
,
444 memcached_binary_protocol_raw_response_handler response_handler
)
446 (void)response_handler
;
447 protocol_binary_response_status rval
;
449 memcached_protocol_client_st
*client
= (void*)cookie
;
450 if (client
->root
->callback
->interface
.v1
.delete_object
!= NULL
)
452 uint16_t keylen
= ntohs(header
->request
.keylen
);
453 void *key
= (header
+1);
454 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
455 rval
= client
->root
->callback
->interface
.v1
.delete_object(cookie
, key
, keylen
, cas
);
456 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
457 header
->request
.opcode
== PROTOCOL_BINARY_CMD_DELETE
)
459 /* Send a positive request */
460 protocol_binary_response_no_extras response
= {
463 .magic
= PROTOCOL_BINARY_RES
,
464 .opcode
= PROTOCOL_BINARY_CMD_DELETE
,
465 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
466 .opaque
= header
->request
.opaque
,
470 rval
= response_handler(cookie
, header
, (void*)&response
);
475 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
482 * Callback for FLUSH and FLUSHQ
483 * @param cookie the calling client
484 * @param header the command
485 * @param response_handler not used
486 * @return the result of the operation
488 static protocol_binary_response_status
489 flush_command_handler(const void *cookie
,
490 protocol_binary_request_header
*header
,
491 memcached_binary_protocol_raw_response_handler response_handler
)
493 (void)response_handler
;
494 protocol_binary_response_status rval
;
496 memcached_protocol_client_st
*client
= (void*)cookie
;
497 if (client
->root
->callback
->interface
.v1
.flush_object
!= NULL
)
499 protocol_binary_request_flush
*flush_object
= (void*)header
;
501 if (htonl(header
->request
.bodylen
) == 4)
503 timeout
= ntohl(flush_object
->message
.body
.expiration
);
506 rval
= client
->root
->callback
->interface
.v1
.flush_object(cookie
, timeout
);
507 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
508 header
->request
.opcode
== PROTOCOL_BINARY_CMD_FLUSH
)
510 /* Send a positive request */
511 protocol_binary_response_no_extras response
= {
514 .magic
= PROTOCOL_BINARY_RES
,
515 .opcode
= PROTOCOL_BINARY_CMD_FLUSH
,
516 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
517 .opaque
= header
->request
.opaque
,
521 rval
= response_handler(cookie
, header
, (void*)&response
);
526 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
533 * Callback for GET, GETK, GETQ, GETKQ
534 * @param cookie the calling client
535 * @param header the command
536 * @param response_handler not used
537 * @return the result of the operation
539 static protocol_binary_response_status
540 get_command_handler(const void *cookie
,
541 protocol_binary_request_header
*header
,
542 memcached_binary_protocol_raw_response_handler response_handler
)
544 (void)response_handler
;
545 protocol_binary_response_status rval
;
547 memcached_protocol_client_st
*client
= (void*)cookie
;
548 if (client
->root
->callback
->interface
.v1
.get
!= NULL
)
550 uint16_t keylen
= ntohs(header
->request
.keylen
);
551 void *key
= (header
+ 1);
552 rval
= client
->root
->callback
->interface
.v1
.get(cookie
, key
, keylen
,
553 get_response_handler
);
555 if (rval
== PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
&&
556 (header
->request
.opcode
== PROTOCOL_BINARY_CMD_GETQ
||
557 header
->request
.opcode
== PROTOCOL_BINARY_CMD_GETKQ
))
559 /* Quiet commands shouldn't respond on cache misses */
560 rval
= PROTOCOL_BINARY_RESPONSE_SUCCESS
;
565 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
572 * Callback for INCREMENT and INCREMENTQ
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 increment_command_handler(const void *cookie
,
580 protocol_binary_request_header
*header
,
581 memcached_binary_protocol_raw_response_handler response_handler
)
583 (void)response_handler
;
584 protocol_binary_response_status rval
;
586 memcached_protocol_client_st
*client
= (void*)cookie
;
587 if (client
->root
->callback
->interface
.v1
.increment
!= NULL
)
589 uint16_t keylen
= ntohs(header
->request
.keylen
);
590 protocol_binary_request_incr
*request
= (void*)header
;
591 uint64_t init
= memcached_ntohll(request
->message
.body
.initial
);
592 uint64_t delta
= memcached_ntohll(request
->message
.body
.delta
);
593 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
594 void *key
= request
->bytes
+ sizeof(request
->bytes
);
598 rval
= client
->root
->callback
->interface
.v1
.increment(cookie
, key
, keylen
,
599 delta
, init
, timeout
,
601 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
602 header
->request
.opcode
== PROTOCOL_BINARY_CMD_INCREMENT
)
604 /* Send a positive request */
605 protocol_binary_response_incr response
= {
608 .magic
= PROTOCOL_BINARY_RES
,
609 .opcode
= PROTOCOL_BINARY_CMD_INCREMENT
,
610 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
611 .opaque
= header
->request
.opaque
,
612 .cas
= memcached_ntohll(cas
),
615 .body
.value
= memcached_htonll(result
)
619 rval
= response_handler(cookie
, header
, (void*)&response
);
624 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
631 * Callback for noop. Inform the v1 interface about the noop packet, and
632 * create and send a packet back to the client
634 * @param cookie the calling client
635 * @param header the command
636 * @param response_handler the response handler
637 * @return the result of the operation
639 static protocol_binary_response_status
640 noop_command_handler(const void *cookie
,
641 protocol_binary_request_header
*header
,
642 memcached_binary_protocol_raw_response_handler response_handler
)
644 memcached_protocol_client_st
*client
= (void*)cookie
;
645 if (client
->root
->callback
->interface
.v1
.noop
!= NULL
)
647 client
->root
->callback
->interface
.v1
.noop(cookie
);
650 protocol_binary_response_no_extras response
= {
653 .magic
= PROTOCOL_BINARY_RES
,
654 .opcode
= PROTOCOL_BINARY_CMD_NOOP
,
655 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
656 .opaque
= header
->request
.opaque
,
661 return response_handler(cookie
, header
, (void*)&response
);
665 * Callback for APPEND and APPENDQ
666 * @param cookie the calling client
667 * @param header the command
668 * @param response_handler not used
669 * @return the result of the operation
671 static protocol_binary_response_status
672 append_command_handler(const void *cookie
,
673 protocol_binary_request_header
*header
,
674 memcached_binary_protocol_raw_response_handler response_handler
)
676 (void)response_handler
;
677 protocol_binary_response_status rval
;
679 memcached_protocol_client_st
*client
= (void*)cookie
;
680 if (client
->root
->callback
->interface
.v1
.append
!= NULL
)
682 uint16_t keylen
= ntohs(header
->request
.keylen
);
683 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
;
684 char *key
= (void*)(header
+1);
685 char *data
= key
+keylen
;
686 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
689 rval
= client
->root
->callback
->interface
.v1
.append(cookie
, key
, keylen
,
692 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
693 header
->request
.opcode
== PROTOCOL_BINARY_CMD_APPEND
)
695 /* Send a positive request */
696 protocol_binary_response_no_extras response
= {
699 .magic
= PROTOCOL_BINARY_RES
,
700 .opcode
= PROTOCOL_BINARY_CMD_APPEND
,
701 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
702 .opaque
= header
->request
.opaque
,
703 .cas
= memcached_ntohll(result_cas
),
707 rval
= response_handler(cookie
, header
, (void*)&response
);
712 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
719 * Callback for PREPEND and PREPENDQ
720 * @param cookie the calling client
721 * @param header the command
722 * @param response_handler not used
723 * @return the result of the operation
725 static protocol_binary_response_status
726 prepend_command_handler(const void *cookie
,
727 protocol_binary_request_header
*header
,
728 memcached_binary_protocol_raw_response_handler response_handler
)
730 (void)response_handler
;
731 protocol_binary_response_status rval
;
733 memcached_protocol_client_st
*client
= (void*)cookie
;
734 if (client
->root
->callback
->interface
.v1
.prepend
!= NULL
)
736 uint16_t keylen
= ntohs(header
->request
.keylen
);
737 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
;
738 char *key
= (char*)(header
+ 1);
739 char *data
= key
+ keylen
;
740 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
742 rval
= client
->root
->callback
->interface
.v1
.prepend(cookie
, key
, keylen
,
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
= {
752 .magic
= PROTOCOL_BINARY_RES
,
753 .opcode
= PROTOCOL_BINARY_CMD_PREPEND
,
754 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
755 .opaque
= header
->request
.opaque
,
756 .cas
= memcached_ntohll(result_cas
),
760 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
,
780 protocol_binary_request_header
*header
,
781 memcached_binary_protocol_raw_response_handler response_handler
)
783 memcached_protocol_client_st
*client
= (void*)cookie
;
784 if (client
->root
->callback
->interface
.v1
.quit
!= NULL
)
786 client
->root
->callback
->interface
.v1
.quit(cookie
);
789 protocol_binary_response_no_extras response
= {
792 .magic
= PROTOCOL_BINARY_RES
,
793 .opcode
= PROTOCOL_BINARY_CMD_QUIT
,
794 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
795 .opaque
= header
->request
.opaque
800 if (header
->request
.opcode
== PROTOCOL_BINARY_CMD_QUIT
)
802 response_handler(cookie
, header
, (void*)&response
);
805 /* I need a better way to signal to close the connection */
806 return PROTOCOL_BINARY_RESPONSE_EINTERNAL
;
810 * Callback for REPLACE and REPLACEQ
811 * @param cookie the calling client
812 * @param header the command
813 * @param response_handler not used
814 * @return the result of the operation
816 static protocol_binary_response_status
817 replace_command_handler(const void *cookie
,
818 protocol_binary_request_header
*header
,
819 memcached_binary_protocol_raw_response_handler response_handler
)
821 (void)response_handler
;
822 protocol_binary_response_status rval
;
824 memcached_protocol_client_st
*client
= (void*)cookie
;
825 if (client
->root
->callback
->interface
.v1
.replace
!= NULL
)
827 uint16_t keylen
= ntohs(header
->request
.keylen
);
828 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
829 protocol_binary_request_replace
*request
= (void*)header
;
830 uint32_t flags
= ntohl(request
->message
.body
.flags
);
831 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
832 char *key
= ((char*)header
) + sizeof(*header
) + 8;
833 char *data
= key
+ keylen
;
834 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
837 rval
= client
->root
->callback
->interface
.v1
.replace(cookie
, key
, keylen
,
838 data
, datalen
, flags
,
841 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
842 header
->request
.opcode
== PROTOCOL_BINARY_CMD_REPLACE
)
844 /* Send a positive request */
845 protocol_binary_response_no_extras response
= {
848 .magic
= PROTOCOL_BINARY_RES
,
849 .opcode
= PROTOCOL_BINARY_CMD_REPLACE
,
850 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
851 .opaque
= header
->request
.opaque
,
852 .cas
= memcached_ntohll(result_cas
),
856 rval
= response_handler(cookie
, header
, (void*)&response
);
861 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
868 * Callback for SET and SETQ
869 * @param cookie the calling client
870 * @param header the command
871 * @param response_handler not used
872 * @return the result of the operation
874 static protocol_binary_response_status
set_command_handler(const void *cookie
,
875 protocol_binary_request_header
*header
,
876 memcached_binary_protocol_raw_response_handler response_handler
)
878 (void)response_handler
;
879 protocol_binary_response_status rval
;
881 memcached_protocol_client_st
*client
= (void*)cookie
;
882 if (client
->root
->callback
->interface
.v1
.set
!= NULL
)
884 uint16_t keylen
= ntohs(header
->request
.keylen
);
885 uint32_t datalen
= ntohl(header
->request
.bodylen
) - keylen
- 8;
886 protocol_binary_request_replace
*request
= (void*)header
;
887 uint32_t flags
= ntohl(request
->message
.body
.flags
);
888 uint32_t timeout
= ntohl(request
->message
.body
.expiration
);
889 char *key
= ((char*)header
) + sizeof(*header
) + 8;
890 char *data
= key
+ keylen
;
891 uint64_t cas
= memcached_ntohll(header
->request
.cas
);
895 rval
= client
->root
->callback
->interface
.v1
.set(cookie
, key
, keylen
,
896 data
, datalen
, flags
,
897 timeout
, cas
, &result_cas
);
898 if (rval
== PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
899 header
->request
.opcode
== PROTOCOL_BINARY_CMD_SET
)
901 /* Send a positive request */
902 protocol_binary_response_no_extras response
= {
905 .magic
= PROTOCOL_BINARY_RES
,
906 .opcode
= PROTOCOL_BINARY_CMD_SET
,
907 .status
= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS
),
908 .opaque
= header
->request
.opaque
,
909 .cas
= memcached_ntohll(result_cas
),
913 rval
= response_handler(cookie
, header
, (void*)&response
);
918 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
926 * @param cookie the calling client
927 * @param header the command
928 * @param response_handler not used
929 * @return the result of the operation
931 static protocol_binary_response_status
932 stat_command_handler(const void *cookie
,
933 protocol_binary_request_header
*header
,
934 memcached_binary_protocol_raw_response_handler response_handler
)
936 (void)response_handler
;
937 protocol_binary_response_status rval
;
939 memcached_protocol_client_st
*client
= (void*)cookie
;
940 if (client
->root
->callback
->interface
.v1
.stat
!= NULL
)
942 uint16_t keylen
= ntohs(header
->request
.keylen
);
944 rval
= client
->root
->callback
->interface
.v1
.stat(cookie
,
947 stat_response_handler
);
951 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
958 * Callback for VERSION
959 * @param cookie the calling client
960 * @param header the command
961 * @param response_handler not used
962 * @return the result of the operation
964 static protocol_binary_response_status
965 version_command_handler(const void *cookie
,
966 protocol_binary_request_header
*header
,
967 memcached_binary_protocol_raw_response_handler response_handler
)
969 (void)response_handler
;
971 protocol_binary_response_status rval
;
973 memcached_protocol_client_st
*client
= (void*)cookie
;
974 if (client
->root
->callback
->interface
.v1
.version
!= NULL
)
976 rval
= client
->root
->callback
->interface
.v1
.version(cookie
,
977 version_response_handler
);
981 rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
988 * The map to remap between the com codes and the v1 logical setting
990 static memcached_binary_protocol_command_handler comcode_v0_v1_remap
[256]= {
991 [PROTOCOL_BINARY_CMD_ADDQ
]= add_command_handler
,
992 [PROTOCOL_BINARY_CMD_ADD
]= add_command_handler
,
993 [PROTOCOL_BINARY_CMD_APPENDQ
]= append_command_handler
,
994 [PROTOCOL_BINARY_CMD_APPEND
]= append_command_handler
,
995 [PROTOCOL_BINARY_CMD_DECREMENTQ
]= decrement_command_handler
,
996 [PROTOCOL_BINARY_CMD_DECREMENT
]= decrement_command_handler
,
997 [PROTOCOL_BINARY_CMD_DELETEQ
]= delete_command_handler
,
998 [PROTOCOL_BINARY_CMD_DELETE
]= delete_command_handler
,
999 [PROTOCOL_BINARY_CMD_FLUSHQ
]= flush_command_handler
,
1000 [PROTOCOL_BINARY_CMD_FLUSH
]= flush_command_handler
,
1001 [PROTOCOL_BINARY_CMD_GETKQ
]= get_command_handler
,
1002 [PROTOCOL_BINARY_CMD_GETK
]= get_command_handler
,
1003 [PROTOCOL_BINARY_CMD_GETQ
]= get_command_handler
,
1004 [PROTOCOL_BINARY_CMD_GET
]= get_command_handler
,
1005 [PROTOCOL_BINARY_CMD_INCREMENTQ
]= increment_command_handler
,
1006 [PROTOCOL_BINARY_CMD_INCREMENT
]= increment_command_handler
,
1007 [PROTOCOL_BINARY_CMD_NOOP
]= noop_command_handler
,
1008 [PROTOCOL_BINARY_CMD_PREPENDQ
]= prepend_command_handler
,
1009 [PROTOCOL_BINARY_CMD_PREPEND
]= prepend_command_handler
,
1010 [PROTOCOL_BINARY_CMD_QUITQ
]= quit_command_handler
,
1011 [PROTOCOL_BINARY_CMD_QUIT
]= quit_command_handler
,
1012 [PROTOCOL_BINARY_CMD_REPLACEQ
]= replace_command_handler
,
1013 [PROTOCOL_BINARY_CMD_REPLACE
]= replace_command_handler
,
1014 [PROTOCOL_BINARY_CMD_SETQ
]= set_command_handler
,
1015 [PROTOCOL_BINARY_CMD_SET
]= set_command_handler
,
1016 [PROTOCOL_BINARY_CMD_STAT
]= stat_command_handler
,
1017 [PROTOCOL_BINARY_CMD_VERSION
]= version_command_handler
,
1021 * Try to execute a command. Fire the pre/post functions and the specialized
1022 * handler function if it's set. If not, the unknown probe should be fired
1024 * @param client the client connection to operate on
1025 * @param header the command to execute
1026 * @return true if success or false if a fatal error occured so that the
1027 * connection should be shut down.
1029 static protocol_binary_response_status
execute_command(memcached_protocol_client_st
*client
, protocol_binary_request_header
*header
)
1031 if (client
->root
->pedantic
&&
1032 memcached_binary_protocol_pedantic_check_request(header
))
1034 /* @todo return invalid command packet */
1037 /* we got all data available, execute the callback! */
1038 if (client
->root
->callback
->pre_execute
!= NULL
)
1040 client
->root
->callback
->pre_execute(client
, header
);
1043 protocol_binary_response_status rval
= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
;
1044 uint8_t cc
= header
->request
.opcode
;
1046 if (client
->is_verbose
)
1051 switch (client
->root
->callback
->interface_version
)
1054 if (client
->root
->callback
->interface
.v0
.comcode
[cc
] != NULL
)
1056 rval
= client
->root
->callback
->interface
.v0
.comcode
[cc
](client
, header
, raw_response_handler
);
1061 if (comcode_v0_v1_remap
[cc
] != NULL
)
1063 rval
= comcode_v0_v1_remap
[cc
](client
, header
, raw_response_handler
);
1068 /* Unknown interface.
1069 * It should be impossible to get here so I'll just call abort
1070 * to avoid getting a compiler warning :-)
1076 if (rval
== PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
&&
1077 client
->root
->callback
->unknown
!= NULL
)
1079 rval
= client
->root
->callback
->unknown(client
, header
, raw_response_handler
);
1082 if (rval
!= PROTOCOL_BINARY_RESPONSE_SUCCESS
&&
1083 rval
!= PROTOCOL_BINARY_RESPONSE_EINTERNAL
&&
1084 rval
!= PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED
)
1086 protocol_binary_response_no_extras response
= {
1089 .magic
= PROTOCOL_BINARY_RES
,
1091 .status
= htons(rval
),
1092 .opaque
= header
->request
.opaque
,
1096 rval
= raw_response_handler(client
, header
, (void*)&response
);
1099 if (client
->root
->callback
->post_execute
!= NULL
)
1101 client
->root
->callback
->post_execute(client
, header
);
1108 ** **********************************************************************
1109 ** "PROTOECTED" INTERFACE
1110 ** **********************************************************************
1112 memcached_protocol_event_t
memcached_binary_protocol_process_data(memcached_protocol_client_st
*client
, ssize_t
*length
, void **endptr
)
1114 /* try to parse all of the received packets */
1115 protocol_binary_request_header
*header
;
1116 header
= (void*)client
->root
->input_buffer
;
1117 if (header
->request
.magic
!= (uint8_t)PROTOCOL_BINARY_REQ
)
1119 client
->error
= EINVAL
;
1120 return MEMCACHED_PROTOCOL_ERROR_EVENT
;
1122 ssize_t len
= *length
;
1124 while (len
>= (ssize_t
)sizeof(*header
) &&
1125 (len
>= (ssize_t
)(sizeof(*header
) + ntohl(header
->request
.bodylen
))))
1127 /* I have the complete package */
1128 client
->current_command
= header
;
1129 protocol_binary_response_status rv
= execute_command(client
, header
);
1131 if (rv
== PROTOCOL_BINARY_RESPONSE_EINTERNAL
)
1134 *endptr
= (void*)header
;
1135 return MEMCACHED_PROTOCOL_ERROR_EVENT
;
1137 else if (rv
== PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED
)
1139 return MEMCACHED_PROTOCOL_PAUSE_EVENT
;
1142 ssize_t total
= (ssize_t
)(sizeof(*header
) + ntohl(header
->request
.bodylen
));
1146 intptr_t ptr
= (intptr_t)header
;
1155 memmove(client
->root
->input_buffer
, (void*)ptr
, (size_t)len
);
1156 header
= (void*)client
->root
->input_buffer
;
1160 *endptr
= (void*)header
;
1163 return MEMCACHED_PROTOCOL_READ_EVENT
;
1167 ** **********************************************************************
1169 ** **********************************************************************
1171 memcached_binary_protocol_callback_st
*memcached_binary_protocol_get_callbacks(memcached_protocol_st
*instance
)
1173 return instance
->callback
;
1176 void memcached_binary_protocol_set_callbacks(memcached_protocol_st
*instance
, memcached_binary_protocol_callback_st
*callback
)
1178 instance
->callback
= callback
;
1181 memcached_binary_protocol_raw_response_handler
memcached_binary_protocol_get_raw_response_handler(const void *cookie
)
1184 return raw_response_handler
;
1187 void memcached_binary_protocol_set_pedantic(memcached_protocol_st
*instance
, bool enable
)
1189 instance
->pedantic
= enable
;
1192 bool memcached_binary_protocol_get_pedantic(memcached_protocol_st
*instance
)
1194 return instance
->pedantic
;