src/libmemcachedprotocol: apply clang-format
[awesomized/libmemcached] / src / libmemcachedprotocol / binary_handler.c
1 /*
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 +--------------------------------------------------------------------+
14 */
15
16 #include "libmemcachedprotocol/common.h"
17
18 #include <stdlib.h>
19 #include <sys/types.h>
20 #include <errno.h>
21 #include <stdbool.h>
22 #include <string.h>
23 #include <stdio.h>
24
25 /*
26 ** **********************************************************************
27 ** INTERNAL INTERFACE
28 ** **********************************************************************
29 */
30
31 /**
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.
35 *
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
40 */
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;
45
46 if (client->root->pedantic
47 && !memcached_binary_protocol_pedantic_check_response(request, response)) {
48 return PROTOCOL_BINARY_RESPONSE_EINVAL;
49 }
50
51 if (client->root->drain(client) == false) {
52 return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
53 }
54
55 size_t len = sizeof(protocol_binary_response_header) + htonl(response->response.bodylen);
56 size_t offset = 0;
57 char *ptr = (void *) response;
58
59 if (client->output == NULL) {
60 /* I can write directly to the socket.... */
61 do {
62 size_t num_bytes = len - offset;
63 ssize_t nw = client->root->send(client, client->sock, ptr + offset, num_bytes);
64 if (nw == -1) {
65 if (get_socket_errno() == EWOULDBLOCK) {
66 break;
67 } else if (get_socket_errno() != EINTR) {
68 client->error = errno;
69 return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
70 }
71 } else {
72 offset += (size_t) nw;
73 }
74 } while (offset < len);
75 }
76
77 return client->root->spool(client, ptr, len - offset);
78 }
79
80 static void print_cmd(protocol_binary_command cmd) {
81 switch (cmd) {
82 case PROTOCOL_BINARY_CMD_GET:
83 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GET\n", __FILE__, __LINE__);
84 return;
85 case PROTOCOL_BINARY_CMD_SET:
86 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SET\n", __FILE__, __LINE__);
87 return;
88 case PROTOCOL_BINARY_CMD_ADD:
89 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_ADD\n", __FILE__, __LINE__);
90 return;
91 case PROTOCOL_BINARY_CMD_REPLACE:
92 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_REPLACE\n", __FILE__, __LINE__);
93 return;
94 case PROTOCOL_BINARY_CMD_DELETE:
95 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DELETE\n", __FILE__, __LINE__);
96 return;
97 case PROTOCOL_BINARY_CMD_INCREMENT:
98 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_INCREMENT\n", __FILE__, __LINE__);
99 return;
100 case PROTOCOL_BINARY_CMD_DECREMENT:
101 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DECREMENT\n", __FILE__, __LINE__);
102 return;
103 case PROTOCOL_BINARY_CMD_QUIT:
104 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_QUIT\n", __FILE__, __LINE__);
105 return;
106 case PROTOCOL_BINARY_CMD_FLUSH:
107 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_FLUSH\n", __FILE__, __LINE__);
108 return;
109 case PROTOCOL_BINARY_CMD_GETQ:
110 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GETQ\n", __FILE__, __LINE__);
111 return;
112 case PROTOCOL_BINARY_CMD_NOOP:
113 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_NOOP\n", __FILE__, __LINE__);
114 return;
115 case PROTOCOL_BINARY_CMD_VERSION:
116 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_VERSION\n", __FILE__, __LINE__);
117 return;
118 case PROTOCOL_BINARY_CMD_GETK:
119 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GETK\n", __FILE__, __LINE__);
120 return;
121 case PROTOCOL_BINARY_CMD_GETKQ:
122 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GETKQ\n", __FILE__, __LINE__);
123 return;
124 case PROTOCOL_BINARY_CMD_APPEND:
125 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_APPEND\n", __FILE__, __LINE__);
126 return;
127 case PROTOCOL_BINARY_CMD_PREPEND:
128 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_PREPEND\n", __FILE__, __LINE__);
129 return;
130 case PROTOCOL_BINARY_CMD_STAT:
131 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_STAT\n", __FILE__, __LINE__);
132 return;
133 case PROTOCOL_BINARY_CMD_SETQ:
134 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SETQ\n", __FILE__, __LINE__);
135 return;
136 case PROTOCOL_BINARY_CMD_ADDQ:
137 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_ADDQ\n", __FILE__, __LINE__);
138 return;
139 case PROTOCOL_BINARY_CMD_REPLACEQ:
140 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_REPLACEQ\n", __FILE__, __LINE__);
141 return;
142 case PROTOCOL_BINARY_CMD_DELETEQ:
143 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DELETEQ\n", __FILE__, __LINE__);
144 return;
145 case PROTOCOL_BINARY_CMD_INCREMENTQ:
146 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_INCREMENTQ\n", __FILE__, __LINE__);
147 return;
148 case PROTOCOL_BINARY_CMD_DECREMENTQ:
149 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DECREMENTQ\n", __FILE__, __LINE__);
150 return;
151 case PROTOCOL_BINARY_CMD_QUITQ:
152 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_QUITQ\n", __FILE__, __LINE__);
153 return;
154 case PROTOCOL_BINARY_CMD_FLUSHQ:
155 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_FLUSHQ\n", __FILE__, __LINE__);
156 return;
157 case PROTOCOL_BINARY_CMD_APPENDQ:
158 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_APPENDQ\n", __FILE__, __LINE__);
159 return;
160 case PROTOCOL_BINARY_CMD_PREPENDQ:
161 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_PREPENDQ\n", __FILE__, __LINE__);
162 return;
163 case PROTOCOL_BINARY_CMD_VERBOSITY:
164 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_VERBOSITY\n", __FILE__, __LINE__);
165 return;
166 case PROTOCOL_BINARY_CMD_TOUCH:
167 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TOUCH\n", __FILE__, __LINE__);
168 return;
169 case PROTOCOL_BINARY_CMD_GAT:
170 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GAT\n", __FILE__, __LINE__);
171 return;
172 case PROTOCOL_BINARY_CMD_GATQ:
173 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GATQ\n", __FILE__, __LINE__);
174 return;
175 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS:
176 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SASL_LIST_MECHS\n", __FILE__, __LINE__);
177 return;
178 case PROTOCOL_BINARY_CMD_SASL_AUTH:
179 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SASL_AUTH\n", __FILE__, __LINE__);
180 return;
181 case PROTOCOL_BINARY_CMD_SASL_STEP:
182 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SASL_STEP\n", __FILE__, __LINE__);
183 return;
184 case PROTOCOL_BINARY_CMD_RGET:
185 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RGET\n", __FILE__, __LINE__);
186 return;
187 case PROTOCOL_BINARY_CMD_RSET:
188 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RSET\n", __FILE__, __LINE__);
189 return;
190 case PROTOCOL_BINARY_CMD_RSETQ:
191 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RSETQ\n", __FILE__, __LINE__);
192 return;
193 case PROTOCOL_BINARY_CMD_RAPPEND:
194 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RAPPEND\n", __FILE__, __LINE__);
195 return;
196 case PROTOCOL_BINARY_CMD_RAPPENDQ:
197 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RAPPENDQ\n", __FILE__, __LINE__);
198 return;
199 case PROTOCOL_BINARY_CMD_RPREPEND:
200 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RPREPEND\n", __FILE__, __LINE__);
201 return;
202 case PROTOCOL_BINARY_CMD_RPREPENDQ:
203 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RPREPENDQ\n", __FILE__, __LINE__);
204 return;
205 case PROTOCOL_BINARY_CMD_RDELETE:
206 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RDELETE\n", __FILE__, __LINE__);
207 return;
208 case PROTOCOL_BINARY_CMD_RDELETEQ:
209 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RDELETEQ\n", __FILE__, __LINE__);
210 return;
211 case PROTOCOL_BINARY_CMD_RINCR:
212 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RINCR\n", __FILE__, __LINE__);
213 return;
214 case PROTOCOL_BINARY_CMD_RINCRQ:
215 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RINCRQ\n", __FILE__, __LINE__);
216 return;
217 case PROTOCOL_BINARY_CMD_RDECR:
218 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RDECR\n", __FILE__, __LINE__);
219 return;
220 case PROTOCOL_BINARY_CMD_RDECRQ:
221 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RDECRQ\n", __FILE__, __LINE__);
222 return;
223 case PROTOCOL_BINARY_CMD_SET_VBUCKET:
224 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SET_VBUCKET\n", __FILE__, __LINE__);
225 return;
226 case PROTOCOL_BINARY_CMD_GET_VBUCKET:
227 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GET_VBUCKET\n", __FILE__, __LINE__);
228 return;
229 case PROTOCOL_BINARY_CMD_DEL_VBUCKET:
230 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DEL_VBUCKET\n", __FILE__, __LINE__);
231 return;
232 case PROTOCOL_BINARY_CMD_TAP_CONNECT:
233 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_CONNECT\n", __FILE__, __LINE__);
234 return;
235 case PROTOCOL_BINARY_CMD_TAP_MUTATION:
236 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_MUTATION\n", __FILE__, __LINE__);
237 return;
238 case PROTOCOL_BINARY_CMD_TAP_DELETE:
239 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_DELETE\n", __FILE__, __LINE__);
240 return;
241 case PROTOCOL_BINARY_CMD_TAP_FLUSH:
242 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_FLUSH\n", __FILE__, __LINE__);
243 return;
244 case PROTOCOL_BINARY_CMD_TAP_OPAQUE:
245 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_OPAQUE\n", __FILE__, __LINE__);
246 return;
247 case PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET:
248 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET\n", __FILE__, __LINE__);
249 return;
250 case PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START:
251 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START\n", __FILE__, __LINE__);
252 return;
253 case PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END:
254 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END\n", __FILE__, __LINE__);
255 return;
256 case PROTOCOL_BINARY_CMD_LAST_RESERVED:
257 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_LAST_RESERVED\n", __FILE__, __LINE__);
258 return;
259 case PROTOCOL_BINARY_CMD_GATK:
260 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GATK\n", __FILE__, __LINE__);
261 return;
262 case PROTOCOL_BINARY_CMD_GATKQ:
263 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GATKQ\n", __FILE__, __LINE__);
264 return;
265 case PROTOCOL_BINARY_CMD_SCRUB:
266 fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SCRUB\n", __FILE__, __LINE__);
267 return;
268 default: abort();
269 }
270 }
271
272 /*
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 :-)
278 */
279
280 /**
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
289 */
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,
293 uint64_t cas) {
294 memcached_protocol_client_st *client = (void *) cookie;
295 uint8_t opcode = client->current_command->request.opcode;
296
297 if (opcode == PROTOCOL_BINARY_CMD_GET || opcode == PROTOCOL_BINARY_CMD_GETQ) {
298 keylen = 0;
299 }
300
301 protocol_binary_response_get response = {
302 .message.header.response =
303 {
304 .magic = PROTOCOL_BINARY_RES,
305 .opcode = opcode,
306 .status = htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
307 .opaque = client->current_command->request.opaque,
308 .cas = memcached_htonll(cas),
309 .keylen = htons(keylen),
310 .extlen = 4,
311 .bodylen = htonl(bodylen + keylen + 4),
312 },
313 };
314
315 response.message.body.flags = htonl(flags);
316
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)
322 {
323 return rval;
324 }
325
326 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
327 }
328
329 /**
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
336 */
337 static protocol_binary_response_status stat_response_handler(const void *cookie, const void *key,
338 uint16_t keylen, const void *body,
339 uint32_t bodylen) {
340 memcached_protocol_client_st *client = (void *) cookie;
341
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),
349 .cas = 0},
350 };
351
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)
357 {
358 return rval;
359 }
360
361 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
362 }
363
364 /**
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
369 */
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;
373
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),
380 .cas = 0},
381 };
382
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)
387 {
388 return rval;
389 }
390
391 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
392 }
393
394 /**
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
400 */
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;
405
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;
415 uint64_t cas;
416
417 rval = client->root->callback->interface.v1.add(cookie, key, keylen, data, datalen, flags,
418 timeout, &cas);
419
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);
430 }
431 } else {
432 rval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
433 }
434
435 return rval;
436 }
437
438 /**
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
444 */
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;
450
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);
459 uint64_t result;
460 uint64_t cas;
461
462 rval = client->root->callback->interface.v1.decrement(cookie, key, keylen, delta, init, timeout,
463 &result, &cas);
464 if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS
465 && header->request.opcode == PROTOCOL_BINARY_CMD_DECREMENT)
466 {
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);
477 }
478 } else {
479 rval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
480 }
481
482 return rval;
483 }
484
485 /**
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
491 */
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;
497
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)
506 {
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,
514 }}};
515 rval = response_handler(cookie, header, (void *) &response);
516 }
517 } else {
518 rval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
519 }
520
521 return rval;
522 }
523
524 /**
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
530 */
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;
536
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);
543 }
544
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,
555 }}};
556 rval = response_handler(cookie, header, (void *) &response);
557 }
558 } else {
559 rval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
560 }
561
562 return rval;
563 }
564
565 /**
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
571 */
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;
577
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);
583
584 if (rval == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
585 && (header->request.opcode == PROTOCOL_BINARY_CMD_GETQ
586 || header->request.opcode == PROTOCOL_BINARY_CMD_GETKQ))
587 {
588 /* Quiet commands shouldn't respond on cache misses */
589 rval = PROTOCOL_BINARY_RESPONSE_SUCCESS;
590 }
591 } else {
592 rval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
593 }
594
595 return rval;
596 }
597
598 /**
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
604 */
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;
610
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);
619 uint64_t cas;
620 uint64_t result;
621
622 rval = client->root->callback->interface.v1.increment(cookie, key, keylen, delta, init, timeout,
623 &result, &cas);
624 if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS
625 && header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENT)
626 {
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)}};
636
637 rval = response_handler(cookie, header, (void *) &response);
638 }
639 } else {
640 rval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
641 }
642
643 return rval;
644 }
645
646 /**
647 * Callback for noop. Inform the v1 interface about the noop packet, and
648 * create and send a packet back to the client
649 *
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
654 */
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);
661 }
662
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,
669 }}};
670
671 return response_handler(cookie, header, (void *) &response);
672 }
673
674 /**
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
680 */
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;
686
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);
694 uint64_t result_cas;
695
696 rval = client->root->callback->interface.v1.append(cookie, key, keylen, data, datalen, cas,
697 &result_cas);
698 if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS
699 && header->request.opcode == PROTOCOL_BINARY_CMD_APPEND)
700 {
701 /* Send a positive request */
702 protocol_binary_response_no_extras response = {
703 .message = {
704 .header.response =
705 {
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),
711 },
712 }};
713 rval = response_handler(cookie, header, (void *) &response);
714 }
715 } else {
716 rval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
717 }
718
719 return rval;
720 }
721
722 /**
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
728 */
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;
734
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);
742 uint64_t result_cas;
743 rval = client->root->callback->interface.v1.prepend(cookie, key, keylen, data, datalen, cas,
744 &result_cas);
745 if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS
746 && header->request.opcode == PROTOCOL_BINARY_CMD_PREPEND)
747 {
748 /* Send a positive request */
749 protocol_binary_response_no_extras response = {
750 .message = {
751 .header.response =
752 {
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),
758 },
759 }};
760 rval = response_handler(cookie, header, (void *) &response);
761 }
762 } else {
763 rval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
764 }
765
766 return rval;
767 }
768
769 /**
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
775 */
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);
782 }
783
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}}};
789
790 if (header->request.opcode == PROTOCOL_BINARY_CMD_QUIT) {
791 response_handler(cookie, header, (void *) &response);
792 }
793
794 /* I need a better way to signal to close the connection */
795 return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
796 }
797
798 /**
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
804 */
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;
810
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);
821 uint64_t result_cas;
822
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)
827 {
828 /* Send a positive request */
829 protocol_binary_response_no_extras response = {
830 .message = {
831 .header.response =
832 {
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),
838 },
839 }};
840 rval = response_handler(cookie, header, (void *) &response);
841 }
842 } else {
843 rval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
844 }
845
846 return rval;
847 }
848
849 /**
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
855 */
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;
861
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);
872 uint64_t result_cas;
873
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 = {
880 .message = {
881 .header.response =
882 {
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),
888 },
889 }};
890 rval = response_handler(cookie, header, (void *) &response);
891 }
892 } else {
893 rval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
894 }
895
896 return rval;
897 }
898
899 /**
900 * Callback for STAT
901 * @param cookie the calling client
902 * @param header the command
903 * @param response_handler not used
904 * @return the result of the operation
905 */
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;
911
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);
915
916 rval = client->root->callback->interface.v1.stat(cookie, (void *) (header + 1), keylen,
917 stat_response_handler);
918 } else {
919 rval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
920 }
921
922 return rval;
923 }
924
925 /**
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
931 */
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;
936 (void) header;
937 protocol_binary_response_status rval;
938
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);
942 } else {
943 rval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
944 }
945
946 return rval;
947 }
948
949 /**
950 * The map to remap between the com codes and the v1 logical setting
951 */
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,
980 };
981
982 /**
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
985 * if it's present.
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.
990 */
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 */
995 }
996
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);
1000 }
1001
1002 protocol_binary_response_status rval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
1003 uint8_t cc = header->request.opcode;
1004
1005 if (client->is_verbose) {
1006 print_cmd(cc);
1007 }
1008
1009 switch (client->root->callback->interface_version) {
1010 case 0:
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);
1014 }
1015 break;
1016
1017 case 1:
1018 if (comcode_v0_v1_remap[cc] != NULL) {
1019 rval = comcode_v0_v1_remap[cc](client, header, binary_raw_response_handler);
1020 }
1021 break;
1022
1023 default:
1024 /* Unknown interface.
1025 * It should be impossible to get here so I'll just call abort
1026 * to avoid getting a compiler warning :-)
1027 */
1028 abort();
1029 }
1030
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);
1033 }
1034
1035 if (rval != PROTOCOL_BINARY_RESPONSE_SUCCESS && rval != PROTOCOL_BINARY_RESPONSE_EINTERNAL
1036 && rval != PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED)
1037 {
1038 protocol_binary_response_no_extras response = {.message = {
1039 .header.response =
1040 {
1041 .magic = PROTOCOL_BINARY_RES,
1042 .opcode = cc,
1043 .status = htons(rval),
1044 .opaque = header->request.opaque,
1045 },
1046 }};
1047 rval = binary_raw_response_handler(client, header, (void *) &response);
1048 }
1049
1050 if (client->root->callback->post_execute != NULL) {
1051 client->root->callback->post_execute(client, header);
1052 }
1053
1054 return rval;
1055 }
1056
1057 /*
1058 ** **********************************************************************
1059 ** "PROTOECTED" INTERFACE
1060 ** **********************************************************************
1061 */
1062 memcached_protocol_event_t
1063 memcached_binary_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length,
1064 void **endptr) {
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;
1071 }
1072 ssize_t len = *length;
1073
1074 while (len >= (ssize_t) sizeof(*header)
1075 && (len >= (ssize_t)(sizeof(*header) + ntohl(header->request.bodylen))))
1076 {
1077 /* I have the complete package */
1078 client->current_command = header;
1079 protocol_binary_response_status rv = execute_command(client, header);
1080
1081 if (rv == PROTOCOL_BINARY_RESPONSE_EINTERNAL) {
1082 *length = len;
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;
1087 }
1088
1089 ssize_t total = (ssize_t)(sizeof(*header) + ntohl(header->request.bodylen));
1090 len -= total;
1091 if (len > 0) {
1092 intptr_t ptr = (intptr_t) header;
1093 ptr += total;
1094 if ((ptr % 8) == 0) {
1095 header = (void *) ptr;
1096 } else {
1097 /* Fix alignment */
1098 memmove(client->root->input_buffer, (void *) ptr, (size_t) len);
1099 header = (void *) client->root->input_buffer;
1100 }
1101 }
1102 *length = len;
1103 *endptr = (void *) header;
1104 }
1105
1106 return MEMCACHED_PROTOCOL_READ_EVENT;
1107 }
1108
1109 /*
1110 ** **********************************************************************
1111 ** PUBLIC INTERFACE
1112 ** **********************************************************************
1113 */
1114 memcached_binary_protocol_callback_st *
1115 memcached_binary_protocol_get_callbacks(memcached_protocol_st *instance) {
1116 return instance->callback;
1117 }
1118
1119 void memcached_binary_protocol_set_callbacks(memcached_protocol_st *instance,
1120 memcached_binary_protocol_callback_st *callback) {
1121 instance->callback = callback;
1122 }
1123
1124 memcached_binary_protocol_raw_response_handler
1125 memcached_binary_protocol_get_raw_response_handler(const void *cookie) {
1126 (void) cookie;
1127 return binary_raw_response_handler;
1128 }
1129
1130 void memcached_binary_protocol_set_pedantic(memcached_protocol_st *instance, bool enable) {
1131 instance->pedantic = enable;
1132 }
1133
1134 bool memcached_binary_protocol_get_pedantic(memcached_protocol_st *instance) {
1135 return instance->pedantic;
1136 }