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 if (rc
== MEMCACHED_UNKNOWN_READ_FAILURE
or
71 rc
== MEMCACHED_READ_FAILURE
or
72 rc
== MEMCACHED_PROTOCOL_ERROR
or
73 rc
== MEMCACHED_CLIENT_ERROR
or
74 rc
== MEMCACHED_MEMORY_ALLOCATION_FAILURE
)
76 memcached_io_reset(ptr
);
82 memcached_return_t
memcached_response(memcached_server_write_instance_st ptr
,
83 char *buffer
, size_t buffer_length
,
84 memcached_result_st
*result
)
86 /* We may have old commands in the buffer not set, first purge */
87 if ((ptr
->root
->flags
.no_block
) && (memcached_is_processing_input(ptr
->root
) == false))
89 (void)memcached_io_write(ptr
, NULL
, 0, true);
93 * The previous implementation purged all pending requests and just
94 * returned the last one. Purge all pending messages to ensure backwards
97 if (ptr
->root
->flags
.binary_protocol
== false)
99 while (memcached_server_response_count(ptr
) > 1)
101 memcached_return_t rc
= memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
103 unlikely (rc
!= MEMCACHED_END
&&
104 rc
!= MEMCACHED_STORED
&&
105 rc
!= MEMCACHED_SUCCESS
&&
106 rc
!= MEMCACHED_STAT
&&
107 rc
!= MEMCACHED_DELETED
&&
108 rc
!= MEMCACHED_NOTFOUND
&&
109 rc
!= MEMCACHED_NOTSTORED
&&
110 rc
!= MEMCACHED_DATA_EXISTS
)
115 return memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
118 static memcached_return_t
textual_value_fetch(memcached_server_write_instance_st ptr
,
120 memcached_result_st
*result
)
127 ssize_t read_length
= 0;
129 if (ptr
->root
->flags
.use_udp
)
131 return memcached_set_error(*ptr
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
134 WATCHPOINT_ASSERT(ptr
->root
);
135 end_ptr
= buffer
+ MEMCACHED_DEFAULT_COMMAND_SIZE
;
137 memcached_result_reset(result
);
140 string_ptr
+= 6; /* "VALUE " */
143 /* We load the key */
146 size_t prefix_length
;
148 key
= result
->item_key
;
149 result
->key_length
= 0;
151 for (prefix_length
= memcached_array_size(ptr
->root
->_namespace
); !(iscntrl(*string_ptr
) || isspace(*string_ptr
)) ; string_ptr
++)
153 if (prefix_length
== 0)
157 result
->key_length
++;
162 result
->item_key
[result
->key_length
]= 0;
165 if (end_ptr
== string_ptr
)
168 /* Flags fetch move past space */
170 if (end_ptr
== string_ptr
)
173 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
174 result
->item_flags
= (uint32_t) strtoul(next_ptr
, &string_ptr
, 10);
176 if (end_ptr
== string_ptr
)
179 /* Length fetch move past space*/
181 if (end_ptr
== string_ptr
)
184 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
185 value_length
= (size_t)strtoull(next_ptr
, &string_ptr
, 10);
187 if (end_ptr
== string_ptr
)
193 if (*string_ptr
== '\r')
195 /* Skip past the \r\n */
201 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
202 result
->item_cas
= strtoull(next_ptr
, &string_ptr
, 10);
205 if (end_ptr
< string_ptr
)
208 /* We add two bytes so that we can walk the \r\n */
209 if (memcached_failed(memcached_string_check(&result
->value
, value_length
+2)))
211 return memcached_set_error(*ptr
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
, MEMCACHED_AT
);
215 char *value_ptr
= memcached_string_value_mutable(&result
->value
);
217 We read the \r\n into the string since not doing so is more
218 cycles then the waster of memory to do so.
220 We are null terminating through, which will most likely make
221 some people lazy about using the return length.
223 to_read
= (value_length
) + 2;
224 memcached_return_t rrc
= memcached_io_read(ptr
, value_ptr
, to_read
, &read_length
);
225 if (memcached_failed(rrc
) and rrc
== MEMCACHED_IN_PROGRESS
)
227 memcached_quit_server(ptr
, true);
228 return memcached_set_error(*ptr
, MEMCACHED_IN_PROGRESS
, MEMCACHED_AT
);
230 else if (memcached_failed(rrc
))
236 if (read_length
!= (ssize_t
)(value_length
+ 2))
241 /* This next bit blows the API, but this is internal....*/
244 char_ptr
= memcached_string_value_mutable(&result
->value
);;
245 char_ptr
[value_length
]= 0;
246 char_ptr
[value_length
+1]= 0;
247 memcached_string_set_length(&result
->value
, value_length
);
250 return MEMCACHED_SUCCESS
;
253 memcached_io_reset(ptr
);
255 return MEMCACHED_PARTIAL_READ
;
258 static memcached_return_t
textual_read_one_response(memcached_server_write_instance_st ptr
,
259 char *buffer
, size_t buffer_length
,
260 memcached_result_st
*result
)
263 memcached_return_t rc
= memcached_io_readline(ptr
, buffer
, buffer_length
, total_read
);
265 if (memcached_failed(rc
))
272 case 'V': /* VALUE || VERSION */
273 if (buffer
[1] == 'A' and buffer
[2] == 'L' and buffer
[3] == 'U' and buffer
[4] == 'E') /* VALUE */
275 /* We add back in one because we will need to search for END */
276 memcached_server_response_increment(ptr
);
277 return textual_value_fetch(ptr
, buffer
, result
);
279 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 */
281 return MEMCACHED_SUCCESS
;
286 if (buffer
[1] == 'K')
288 return MEMCACHED_SUCCESS
;
292 case 'S': /* STORED STATS SERVER_ERROR */
294 if (buffer
[1] == 'T' and buffer
[2] == 'A' and buffer
[3] == 'T') /* STORED STATS */
296 memcached_server_response_increment(ptr
);
297 return MEMCACHED_STAT
;
299 else if (buffer
[1] == 'E' and buffer
[2] == 'R' and buffer
[3] == 'V' and buffer
[4] == 'E' and buffer
[5] == 'R'
301 and buffer
[7] == 'E' and buffer
[8] == 'R' and buffer
[9] == 'R' and buffer
[10] == 'O' and buffer
[11] == 'R' ) /* SERVER_ERROR */
303 if (total_read
== memcached_literal_param_size("SERVER_ERROR"))
305 return MEMCACHED_SERVER_ERROR
;
308 if (total_read
> memcached_literal_param_size("SERVER_ERROR object too large for cache") and
309 (memcmp(buffer
, memcached_literal_param("SERVER_ERROR object too large for cache")) == 0))
311 return MEMCACHED_E2BIG
;
314 // Move past the basic error message and whitespace
315 char *startptr
= buffer
+ memcached_literal_param_size("SERVER_ERROR");
316 if (startptr
[0] == ' ')
321 char *endptr
= startptr
;
322 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
324 return memcached_set_error(*ptr
, MEMCACHED_SERVER_ERROR
, MEMCACHED_AT
, startptr
, size_t(endptr
- startptr
));
326 else if (buffer
[1] == 'T' and buffer
[2] == 'O' and buffer
[3] == 'R' and buffer
[4] == 'E' and buffer
[5] == 'D')
328 return MEMCACHED_STORED
;
333 case 'D': /* DELETED */
334 if (buffer
[1] == 'E' and buffer
[2] == 'L' and buffer
[3] == 'E' and buffer
[4] == 'T' and buffer
[5] == 'E' and buffer
[6] == 'D')
336 return MEMCACHED_DELETED
;
340 case 'N': /* NOT_FOUND */
342 if (buffer
[1] == 'O' and buffer
[2] == 'T'
344 and buffer
[4] == 'F' and buffer
[5] == 'O' and buffer
[6] == 'U' and buffer
[7] == 'N' and buffer
[8] == 'D')
346 return MEMCACHED_NOTFOUND
;
348 else if (buffer
[1] == 'O' and buffer
[2] == 'T'
350 and buffer
[4] == 'S' and buffer
[5] == 'T' and buffer
[6] == 'O' and buffer
[7] == 'R' and buffer
[8] == 'E' and buffer
[9] == 'D')
352 return MEMCACHED_NOTSTORED
;
357 case 'E': /* PROTOCOL ERROR or END */
359 if (buffer
[1] == 'N' and buffer
[2] == 'D')
361 return MEMCACHED_END
;
363 else if (buffer
[1] == 'R' and buffer
[2] == 'O' and buffer
[3] == 'T' and buffer
[4] == 'O' and buffer
[5] == 'C' and buffer
[6] == 'O' and buffer
[7] == 'L'
365 and buffer
[9] == 'E' and buffer
[10] == 'R' and buffer
[11] == 'R' and buffer
[12] == 'O' and buffer
[13] == 'R')
367 return MEMCACHED_PROTOCOL_ERROR
;
369 else if (buffer
[1] == 'X' and buffer
[2] == 'I' and buffer
[3] == 'S' and buffer
[4] == 'T' and buffer
[5] == 'S')
371 return MEMCACHED_DATA_EXISTS
;
376 case 'T': /* TOUCHED */
378 if (buffer
[1] == 'O' and buffer
[2] == 'U' and buffer
[3] == 'C' and buffer
[4] == 'H' and buffer
[5] == 'E' and buffer
[6] == 'D')
380 return MEMCACHED_SUCCESS
;
386 if (buffer
[1] == 'T' and buffer
[2] == 'E' and buffer
[3] == 'M')
388 /* We add back in one because we will need to search for END */
389 memcached_server_response_increment(ptr
);
390 return MEMCACHED_ITEM
;
394 case 'C': /* CLIENT ERROR */
395 if (buffer
[1] == 'L' and buffer
[2] == 'I' and buffer
[3] == 'E' and buffer
[4] == 'N' and buffer
[5] == 'T')
397 return MEMCACHED_CLIENT_ERROR
;
401 case '0': /* INCR/DECR response */
402 case '1': /* INCR/DECR response */
403 case '2': /* INCR/DECR response */
404 case '3': /* INCR/DECR response */
405 case '4': /* INCR/DECR response */
406 case '5': /* INCR/DECR response */
407 case '6': /* INCR/DECR response */
408 case '7': /* INCR/DECR response */
409 case '8': /* INCR/DECR response */
410 case '9': /* INCR/DECR response */
412 unsigned long long int auto_return_value
= strtoull(buffer
, (char **)NULL
, 10);
414 if (auto_return_value
== ULLONG_MAX
and errno
== ERANGE
)
416 return MEMCACHED_UNKNOWN_READ_FAILURE
;
418 else if (errno
== EINVAL
)
420 return MEMCACHED_UNKNOWN_READ_FAILURE
;
423 WATCHPOINT_STRING(buffer
);
424 return MEMCACHED_SUCCESS
;
431 return MEMCACHED_UNKNOWN_READ_FAILURE
;
434 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
435 char *buffer
, size_t buffer_length
,
436 memcached_result_st
*result
)
438 memcached_return_t rc
;
439 protocol_binary_response_header header
;
441 if ((rc
= memcached_safe_read(ptr
, &header
.bytes
, sizeof(header
.bytes
))) != MEMCACHED_SUCCESS
)
443 WATCHPOINT_ERROR(rc
);
447 if (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
449 return MEMCACHED_PROTOCOL_ERROR
;
453 ** Convert the header to host local endian!
455 header
.response
.keylen
= ntohs(header
.response
.keylen
);
456 header
.response
.status
= ntohs(header
.response
.status
);
457 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
458 header
.response
.cas
= memcached_ntohll(header
.response
.cas
);
459 uint32_t bodylen
= header
.response
.bodylen
;
461 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
or
462 header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
464 switch (header
.response
.opcode
)
466 case PROTOCOL_BINARY_CMD_GETKQ
:
468 * We didn't increment the response counter for the GETKQ packet
469 * (only the final NOOP), so we need to increment the counter again.
471 memcached_server_response_increment(ptr
);
473 case PROTOCOL_BINARY_CMD_GETK
:
475 uint16_t keylen
= header
.response
.keylen
;
476 memcached_result_reset(result
);
477 result
->item_cas
= header
.response
.cas
;
479 if ((rc
= memcached_safe_read(ptr
, &result
->item_flags
, sizeof (result
->item_flags
))) != MEMCACHED_SUCCESS
)
481 WATCHPOINT_ERROR(rc
);
482 return MEMCACHED_UNKNOWN_READ_FAILURE
;
485 result
->item_flags
= ntohl(result
->item_flags
);
486 bodylen
-= header
.response
.extlen
;
488 result
->key_length
= keylen
;
489 if (memcached_failed(rc
= memcached_safe_read(ptr
, result
->item_key
, keylen
)))
491 WATCHPOINT_ERROR(rc
);
492 return MEMCACHED_UNKNOWN_READ_FAILURE
;
495 // Only bother with doing this if key_length > 0
496 if (result
->key_length
)
498 if (memcached_array_size(ptr
->root
->_namespace
) and memcached_array_size(ptr
->root
->_namespace
) >= result
->key_length
)
500 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
503 if (memcached_array_size(ptr
->root
->_namespace
))
505 result
->key_length
-= memcached_array_size(ptr
->root
->_namespace
);
506 memmove(result
->item_key
, result
->item_key
+memcached_array_size(ptr
->root
->_namespace
), result
->key_length
);
511 if (memcached_failed(memcached_string_check(&result
->value
, bodylen
)))
513 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
516 char *vptr
= memcached_string_value_mutable(&result
->value
);
517 if (memcached_failed(rc
= memcached_safe_read(ptr
, vptr
, bodylen
)))
519 WATCHPOINT_ERROR(rc
);
520 return MEMCACHED_UNKNOWN_READ_FAILURE
;
523 memcached_string_set_length(&result
->value
, bodylen
);
527 case PROTOCOL_BINARY_CMD_INCREMENT
:
528 case PROTOCOL_BINARY_CMD_DECREMENT
:
530 if (bodylen
!= sizeof(uint64_t) or buffer_length
!= sizeof(uint64_t))
532 return MEMCACHED_PROTOCOL_ERROR
;
535 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
537 if ((rc
= memcached_safe_read(ptr
, &val
, sizeof(val
))) != MEMCACHED_SUCCESS
)
539 WATCHPOINT_ERROR(rc
);
540 return MEMCACHED_UNKNOWN_READ_FAILURE
;
543 val
= memcached_ntohll(val
);
544 memcpy(buffer
, &val
, sizeof(val
));
548 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
549 case PROTOCOL_BINARY_CMD_VERSION
:
551 memset(buffer
, 0, buffer_length
);
552 if (bodylen
>= buffer_length
)
554 /* not enough space in buffer.. should not happen... */
555 return MEMCACHED_UNKNOWN_READ_FAILURE
;
557 else if ((rc
= memcached_safe_read(ptr
, buffer
, bodylen
)) != MEMCACHED_SUCCESS
)
559 WATCHPOINT_ERROR(rc
);
560 return MEMCACHED_UNKNOWN_READ_FAILURE
;
564 case PROTOCOL_BINARY_CMD_FLUSH
:
565 case PROTOCOL_BINARY_CMD_QUIT
:
566 case PROTOCOL_BINARY_CMD_SET
:
567 case PROTOCOL_BINARY_CMD_ADD
:
568 case PROTOCOL_BINARY_CMD_REPLACE
:
569 case PROTOCOL_BINARY_CMD_APPEND
:
570 case PROTOCOL_BINARY_CMD_PREPEND
:
571 case PROTOCOL_BINARY_CMD_DELETE
:
572 case PROTOCOL_BINARY_CMD_TOUCH
:
574 WATCHPOINT_ASSERT(bodylen
== 0);
575 return MEMCACHED_SUCCESS
;
578 case PROTOCOL_BINARY_CMD_NOOP
:
580 WATCHPOINT_ASSERT(bodylen
== 0);
581 return MEMCACHED_END
;
584 case PROTOCOL_BINARY_CMD_STAT
:
588 return MEMCACHED_END
;
590 else if (bodylen
+ 1 > buffer_length
)
592 /* not enough space in buffer.. should not happen... */
593 return MEMCACHED_UNKNOWN_READ_FAILURE
;
597 size_t keylen
= header
.response
.keylen
;
598 memset(buffer
, 0, buffer_length
);
599 if ((rc
= memcached_safe_read(ptr
, buffer
, keylen
)) != MEMCACHED_SUCCESS
||
600 (rc
= memcached_safe_read(ptr
, buffer
+ keylen
+ 1, bodylen
- keylen
)) != MEMCACHED_SUCCESS
)
602 WATCHPOINT_ERROR(rc
);
603 return MEMCACHED_UNKNOWN_READ_FAILURE
;
609 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
610 case PROTOCOL_BINARY_CMD_SASL_STEP
:
612 memcached_result_reset(result
);
613 result
->item_cas
= header
.response
.cas
;
615 if (memcached_string_check(&result
->value
,
616 bodylen
) != MEMCACHED_SUCCESS
)
617 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
619 char *vptr
= memcached_string_value_mutable(&result
->value
);
620 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
622 WATCHPOINT_ERROR(rc
);
623 return MEMCACHED_UNKNOWN_READ_FAILURE
;
626 memcached_string_set_length(&result
->value
, bodylen
);
631 /* Command not implemented yet! */
632 WATCHPOINT_ASSERT(0);
633 return MEMCACHED_PROTOCOL_ERROR
;
637 else if (header
.response
.bodylen
)
639 /* What should I do with the error message??? just discard it for now */
640 char hole
[SMALL_STRING_LEN
];
643 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
644 if ((rc
= memcached_safe_read(ptr
, hole
, nr
)) != MEMCACHED_SUCCESS
)
646 WATCHPOINT_ERROR(rc
);
647 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
649 bodylen
-= (uint32_t) nr
;
652 /* This might be an error from one of the quiet commands.. if
653 * so, just throw it away and get the next one. What about creating
654 * a callback to the user with the error information?
656 switch (header
.response
.opcode
)
658 case PROTOCOL_BINARY_CMD_SETQ
:
659 case PROTOCOL_BINARY_CMD_ADDQ
:
660 case PROTOCOL_BINARY_CMD_REPLACEQ
:
661 case PROTOCOL_BINARY_CMD_APPENDQ
:
662 case PROTOCOL_BINARY_CMD_PREPENDQ
:
663 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
670 rc
= MEMCACHED_SUCCESS
;
671 if (header
.response
.status
!= 0)
673 switch (header
.response
.status
)
675 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
676 rc
= MEMCACHED_NOTFOUND
;
679 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
680 rc
= MEMCACHED_DATA_EXISTS
;
683 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
684 rc
= MEMCACHED_NOTSTORED
;
687 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
691 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
692 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
695 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
696 rc
= MEMCACHED_AUTH_CONTINUE
;
699 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
700 rc
= MEMCACHED_AUTH_FAILURE
;
703 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
704 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
706 /* @todo fix the error mappings */
707 rc
= MEMCACHED_PROTOCOL_ERROR
;