1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
6 * Copyright (C) 2006-2009 Brian Aker All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 #include <libmemcached/common.h>
39 #include <libmemcached/string.hpp>
41 static memcached_return_t
textual_read_one_response(memcached_server_write_instance_st ptr
,
42 char *buffer
, size_t buffer_length
,
43 memcached_result_st
*result
);
44 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
45 char *buffer
, size_t buffer_length
,
46 memcached_result_st
*result
);
48 memcached_return_t
memcached_read_one_response(memcached_server_write_instance_st ptr
,
49 char *buffer
, size_t buffer_length
,
50 memcached_result_st
*result
)
52 memcached_server_response_decrement(ptr
);
56 memcached_st
*root
= (memcached_st
*)ptr
->root
;
57 result
= &root
->result
;
60 memcached_return_t rc
;
61 if (ptr
->root
->flags
.binary_protocol
)
63 rc
= binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
67 rc
= textual_read_one_response(ptr
, buffer
, buffer_length
, result
);
70 unlikely(rc
== MEMCACHED_UNKNOWN_READ_FAILURE
or
71 rc
== MEMCACHED_PROTOCOL_ERROR
or
72 rc
== MEMCACHED_CLIENT_ERROR
or
73 rc
== MEMCACHED_MEMORY_ALLOCATION_FAILURE
)
75 memcached_io_reset(ptr
);
81 memcached_return_t
memcached_response(memcached_server_write_instance_st ptr
,
82 char *buffer
, size_t buffer_length
,
83 memcached_result_st
*result
)
85 /* We may have old commands in the buffer not set, first purge */
86 if ((ptr
->root
->flags
.no_block
) && (memcached_is_processing_input(ptr
->root
) == false))
88 (void)memcached_io_write(ptr
, NULL
, 0, true);
92 * The previous implementation purged all pending requests and just
93 * returned the last one. Purge all pending messages to ensure backwards
96 if (ptr
->root
->flags
.binary_protocol
== false)
98 while (memcached_server_response_count(ptr
) > 1)
100 memcached_return_t rc
= memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
102 unlikely (rc
!= MEMCACHED_END
&&
103 rc
!= MEMCACHED_STORED
&&
104 rc
!= MEMCACHED_SUCCESS
&&
105 rc
!= MEMCACHED_STAT
&&
106 rc
!= MEMCACHED_DELETED
&&
107 rc
!= MEMCACHED_NOTFOUND
&&
108 rc
!= MEMCACHED_NOTSTORED
&&
109 rc
!= MEMCACHED_DATA_EXISTS
)
114 return memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
117 static memcached_return_t
textual_value_fetch(memcached_server_write_instance_st ptr
,
119 memcached_result_st
*result
)
126 ssize_t read_length
= 0;
128 if (ptr
->root
->flags
.use_udp
)
130 return memcached_set_error(*ptr
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
133 WATCHPOINT_ASSERT(ptr
->root
);
134 end_ptr
= buffer
+ MEMCACHED_DEFAULT_COMMAND_SIZE
;
136 memcached_result_reset(result
);
139 string_ptr
+= 6; /* "VALUE " */
142 /* We load the key */
145 size_t prefix_length
;
147 key
= result
->item_key
;
148 result
->key_length
= 0;
150 for (prefix_length
= memcached_array_size(ptr
->root
->_namespace
); !(iscntrl(*string_ptr
) || isspace(*string_ptr
)) ; string_ptr
++)
152 if (prefix_length
== 0)
156 result
->key_length
++;
161 result
->item_key
[result
->key_length
]= 0;
164 if (end_ptr
== string_ptr
)
167 /* Flags fetch move past space */
169 if (end_ptr
== string_ptr
)
172 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
173 result
->item_flags
= (uint32_t) strtoul(next_ptr
, &string_ptr
, 10);
175 if (end_ptr
== string_ptr
)
178 /* Length fetch move past space*/
180 if (end_ptr
== string_ptr
)
183 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
184 value_length
= (size_t)strtoull(next_ptr
, &string_ptr
, 10);
186 if (end_ptr
== string_ptr
)
192 if (*string_ptr
== '\r')
194 /* Skip past the \r\n */
200 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
201 result
->item_cas
= strtoull(next_ptr
, &string_ptr
, 10);
204 if (end_ptr
< string_ptr
)
207 /* We add two bytes so that we can walk the \r\n */
208 if (memcached_failed(memcached_string_check(&result
->value
, value_length
+2)))
210 return memcached_set_error(*ptr
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
, MEMCACHED_AT
);
214 char *value_ptr
= memcached_string_value_mutable(&result
->value
);
216 We read the \r\n into the string since not doing so is more
217 cycles then the waster of memory to do so.
219 We are null terminating through, which will most likely make
220 some people lazy about using the return length.
222 to_read
= (value_length
) + 2;
223 memcached_return_t rrc
= memcached_io_read(ptr
, value_ptr
, to_read
, &read_length
);
224 if (memcached_failed(rrc
) and rrc
== MEMCACHED_IN_PROGRESS
)
226 memcached_quit_server(ptr
, true);
227 return memcached_set_error(*ptr
, MEMCACHED_IN_PROGRESS
, MEMCACHED_AT
);
229 else if (memcached_failed(rrc
))
235 if (read_length
!= (ssize_t
)(value_length
+ 2))
240 /* This next bit blows the API, but this is internal....*/
243 char_ptr
= memcached_string_value_mutable(&result
->value
);;
244 char_ptr
[value_length
]= 0;
245 char_ptr
[value_length
+1]= 0;
246 memcached_string_set_length(&result
->value
, value_length
);
249 return MEMCACHED_SUCCESS
;
252 memcached_io_reset(ptr
);
254 return MEMCACHED_PARTIAL_READ
;
257 static memcached_return_t
textual_read_one_response(memcached_server_write_instance_st ptr
,
258 char *buffer
, size_t buffer_length
,
259 memcached_result_st
*result
)
262 memcached_return_t rc
= memcached_io_readline(ptr
, buffer
, buffer_length
, total_read
);
264 if (memcached_failed(rc
))
271 case 'V': /* VALUE || VERSION */
272 if (buffer
[1] == 'A') /* VALUE */
274 /* We add back in one because we will need to search for END */
275 memcached_server_response_increment(ptr
);
276 return textual_value_fetch(ptr
, buffer
, result
);
278 else if (buffer
[1] == 'E') /* VERSION */
280 return MEMCACHED_SUCCESS
;
284 WATCHPOINT_STRING(buffer
);
285 return MEMCACHED_UNKNOWN_READ_FAILURE
;
288 return MEMCACHED_SUCCESS
;
290 case 'S': /* STORED STATS SERVER_ERROR */
292 if (buffer
[2] == 'A') /* STORED STATS */
294 memcached_server_response_increment(ptr
);
295 return MEMCACHED_STAT
;
297 else if (buffer
[1] == 'E') /* SERVER_ERROR */
299 if (total_read
== memcached_literal_param_size("SERVER_ERROR"))
301 return MEMCACHED_SERVER_ERROR
;
304 if (total_read
> memcached_literal_param_size("SERVER_ERROR object too large for cache") and
305 (memcmp(buffer
, memcached_literal_param("SERVER_ERROR object too large for cache")) == 0))
307 return MEMCACHED_E2BIG
;
310 // Move past the basic error message and whitespace
311 char *startptr
= buffer
+ memcached_literal_param_size("SERVER_ERROR");
312 if (startptr
[0] == ' ')
317 char *endptr
= startptr
;
318 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
320 return memcached_set_error(*ptr
, MEMCACHED_SERVER_ERROR
, MEMCACHED_AT
, startptr
, size_t(endptr
- startptr
));
322 else if (buffer
[1] == 'T')
324 return MEMCACHED_STORED
;
328 WATCHPOINT_STRING(buffer
);
329 return MEMCACHED_UNKNOWN_READ_FAILURE
;
332 case 'D': /* DELETED */
333 return MEMCACHED_DELETED
;
335 case 'N': /* NOT_FOUND */
337 if (buffer
[4] == 'F')
339 return MEMCACHED_NOTFOUND
;
341 else if (buffer
[4] == 'S')
343 return MEMCACHED_NOTSTORED
;
347 WATCHPOINT_STRING(buffer
);
348 return MEMCACHED_UNKNOWN_READ_FAILURE
;
351 case 'E': /* PROTOCOL ERROR or END */
353 if (buffer
[1] == 'N')
355 return MEMCACHED_END
;
357 else if (buffer
[1] == 'R' and buffer
[2] == 'R' and buffer
[3] == 'O' and buffer
[4] == 'R')
359 return MEMCACHED_PROTOCOL_ERROR
;
361 else if (buffer
[1] == 'X')
363 return MEMCACHED_DATA_EXISTS
;
367 WATCHPOINT_STRING(buffer
);
368 return MEMCACHED_UNKNOWN_READ_FAILURE
;
372 case 'T': /* TOUCHED */
374 if (buffer
[1] == 'O' and buffer
[2] == 'U'
375 and buffer
[3] == 'C' and buffer
[4] == 'H'
376 and buffer
[5] == 'E' and buffer
[6] == 'D')
378 return MEMCACHED_SUCCESS
;
381 return MEMCACHED_UNKNOWN_READ_FAILURE
;
384 /* We add back in one because we will need to search for END */
385 memcached_server_response_increment(ptr
);
386 return MEMCACHED_ITEM
;
388 case 'C': /* CLIENT ERROR */
389 return MEMCACHED_CLIENT_ERROR
;
393 unsigned long long int auto_return_value
= strtoull(buffer
, (char **)NULL
, 10);
395 if (auto_return_value
== ULLONG_MAX
and errno
== ERANGE
)
397 return MEMCACHED_UNKNOWN_READ_FAILURE
;
399 else if (errno
== EINVAL
)
401 return MEMCACHED_UNKNOWN_READ_FAILURE
;
404 WATCHPOINT_STRING(buffer
);
405 return MEMCACHED_SUCCESS
;
412 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
413 char *buffer
, size_t buffer_length
,
414 memcached_result_st
*result
)
416 memcached_return_t rc
;
417 protocol_binary_response_header header
;
419 if ((rc
= memcached_safe_read(ptr
, &header
.bytes
, sizeof(header
.bytes
))) != MEMCACHED_SUCCESS
)
421 WATCHPOINT_ERROR(rc
);
425 if (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
427 return MEMCACHED_PROTOCOL_ERROR
;
431 ** Convert the header to host local endian!
433 header
.response
.keylen
= ntohs(header
.response
.keylen
);
434 header
.response
.status
= ntohs(header
.response
.status
);
435 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
436 header
.response
.cas
= memcached_ntohll(header
.response
.cas
);
437 uint32_t bodylen
= header
.response
.bodylen
;
439 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
or
440 header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
442 switch (header
.response
.opcode
)
444 case PROTOCOL_BINARY_CMD_GETKQ
:
446 * We didn't increment the response counter for the GETKQ packet
447 * (only the final NOOP), so we need to increment the counter again.
449 memcached_server_response_increment(ptr
);
451 case PROTOCOL_BINARY_CMD_GETK
:
453 uint16_t keylen
= header
.response
.keylen
;
454 memcached_result_reset(result
);
455 result
->item_cas
= header
.response
.cas
;
457 if ((rc
= memcached_safe_read(ptr
, &result
->item_flags
, sizeof (result
->item_flags
))) != MEMCACHED_SUCCESS
)
459 WATCHPOINT_ERROR(rc
);
460 return MEMCACHED_UNKNOWN_READ_FAILURE
;
463 result
->item_flags
= ntohl(result
->item_flags
);
464 bodylen
-= header
.response
.extlen
;
466 result
->key_length
= keylen
;
467 if (memcached_failed(rc
= memcached_safe_read(ptr
, result
->item_key
, keylen
)))
469 WATCHPOINT_ERROR(rc
);
470 return MEMCACHED_UNKNOWN_READ_FAILURE
;
473 // Only bother with doing this if key_length > 0
474 if (result
->key_length
)
476 if (memcached_array_size(ptr
->root
->_namespace
) and memcached_array_size(ptr
->root
->_namespace
) >= result
->key_length
)
478 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
481 if (memcached_array_size(ptr
->root
->_namespace
))
483 result
->key_length
-= memcached_array_size(ptr
->root
->_namespace
);
484 memmove(result
->item_key
, result
->item_key
+memcached_array_size(ptr
->root
->_namespace
), result
->key_length
);
489 if (memcached_failed(memcached_string_check(&result
->value
, bodylen
)))
491 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
494 char *vptr
= memcached_string_value_mutable(&result
->value
);
495 if (memcached_failed(rc
= memcached_safe_read(ptr
, vptr
, bodylen
)))
497 WATCHPOINT_ERROR(rc
);
498 return MEMCACHED_UNKNOWN_READ_FAILURE
;
501 memcached_string_set_length(&result
->value
, bodylen
);
505 case PROTOCOL_BINARY_CMD_INCREMENT
:
506 case PROTOCOL_BINARY_CMD_DECREMENT
:
508 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
510 return MEMCACHED_PROTOCOL_ERROR
;
513 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
515 if ((rc
= memcached_safe_read(ptr
, &val
, sizeof(val
))) != MEMCACHED_SUCCESS
)
517 WATCHPOINT_ERROR(rc
);
518 return MEMCACHED_UNKNOWN_READ_FAILURE
;
521 val
= memcached_ntohll(val
);
522 memcpy(buffer
, &val
, sizeof(val
));
526 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
527 case PROTOCOL_BINARY_CMD_VERSION
:
529 memset(buffer
, 0, buffer_length
);
530 if (bodylen
>= buffer_length
)
532 /* not enough space in buffer.. should not happen... */
533 return MEMCACHED_UNKNOWN_READ_FAILURE
;
535 else if ((rc
= memcached_safe_read(ptr
, buffer
, bodylen
)) != MEMCACHED_SUCCESS
)
537 WATCHPOINT_ERROR(rc
);
538 return MEMCACHED_UNKNOWN_READ_FAILURE
;
542 case PROTOCOL_BINARY_CMD_FLUSH
:
543 case PROTOCOL_BINARY_CMD_QUIT
:
544 case PROTOCOL_BINARY_CMD_SET
:
545 case PROTOCOL_BINARY_CMD_ADD
:
546 case PROTOCOL_BINARY_CMD_REPLACE
:
547 case PROTOCOL_BINARY_CMD_APPEND
:
548 case PROTOCOL_BINARY_CMD_PREPEND
:
549 case PROTOCOL_BINARY_CMD_DELETE
:
550 case PROTOCOL_BINARY_CMD_TOUCH
:
552 WATCHPOINT_ASSERT(bodylen
== 0);
553 return MEMCACHED_SUCCESS
;
556 case PROTOCOL_BINARY_CMD_NOOP
:
558 WATCHPOINT_ASSERT(bodylen
== 0);
559 return MEMCACHED_END
;
562 case PROTOCOL_BINARY_CMD_STAT
:
566 return MEMCACHED_END
;
568 else if (bodylen
+ 1 > buffer_length
)
570 /* not enough space in buffer.. should not happen... */
571 return MEMCACHED_UNKNOWN_READ_FAILURE
;
575 size_t keylen
= header
.response
.keylen
;
576 memset(buffer
, 0, buffer_length
);
577 if ((rc
= memcached_safe_read(ptr
, buffer
, keylen
)) != MEMCACHED_SUCCESS
||
578 (rc
= memcached_safe_read(ptr
, buffer
+ keylen
+ 1, bodylen
- keylen
)) != MEMCACHED_SUCCESS
)
580 WATCHPOINT_ERROR(rc
);
581 return MEMCACHED_UNKNOWN_READ_FAILURE
;
587 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
588 case PROTOCOL_BINARY_CMD_SASL_STEP
:
590 memcached_result_reset(result
);
591 result
->item_cas
= header
.response
.cas
;
593 if (memcached_string_check(&result
->value
,
594 bodylen
) != MEMCACHED_SUCCESS
)
595 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
597 char *vptr
= memcached_string_value_mutable(&result
->value
);
598 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
600 WATCHPOINT_ERROR(rc
);
601 return MEMCACHED_UNKNOWN_READ_FAILURE
;
604 memcached_string_set_length(&result
->value
, bodylen
);
609 /* Command not implemented yet! */
610 WATCHPOINT_ASSERT(0);
611 return MEMCACHED_PROTOCOL_ERROR
;
615 else if (header
.response
.bodylen
)
617 /* What should I do with the error message??? just discard it for now */
618 char hole
[SMALL_STRING_LEN
];
621 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
622 if ((rc
= memcached_safe_read(ptr
, hole
, nr
)) != MEMCACHED_SUCCESS
)
624 WATCHPOINT_ERROR(rc
);
625 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
627 bodylen
-= (uint32_t) nr
;
630 /* This might be an error from one of the quiet commands.. if
631 * so, just throw it away and get the next one. What about creating
632 * a callback to the user with the error information?
634 switch (header
.response
.opcode
)
636 case PROTOCOL_BINARY_CMD_SETQ
:
637 case PROTOCOL_BINARY_CMD_ADDQ
:
638 case PROTOCOL_BINARY_CMD_REPLACEQ
:
639 case PROTOCOL_BINARY_CMD_APPENDQ
:
640 case PROTOCOL_BINARY_CMD_PREPENDQ
:
641 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
648 rc
= MEMCACHED_SUCCESS
;
649 if (header
.response
.status
!= 0)
651 switch (header
.response
.status
)
653 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
654 rc
= MEMCACHED_NOTFOUND
;
657 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
658 rc
= MEMCACHED_DATA_EXISTS
;
661 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
662 rc
= MEMCACHED_NOTSTORED
;
665 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
669 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
670 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
673 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
674 rc
= MEMCACHED_AUTH_CONTINUE
;
677 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
678 rc
= MEMCACHED_AUTH_FAILURE
;
681 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
682 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
684 /* @todo fix the error mappings */
685 rc
= MEMCACHED_PROTOCOL_ERROR
;