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_value_fetch(memcached_server_write_instance_st ptr
,
43 memcached_result_st
*result
)
46 ssize_t read_length
= 0;
49 WATCHPOINT_ASSERT(ptr
->root
);
50 char *end_ptr
= buffer
+ MEMCACHED_DEFAULT_COMMAND_SIZE
;
52 memcached_result_reset(result
);
54 char *string_ptr
= buffer
;
55 string_ptr
+= 6; /* "VALUE " */
63 key
= result
->item_key
;
64 result
->key_length
= 0;
66 for (prefix_length
= memcached_array_size(ptr
->root
->_namespace
); !(iscntrl(*string_ptr
) || isspace(*string_ptr
)) ; string_ptr
++)
68 if (prefix_length
== 0)
77 result
->item_key
[result
->key_length
]= 0;
80 if (end_ptr
== string_ptr
)
85 /* Flags fetch move past space */
87 if (end_ptr
== string_ptr
)
92 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
93 result
->item_flags
= (uint32_t) strtoul(next_ptr
, &string_ptr
, 10);
95 if (end_ptr
== string_ptr
)
100 /* Length fetch move past space*/
102 if (end_ptr
== string_ptr
)
107 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
108 value_length
= (size_t)strtoull(next_ptr
, &string_ptr
, 10);
110 if (end_ptr
== string_ptr
)
116 if (*string_ptr
== '\r')
118 /* Skip past the \r\n */
124 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
125 result
->item_cas
= strtoull(next_ptr
, &string_ptr
, 10);
128 if (end_ptr
< string_ptr
)
133 /* We add two bytes so that we can walk the \r\n */
134 if (memcached_failed(memcached_string_check(&result
->value
, value_length
+2)))
136 return memcached_set_error(*ptr
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
, MEMCACHED_AT
);
140 char *value_ptr
= memcached_string_value_mutable(&result
->value
);
142 We read the \r\n into the string since not doing so is more
143 cycles then the waster of memory to do so.
145 We are null terminating through, which will most likely make
146 some people lazy about using the return length.
148 size_t to_read
= (value_length
) + 2;
149 memcached_return_t rrc
= memcached_io_read(ptr
, value_ptr
, to_read
, &read_length
);
150 if (memcached_failed(rrc
) and rrc
== MEMCACHED_IN_PROGRESS
)
152 memcached_quit_server(ptr
, true);
153 return memcached_set_error(*ptr
, MEMCACHED_IN_PROGRESS
, MEMCACHED_AT
);
155 else if (memcached_failed(rrc
))
161 if (read_length
!= (ssize_t
)(value_length
+ 2))
166 /* This next bit blows the API, but this is internal....*/
169 char_ptr
= memcached_string_value_mutable(&result
->value
);;
170 char_ptr
[value_length
]= 0;
171 char_ptr
[value_length
+1]= 0;
172 memcached_string_set_length(&result
->value
, value_length
);
175 return MEMCACHED_SUCCESS
;
178 memcached_io_reset(ptr
);
180 return MEMCACHED_PARTIAL_READ
;
183 static memcached_return_t
textual_read_one_response(memcached_server_write_instance_st ptr
,
184 char *buffer
, size_t buffer_length
,
185 memcached_result_st
*result
,
186 uint64_t& numeric_value
)
188 numeric_value
= UINT64_MAX
;
190 memcached_return_t rc
= memcached_io_readline(ptr
, buffer
, buffer_length
, total_read
);
192 if (memcached_failed(rc
))
199 case 'V': /* VALUE || VERSION */
200 if (buffer
[1] == 'A' and buffer
[2] == 'L' and buffer
[3] == 'U' and buffer
[4] == 'E') /* VALUE */
202 /* We add back in one because we will need to search for END */
203 memcached_server_response_increment(ptr
);
204 return textual_value_fetch(ptr
, buffer
, result
);
206 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 */
208 return MEMCACHED_SUCCESS
;
213 if (buffer
[1] == 'K')
215 return MEMCACHED_SUCCESS
;
219 case 'S': /* STORED STATS SERVER_ERROR */
221 if (buffer
[1] == 'T' and buffer
[2] == 'A' and buffer
[3] == 'T') /* STORED STATS */
223 memcached_server_response_increment(ptr
);
224 return MEMCACHED_STAT
;
226 else if (buffer
[1] == 'E' and buffer
[2] == 'R' and buffer
[3] == 'V' and buffer
[4] == 'E' and buffer
[5] == 'R'
228 and buffer
[7] == 'E' and buffer
[8] == 'R' and buffer
[9] == 'R' and buffer
[10] == 'O' and buffer
[11] == 'R' ) /* SERVER_ERROR */
230 if (total_read
== memcached_literal_param_size("SERVER_ERROR"))
232 return MEMCACHED_SERVER_ERROR
;
235 if (total_read
> memcached_literal_param_size("SERVER_ERROR object too large for cache") and
236 (memcmp(buffer
, memcached_literal_param("SERVER_ERROR object too large for cache")) == 0))
238 return MEMCACHED_E2BIG
;
241 // Move past the basic error message and whitespace
242 char *startptr
= buffer
+ memcached_literal_param_size("SERVER_ERROR");
243 if (startptr
[0] == ' ')
248 char *endptr
= startptr
;
249 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
251 return memcached_set_error(*ptr
, MEMCACHED_SERVER_ERROR
, MEMCACHED_AT
, startptr
, size_t(endptr
- startptr
));
253 else if (buffer
[1] == 'T' and buffer
[2] == 'O' and buffer
[3] == 'R' and buffer
[4] == 'E' and buffer
[5] == 'D')
255 return MEMCACHED_STORED
;
260 case 'D': /* DELETED */
261 if (buffer
[1] == 'E' and buffer
[2] == 'L' and buffer
[3] == 'E' and buffer
[4] == 'T' and buffer
[5] == 'E' and buffer
[6] == 'D')
263 return MEMCACHED_DELETED
;
267 case 'N': /* NOT_FOUND */
269 if (buffer
[1] == 'O' and buffer
[2] == 'T'
271 and buffer
[4] == 'F' and buffer
[5] == 'O' and buffer
[6] == 'U' and buffer
[7] == 'N' and buffer
[8] == 'D')
273 return MEMCACHED_NOTFOUND
;
275 else if (buffer
[1] == 'O' and buffer
[2] == 'T'
277 and buffer
[4] == 'S' and buffer
[5] == 'T' and buffer
[6] == 'O' and buffer
[7] == 'R' and buffer
[8] == 'E' and buffer
[9] == 'D')
279 return MEMCACHED_NOTSTORED
;
284 case 'E': /* PROTOCOL ERROR or END */
286 if (buffer
[1] == 'N' and buffer
[2] == 'D')
288 return MEMCACHED_END
;
290 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'
292 and buffer
[9] == 'E' and buffer
[10] == 'R' and buffer
[11] == 'R' and buffer
[12] == 'O' and buffer
[13] == 'R')
294 return MEMCACHED_PROTOCOL_ERROR
;
296 else if (buffer
[1] == 'X' and buffer
[2] == 'I' and buffer
[3] == 'S' and buffer
[4] == 'T' and buffer
[5] == 'S')
298 return MEMCACHED_DATA_EXISTS
;
303 case 'T': /* TOUCHED */
305 if (buffer
[1] == 'O' and buffer
[2] == 'U' and buffer
[3] == 'C' and buffer
[4] == 'H' and buffer
[5] == 'E' and buffer
[6] == 'D')
307 return MEMCACHED_SUCCESS
;
313 if (buffer
[1] == 'T' and buffer
[2] == 'E' and buffer
[3] == 'M')
315 /* We add back in one because we will need to search for END */
316 memcached_server_response_increment(ptr
);
317 return MEMCACHED_ITEM
;
321 case 'C': /* CLIENT ERROR */
322 if (buffer
[1] == 'L' and buffer
[2] == 'I' and buffer
[3] == 'E' and buffer
[4] == 'N' and buffer
[5] == 'T')
324 return MEMCACHED_CLIENT_ERROR
;
328 case '0': /* INCR/DECR response */
329 case '1': /* INCR/DECR response */
330 case '2': /* INCR/DECR response */
331 case '3': /* INCR/DECR response */
332 case '4': /* INCR/DECR response */
333 case '5': /* INCR/DECR response */
334 case '6': /* INCR/DECR response */
335 case '7': /* INCR/DECR response */
336 case '8': /* INCR/DECR response */
337 case '9': /* INCR/DECR response */
339 unsigned long long int auto_return_value
= strtoull(buffer
, (char **)NULL
, 10);
341 if (auto_return_value
== ULLONG_MAX
and errno
== ERANGE
)
343 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
344 memcached_literal_param("Numeric response was out of range"));
346 else if (errno
== EINVAL
)
348 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
349 memcached_literal_param("Numeric response was out of range"));
352 numeric_value
= uint64_t(auto_return_value
);
354 WATCHPOINT_STRING(buffer
);
355 return MEMCACHED_SUCCESS
;
362 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
363 memcached_literal_param("Could not determine response"));
366 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
367 char *buffer
, size_t buffer_length
,
368 memcached_result_st
*result
)
370 memcached_return_t rc
;
371 protocol_binary_response_header header
;
373 if ((rc
= memcached_safe_read(ptr
, &header
.bytes
, sizeof(header
.bytes
))) != MEMCACHED_SUCCESS
)
375 WATCHPOINT_ERROR(rc
);
379 if (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
381 return MEMCACHED_PROTOCOL_ERROR
;
385 ** Convert the header to host local endian!
387 header
.response
.keylen
= ntohs(header
.response
.keylen
);
388 header
.response
.status
= ntohs(header
.response
.status
);
389 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
390 header
.response
.cas
= memcached_ntohll(header
.response
.cas
);
391 uint32_t bodylen
= header
.response
.bodylen
;
393 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
or
394 header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
396 switch (header
.response
.opcode
)
398 case PROTOCOL_BINARY_CMD_GETKQ
:
400 * We didn't increment the response counter for the GETKQ packet
401 * (only the final NOOP), so we need to increment the counter again.
403 memcached_server_response_increment(ptr
);
405 case PROTOCOL_BINARY_CMD_GETK
:
407 uint16_t keylen
= header
.response
.keylen
;
408 memcached_result_reset(result
);
409 result
->item_cas
= header
.response
.cas
;
411 if ((rc
= memcached_safe_read(ptr
, &result
->item_flags
, sizeof (result
->item_flags
))) != MEMCACHED_SUCCESS
)
413 WATCHPOINT_ERROR(rc
);
414 return MEMCACHED_UNKNOWN_READ_FAILURE
;
417 result
->item_flags
= ntohl(result
->item_flags
);
418 bodylen
-= header
.response
.extlen
;
420 result
->key_length
= keylen
;
421 if (memcached_failed(rc
= memcached_safe_read(ptr
, result
->item_key
, keylen
)))
423 WATCHPOINT_ERROR(rc
);
424 return MEMCACHED_UNKNOWN_READ_FAILURE
;
427 // Only bother with doing this if key_length > 0
428 if (result
->key_length
)
430 if (memcached_array_size(ptr
->root
->_namespace
) and memcached_array_size(ptr
->root
->_namespace
) >= result
->key_length
)
432 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
435 if (memcached_array_size(ptr
->root
->_namespace
))
437 result
->key_length
-= memcached_array_size(ptr
->root
->_namespace
);
438 memmove(result
->item_key
, result
->item_key
+memcached_array_size(ptr
->root
->_namespace
), result
->key_length
);
443 if (memcached_failed(memcached_string_check(&result
->value
, bodylen
)))
445 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
448 char *vptr
= memcached_string_value_mutable(&result
->value
);
449 if (memcached_failed(rc
= memcached_safe_read(ptr
, vptr
, bodylen
)))
451 WATCHPOINT_ERROR(rc
);
452 return MEMCACHED_UNKNOWN_READ_FAILURE
;
455 memcached_string_set_length(&result
->value
, bodylen
);
459 case PROTOCOL_BINARY_CMD_INCREMENT
:
460 case PROTOCOL_BINARY_CMD_DECREMENT
:
462 if (bodylen
!= sizeof(uint64_t) or buffer_length
!= sizeof(uint64_t))
464 return MEMCACHED_PROTOCOL_ERROR
;
467 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
469 if ((rc
= memcached_safe_read(ptr
, &val
, sizeof(val
))) != MEMCACHED_SUCCESS
)
471 WATCHPOINT_ERROR(rc
);
472 return MEMCACHED_UNKNOWN_READ_FAILURE
;
475 val
= memcached_ntohll(val
);
476 memcpy(buffer
, &val
, sizeof(val
));
480 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
481 case PROTOCOL_BINARY_CMD_VERSION
:
483 memset(buffer
, 0, buffer_length
);
484 if (bodylen
>= buffer_length
)
486 /* not enough space in buffer.. should not happen... */
487 return MEMCACHED_UNKNOWN_READ_FAILURE
;
489 else if ((rc
= memcached_safe_read(ptr
, buffer
, bodylen
)) != MEMCACHED_SUCCESS
)
491 WATCHPOINT_ERROR(rc
);
492 return MEMCACHED_UNKNOWN_READ_FAILURE
;
496 case PROTOCOL_BINARY_CMD_FLUSH
:
497 case PROTOCOL_BINARY_CMD_QUIT
:
498 case PROTOCOL_BINARY_CMD_SET
:
499 case PROTOCOL_BINARY_CMD_ADD
:
500 case PROTOCOL_BINARY_CMD_REPLACE
:
501 case PROTOCOL_BINARY_CMD_APPEND
:
502 case PROTOCOL_BINARY_CMD_PREPEND
:
503 case PROTOCOL_BINARY_CMD_DELETE
:
504 case PROTOCOL_BINARY_CMD_TOUCH
:
506 WATCHPOINT_ASSERT(bodylen
== 0);
507 return MEMCACHED_SUCCESS
;
510 case PROTOCOL_BINARY_CMD_NOOP
:
512 WATCHPOINT_ASSERT(bodylen
== 0);
513 return MEMCACHED_END
;
516 case PROTOCOL_BINARY_CMD_STAT
:
520 return MEMCACHED_END
;
522 else if (bodylen
+ 1 > buffer_length
)
524 /* not enough space in buffer.. should not happen... */
525 return MEMCACHED_UNKNOWN_READ_FAILURE
;
529 size_t keylen
= header
.response
.keylen
;
530 memset(buffer
, 0, buffer_length
);
531 if ((rc
= memcached_safe_read(ptr
, buffer
, keylen
)) != MEMCACHED_SUCCESS
||
532 (rc
= memcached_safe_read(ptr
, buffer
+ keylen
+ 1, bodylen
- keylen
)) != MEMCACHED_SUCCESS
)
534 WATCHPOINT_ERROR(rc
);
535 return MEMCACHED_UNKNOWN_READ_FAILURE
;
541 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
542 case PROTOCOL_BINARY_CMD_SASL_STEP
:
544 memcached_result_reset(result
);
545 result
->item_cas
= header
.response
.cas
;
547 if (memcached_string_check(&result
->value
,
548 bodylen
) != MEMCACHED_SUCCESS
)
549 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
551 char *vptr
= memcached_string_value_mutable(&result
->value
);
552 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
554 WATCHPOINT_ERROR(rc
);
555 return MEMCACHED_UNKNOWN_READ_FAILURE
;
558 memcached_string_set_length(&result
->value
, bodylen
);
563 /* Command not implemented yet! */
564 WATCHPOINT_ASSERT(0);
565 return MEMCACHED_PROTOCOL_ERROR
;
569 else if (header
.response
.bodylen
)
571 /* What should I do with the error message??? just discard it for now */
572 char hole
[SMALL_STRING_LEN
];
575 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
576 if ((rc
= memcached_safe_read(ptr
, hole
, nr
)) != MEMCACHED_SUCCESS
)
578 WATCHPOINT_ERROR(rc
);
579 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
581 bodylen
-= (uint32_t) nr
;
584 /* This might be an error from one of the quiet commands.. if
585 * so, just throw it away and get the next one. What about creating
586 * a callback to the user with the error information?
588 switch (header
.response
.opcode
)
590 case PROTOCOL_BINARY_CMD_SETQ
:
591 case PROTOCOL_BINARY_CMD_ADDQ
:
592 case PROTOCOL_BINARY_CMD_REPLACEQ
:
593 case PROTOCOL_BINARY_CMD_APPENDQ
:
594 case PROTOCOL_BINARY_CMD_PREPENDQ
:
595 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
602 rc
= MEMCACHED_SUCCESS
;
603 if (header
.response
.status
!= 0)
605 switch (header
.response
.status
)
607 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
608 rc
= MEMCACHED_NOTFOUND
;
611 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
612 rc
= MEMCACHED_DATA_EXISTS
;
615 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
616 rc
= MEMCACHED_NOTSTORED
;
619 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
623 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
624 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
627 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
628 rc
= MEMCACHED_AUTH_CONTINUE
;
631 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
632 rc
= MEMCACHED_AUTH_FAILURE
;
635 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
636 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
638 /* @todo fix the error mappings */
639 rc
= MEMCACHED_PROTOCOL_ERROR
;
647 memcached_return_t
memcached_read_one_response(memcached_server_write_instance_st ptr
,
648 char *buffer
, size_t buffer_length
,
649 memcached_result_st
*result
)
651 uint64_t numeric_value
;
653 return memcached_read_one_response(ptr
, buffer
, buffer_length
, result
, numeric_value
);
656 memcached_return_t
memcached_read_one_response(memcached_server_write_instance_st ptr
,
657 char *buffer
, size_t buffer_length
,
658 memcached_result_st
*result
,
659 uint64_t& numeric_value
)
661 if (memcached_is_udp(ptr
->root
))
663 return memcached_set_error(*ptr
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
666 memcached_server_response_decrement(ptr
);
670 memcached_st
*root
= (memcached_st
*)ptr
->root
;
671 result
= &root
->result
;
674 memcached_return_t rc
;
675 if (ptr
->root
->flags
.binary_protocol
)
677 rc
= binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
681 rc
= textual_read_one_response(ptr
, buffer
, buffer_length
, result
, numeric_value
);
684 if (rc
== MEMCACHED_UNKNOWN_READ_FAILURE
or
685 rc
== MEMCACHED_READ_FAILURE
or
686 rc
== MEMCACHED_PROTOCOL_ERROR
or
687 rc
== MEMCACHED_CLIENT_ERROR
or
688 rc
== MEMCACHED_MEMORY_ALLOCATION_FAILURE
)
690 memcached_io_reset(ptr
);
696 memcached_return_t
memcached_response(memcached_server_write_instance_st ptr
,
697 char *buffer
, size_t buffer_length
,
698 memcached_result_st
*result
)
700 uint64_t numeric_value
;
702 return memcached_response(ptr
, buffer
, buffer_length
, result
, numeric_value
);
705 memcached_return_t
memcached_response(memcached_server_write_instance_st ptr
,
706 char *buffer
, size_t buffer_length
,
707 memcached_result_st
*result
,
708 uint64_t& numeric_value
)
710 if (memcached_is_udp(ptr
->root
))
712 return memcached_set_error(*ptr
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
715 /* We may have old commands in the buffer not set, first purge */
716 if ((ptr
->root
->flags
.no_block
) and (memcached_is_processing_input(ptr
->root
) == false))
718 (void)memcached_io_write(ptr
);
722 * The previous implementation purged all pending requests and just
723 * returned the last one. Purge all pending messages to ensure backwards
726 if (memcached_is_binary(ptr
->root
) == false)
728 while (memcached_server_response_count(ptr
) > 1)
730 memcached_return_t rc
= memcached_read_one_response(ptr
, buffer
, buffer_length
, result
, numeric_value
);
732 if (rc
!= MEMCACHED_END
&&
733 rc
!= MEMCACHED_STORED
&&
734 rc
!= MEMCACHED_SUCCESS
&&
735 rc
!= MEMCACHED_STAT
&&
736 rc
!= MEMCACHED_DELETED
&&
737 rc
!= MEMCACHED_NOTFOUND
&&
738 rc
!= MEMCACHED_NOTSTORED
&&
739 rc
!= MEMCACHED_DATA_EXISTS
)
746 return memcached_read_one_response(ptr
, buffer
, buffer_length
, result
, numeric_value
);