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' and buffer
[2] == 'L' and buffer
[3] == 'U' and buffer
[4] == 'E') /* 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' and buffer
[2] == 'R' and buffer
[3] == 'S' and buffer
[4] == 'I' and buffer
[5] == 'O' and buffer
[6] == 'N') /* VERSION */
280 return MEMCACHED_SUCCESS
;
285 if (buffer
[1] == 'K')
287 return MEMCACHED_SUCCESS
;
291 case 'S': /* STORED STATS SERVER_ERROR */
293 if (buffer
[1] == 'T' and buffer
[2] == 'A' and buffer
[3] == 'T') /* STORED STATS */
295 memcached_server_response_increment(ptr
);
296 return MEMCACHED_STAT
;
298 else if (buffer
[1] == 'E' and buffer
[2] == 'R' and buffer
[3] == 'V' and buffer
[4] == 'E' and buffer
[5] == 'R'
300 and buffer
[7] == 'E' and buffer
[8] == 'R' and buffer
[9] == 'R' and buffer
[10] == 'O' and buffer
[11] == 'R' ) /* SERVER_ERROR */
302 if (total_read
== memcached_literal_param_size("SERVER_ERROR"))
304 return MEMCACHED_SERVER_ERROR
;
307 if (total_read
> memcached_literal_param_size("SERVER_ERROR object too large for cache") and
308 (memcmp(buffer
, memcached_literal_param("SERVER_ERROR object too large for cache")) == 0))
310 return MEMCACHED_E2BIG
;
313 // Move past the basic error message and whitespace
314 char *startptr
= buffer
+ memcached_literal_param_size("SERVER_ERROR");
315 if (startptr
[0] == ' ')
320 char *endptr
= startptr
;
321 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
323 return memcached_set_error(*ptr
, MEMCACHED_SERVER_ERROR
, MEMCACHED_AT
, startptr
, size_t(endptr
- startptr
));
325 else if (buffer
[1] == 'T' and buffer
[2] == 'O' and buffer
[3] == 'R' and buffer
[4] == 'E' and buffer
[5] == 'D')
327 return MEMCACHED_STORED
;
332 case 'D': /* DELETED */
333 if (buffer
[1] == 'E' and buffer
[2] == 'L' and buffer
[3] == 'E' and buffer
[4] == 'T' and buffer
[5] == 'E' and buffer
[6] == 'D')
335 return MEMCACHED_DELETED
;
339 case 'N': /* NOT_FOUND */
341 if (buffer
[1] == 'O' and buffer
[2] == 'T'
343 and buffer
[4] == 'F' and buffer
[5] == 'O' and buffer
[6] == 'U' and buffer
[7] == 'N' and buffer
[8] == 'D')
345 return MEMCACHED_NOTFOUND
;
347 else if (buffer
[1] == 'O' and buffer
[2] == 'T'
349 and buffer
[4] == 'S' and buffer
[5] == 'T' and buffer
[6] == 'O' and buffer
[7] == 'R' and buffer
[8] == 'E' and buffer
[9] == 'D')
351 return MEMCACHED_NOTSTORED
;
356 case 'E': /* PROTOCOL ERROR or END */
358 if (buffer
[1] == 'N' and buffer
[2] == 'D')
360 return MEMCACHED_END
;
362 else if (buffer
[1] == 'R' and buffer
[2] == 'R' and buffer
[3] == 'O' and buffer
[4] == 'R')
364 return MEMCACHED_PROTOCOL_ERROR
;
366 else if (buffer
[1] == 'X' and buffer
[2] == 'I' and buffer
[3] == 'S' and buffer
[4] == 'T' and buffer
[5] == 'S')
368 return MEMCACHED_DATA_EXISTS
;
373 case 'T': /* TOUCHED */
375 if (buffer
[1] == 'O' and buffer
[2] == 'U' and buffer
[3] == 'C' and buffer
[4] == 'H' and buffer
[5] == 'E' and buffer
[6] == 'D')
377 return MEMCACHED_SUCCESS
;
383 if (buffer
[1] == 'T' and buffer
[2] == 'E' and buffer
[3] == 'M')
385 /* We add back in one because we will need to search for END */
386 memcached_server_response_increment(ptr
);
387 return MEMCACHED_ITEM
;
391 case 'C': /* CLIENT ERROR */
392 if (buffer
[1] == 'L' and buffer
[2] == 'I' and buffer
[3] == 'E' and buffer
[4] == 'N' and buffer
[5] == 'T')
394 return MEMCACHED_CLIENT_ERROR
;
398 case '0': /* INCR/DECR response */
399 case '1': /* INCR/DECR response */
400 case '2': /* INCR/DECR response */
401 case '3': /* INCR/DECR response */
402 case '4': /* INCR/DECR response */
403 case '5': /* INCR/DECR response */
404 case '6': /* INCR/DECR response */
405 case '7': /* INCR/DECR response */
406 case '8': /* INCR/DECR response */
407 case '9': /* INCR/DECR response */
409 unsigned long long int auto_return_value
= strtoull(buffer
, (char **)NULL
, 10);
411 if (auto_return_value
== ULLONG_MAX
and errno
== ERANGE
)
413 return MEMCACHED_UNKNOWN_READ_FAILURE
;
415 else if (errno
== EINVAL
)
417 return MEMCACHED_UNKNOWN_READ_FAILURE
;
420 WATCHPOINT_STRING(buffer
);
421 return MEMCACHED_SUCCESS
;
428 return MEMCACHED_UNKNOWN_READ_FAILURE
;
431 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
432 char *buffer
, size_t buffer_length
,
433 memcached_result_st
*result
)
435 memcached_return_t rc
;
436 protocol_binary_response_header header
;
438 if ((rc
= memcached_safe_read(ptr
, &header
.bytes
, sizeof(header
.bytes
))) != MEMCACHED_SUCCESS
)
440 WATCHPOINT_ERROR(rc
);
444 if (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
446 return MEMCACHED_PROTOCOL_ERROR
;
450 ** Convert the header to host local endian!
452 header
.response
.keylen
= ntohs(header
.response
.keylen
);
453 header
.response
.status
= ntohs(header
.response
.status
);
454 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
455 header
.response
.cas
= memcached_ntohll(header
.response
.cas
);
456 uint32_t bodylen
= header
.response
.bodylen
;
458 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
or
459 header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
461 switch (header
.response
.opcode
)
463 case PROTOCOL_BINARY_CMD_GETKQ
:
465 * We didn't increment the response counter for the GETKQ packet
466 * (only the final NOOP), so we need to increment the counter again.
468 memcached_server_response_increment(ptr
);
470 case PROTOCOL_BINARY_CMD_GETK
:
472 uint16_t keylen
= header
.response
.keylen
;
473 memcached_result_reset(result
);
474 result
->item_cas
= header
.response
.cas
;
476 if ((rc
= memcached_safe_read(ptr
, &result
->item_flags
, sizeof (result
->item_flags
))) != MEMCACHED_SUCCESS
)
478 WATCHPOINT_ERROR(rc
);
479 return MEMCACHED_UNKNOWN_READ_FAILURE
;
482 result
->item_flags
= ntohl(result
->item_flags
);
483 bodylen
-= header
.response
.extlen
;
485 result
->key_length
= keylen
;
486 if (memcached_failed(rc
= memcached_safe_read(ptr
, result
->item_key
, keylen
)))
488 WATCHPOINT_ERROR(rc
);
489 return MEMCACHED_UNKNOWN_READ_FAILURE
;
492 // Only bother with doing this if key_length > 0
493 if (result
->key_length
)
495 if (memcached_array_size(ptr
->root
->_namespace
) and memcached_array_size(ptr
->root
->_namespace
) >= result
->key_length
)
497 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
500 if (memcached_array_size(ptr
->root
->_namespace
))
502 result
->key_length
-= memcached_array_size(ptr
->root
->_namespace
);
503 memmove(result
->item_key
, result
->item_key
+memcached_array_size(ptr
->root
->_namespace
), result
->key_length
);
508 if (memcached_failed(memcached_string_check(&result
->value
, bodylen
)))
510 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
513 char *vptr
= memcached_string_value_mutable(&result
->value
);
514 if (memcached_failed(rc
= memcached_safe_read(ptr
, vptr
, bodylen
)))
516 WATCHPOINT_ERROR(rc
);
517 return MEMCACHED_UNKNOWN_READ_FAILURE
;
520 memcached_string_set_length(&result
->value
, bodylen
);
524 case PROTOCOL_BINARY_CMD_INCREMENT
:
525 case PROTOCOL_BINARY_CMD_DECREMENT
:
527 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
529 return MEMCACHED_PROTOCOL_ERROR
;
532 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
534 if ((rc
= memcached_safe_read(ptr
, &val
, sizeof(val
))) != MEMCACHED_SUCCESS
)
536 WATCHPOINT_ERROR(rc
);
537 return MEMCACHED_UNKNOWN_READ_FAILURE
;
540 val
= memcached_ntohll(val
);
541 memcpy(buffer
, &val
, sizeof(val
));
545 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
546 case PROTOCOL_BINARY_CMD_VERSION
:
548 memset(buffer
, 0, buffer_length
);
549 if (bodylen
>= buffer_length
)
551 /* not enough space in buffer.. should not happen... */
552 return MEMCACHED_UNKNOWN_READ_FAILURE
;
554 else if ((rc
= memcached_safe_read(ptr
, buffer
, bodylen
)) != MEMCACHED_SUCCESS
)
556 WATCHPOINT_ERROR(rc
);
557 return MEMCACHED_UNKNOWN_READ_FAILURE
;
561 case PROTOCOL_BINARY_CMD_FLUSH
:
562 case PROTOCOL_BINARY_CMD_QUIT
:
563 case PROTOCOL_BINARY_CMD_SET
:
564 case PROTOCOL_BINARY_CMD_ADD
:
565 case PROTOCOL_BINARY_CMD_REPLACE
:
566 case PROTOCOL_BINARY_CMD_APPEND
:
567 case PROTOCOL_BINARY_CMD_PREPEND
:
568 case PROTOCOL_BINARY_CMD_DELETE
:
569 case PROTOCOL_BINARY_CMD_TOUCH
:
571 WATCHPOINT_ASSERT(bodylen
== 0);
572 return MEMCACHED_SUCCESS
;
575 case PROTOCOL_BINARY_CMD_NOOP
:
577 WATCHPOINT_ASSERT(bodylen
== 0);
578 return MEMCACHED_END
;
581 case PROTOCOL_BINARY_CMD_STAT
:
585 return MEMCACHED_END
;
587 else if (bodylen
+ 1 > buffer_length
)
589 /* not enough space in buffer.. should not happen... */
590 return MEMCACHED_UNKNOWN_READ_FAILURE
;
594 size_t keylen
= header
.response
.keylen
;
595 memset(buffer
, 0, buffer_length
);
596 if ((rc
= memcached_safe_read(ptr
, buffer
, keylen
)) != MEMCACHED_SUCCESS
||
597 (rc
= memcached_safe_read(ptr
, buffer
+ keylen
+ 1, bodylen
- keylen
)) != MEMCACHED_SUCCESS
)
599 WATCHPOINT_ERROR(rc
);
600 return MEMCACHED_UNKNOWN_READ_FAILURE
;
606 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
607 case PROTOCOL_BINARY_CMD_SASL_STEP
:
609 memcached_result_reset(result
);
610 result
->item_cas
= header
.response
.cas
;
612 if (memcached_string_check(&result
->value
,
613 bodylen
) != MEMCACHED_SUCCESS
)
614 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
616 char *vptr
= memcached_string_value_mutable(&result
->value
);
617 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
619 WATCHPOINT_ERROR(rc
);
620 return MEMCACHED_UNKNOWN_READ_FAILURE
;
623 memcached_string_set_length(&result
->value
, bodylen
);
628 /* Command not implemented yet! */
629 WATCHPOINT_ASSERT(0);
630 return MEMCACHED_PROTOCOL_ERROR
;
634 else if (header
.response
.bodylen
)
636 /* What should I do with the error message??? just discard it for now */
637 char hole
[SMALL_STRING_LEN
];
640 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
641 if ((rc
= memcached_safe_read(ptr
, hole
, nr
)) != MEMCACHED_SUCCESS
)
643 WATCHPOINT_ERROR(rc
);
644 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
646 bodylen
-= (uint32_t) nr
;
649 /* This might be an error from one of the quiet commands.. if
650 * so, just throw it away and get the next one. What about creating
651 * a callback to the user with the error information?
653 switch (header
.response
.opcode
)
655 case PROTOCOL_BINARY_CMD_SETQ
:
656 case PROTOCOL_BINARY_CMD_ADDQ
:
657 case PROTOCOL_BINARY_CMD_REPLACEQ
:
658 case PROTOCOL_BINARY_CMD_APPENDQ
:
659 case PROTOCOL_BINARY_CMD_PREPENDQ
:
660 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
667 rc
= MEMCACHED_SUCCESS
;
668 if (header
.response
.status
!= 0)
670 switch (header
.response
.status
)
672 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
673 rc
= MEMCACHED_NOTFOUND
;
676 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
677 rc
= MEMCACHED_DATA_EXISTS
;
680 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
681 rc
= MEMCACHED_NOTSTORED
;
684 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
688 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
689 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
692 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
693 rc
= MEMCACHED_AUTH_CONTINUE
;
696 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
697 rc
= MEMCACHED_AUTH_FAILURE
;
700 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
701 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
703 /* @todo fix the error mappings */
704 rc
= MEMCACHED_PROTOCOL_ERROR
;