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
, const 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
))
203 if (buffer
[1] == 'A' and buffer
[2] == 'L' and buffer
[3] == 'U' and buffer
[4] == 'E') /* VALUE */
205 /* We add back in one because we will need to search for END */
206 memcached_server_response_increment(ptr
);
207 return textual_value_fetch(ptr
, buffer
, result
);
210 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 */
212 return MEMCACHED_SUCCESS
;
220 if (buffer
[1] == 'K')
222 return MEMCACHED_SUCCESS
;
230 if (buffer
[1] == 'T' and buffer
[2] == 'A' and buffer
[3] == 'T') /* STORED STATS */
232 memcached_server_response_increment(ptr
);
233 return MEMCACHED_STAT
;
236 else if (buffer
[1] == 'E' and buffer
[2] == 'R' and buffer
[3] == 'V' and buffer
[4] == 'E' and buffer
[5] == 'R'
238 and buffer
[7] == 'E' and buffer
[8] == 'R' and buffer
[9] == 'R' and buffer
[10] == 'O' and buffer
[11] == 'R' )
240 if (total_read
== memcached_literal_param_size("SERVER_ERROR"))
242 return MEMCACHED_SERVER_ERROR
;
245 if (total_read
> memcached_literal_param_size("SERVER_ERROR object too large for cache") and
246 (memcmp(buffer
, memcached_literal_param("SERVER_ERROR object too large for cache")) == 0))
248 return MEMCACHED_E2BIG
;
251 // Move past the basic error message and whitespace
252 char *startptr
= buffer
+ memcached_literal_param_size("SERVER_ERROR");
253 if (startptr
[0] == ' ')
258 char *endptr
= startptr
;
259 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
261 return memcached_set_error(*ptr
, MEMCACHED_SERVER_ERROR
, MEMCACHED_AT
, startptr
, size_t(endptr
- startptr
));
264 else if (buffer
[1] == 'T' and buffer
[2] == 'O' and buffer
[3] == 'R') // and buffer[4] == 'E' and buffer[5] == 'D')
266 return MEMCACHED_STORED
;
274 if (buffer
[1] == 'E' and buffer
[2] == 'L' and buffer
[3] == 'E' and buffer
[4] == 'T' and buffer
[5] == 'E' and buffer
[6] == 'D')
276 return MEMCACHED_DELETED
;
284 if (buffer
[1] == 'O' and buffer
[2] == 'T'
286 and buffer
[4] == 'F' and buffer
[5] == 'O' and buffer
[6] == 'U' and buffer
[7] == 'N' and buffer
[8] == 'D')
288 return MEMCACHED_NOTFOUND
;
291 else if (buffer
[1] == 'O' and buffer
[2] == 'T'
293 and buffer
[4] == 'S' and buffer
[5] == 'T' and buffer
[6] == 'O' and buffer
[7] == 'R' and buffer
[8] == 'E' and buffer
[9] == 'D')
295 return MEMCACHED_NOTSTORED
;
300 case 'E': /* PROTOCOL ERROR or END */
303 if (buffer
[1] == 'N' and buffer
[2] == 'D')
305 return MEMCACHED_END
;
309 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'
311 and buffer
[9] == 'E' and buffer
[10] == 'R' and buffer
[11] == 'R' and buffer
[12] == 'O' and buffer
[13] == 'R')
313 return MEMCACHED_PROTOCOL_ERROR
;
317 else if (buffer
[1] == 'X' and buffer
[2] == 'I' and buffer
[3] == 'S' and buffer
[4] == 'T' and buffer
[5] == 'S')
319 return MEMCACHED_DATA_EXISTS
;
324 case 'T': /* TOUCHED */
327 if (buffer
[1] == 'O' and buffer
[2] == 'U' and buffer
[3] == 'C' and buffer
[4] == 'H' and buffer
[5] == 'E' and buffer
[6] == 'D')
329 return MEMCACHED_SUCCESS
;
337 if (buffer
[1] == 'T' and buffer
[2] == 'E' and buffer
[3] == 'M')
339 /* We add back in one because we will need to search for END */
340 memcached_server_response_increment(ptr
);
341 return MEMCACHED_ITEM
;
346 case 'C': /* CLIENT ERROR */
349 if (buffer
[1] == 'L' and buffer
[2] == 'I' and buffer
[3] == 'E' and buffer
[4] == 'N' and buffer
[5] == 'T'
351 and buffer
[7] == 'E' and buffer
[8] == 'R' and buffer
[9] == 'R' and buffer
[10] == 'O' and buffer
[11] == 'R')
353 return MEMCACHED_CLIENT_ERROR
;
358 case '0': /* INCR/DECR response */
359 case '1': /* INCR/DECR response */
360 case '2': /* INCR/DECR response */
361 case '3': /* INCR/DECR response */
362 case '4': /* INCR/DECR response */
363 case '5': /* INCR/DECR response */
364 case '6': /* INCR/DECR response */
365 case '7': /* INCR/DECR response */
366 case '8': /* INCR/DECR response */
367 case '9': /* INCR/DECR response */
369 unsigned long long int auto_return_value
= strtoull(buffer
, (char **)NULL
, 10);
371 if (auto_return_value
== ULLONG_MAX
and errno
== ERANGE
)
373 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
374 memcached_literal_param("Numeric response was out of range"));
376 else if (errno
== EINVAL
)
378 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
379 memcached_literal_param("Numeric response was out of range"));
382 numeric_value
= uint64_t(auto_return_value
);
384 WATCHPOINT_STRING(buffer
);
385 return MEMCACHED_SUCCESS
;
392 buffer
[total_read
]= 0;
394 if (total_read
>= sizeof("STORSTORED") -1)
396 fprintf(stderr
, "%s:%d '%s', %.*s\n", __FILE__
, __LINE__
,
397 buffer
, MEMCACHED_MAX_BUFFER
, ptr
->read_buffer
);
398 assert(memcmp(buffer
,"STORSTORED", sizeof("STORSTORED") -1));
401 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
405 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
406 char *buffer
, const size_t buffer_length
,
407 memcached_result_st
*result
)
409 memcached_return_t rc
;
410 protocol_binary_response_header header
;
412 if ((rc
= memcached_safe_read(ptr
, &header
.bytes
, sizeof(header
.bytes
))) != MEMCACHED_SUCCESS
)
414 WATCHPOINT_ERROR(rc
);
418 if (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
420 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
424 ** Convert the header to host local endian!
426 header
.response
.keylen
= ntohs(header
.response
.keylen
);
427 header
.response
.status
= ntohs(header
.response
.status
);
428 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
429 header
.response
.cas
= memcached_ntohll(header
.response
.cas
);
430 uint32_t bodylen
= header
.response
.bodylen
;
432 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
or
433 header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
435 switch (header
.response
.opcode
)
437 case PROTOCOL_BINARY_CMD_GETKQ
:
439 * We didn't increment the response counter for the GETKQ packet
440 * (only the final NOOP), so we need to increment the counter again.
442 memcached_server_response_increment(ptr
);
444 case PROTOCOL_BINARY_CMD_GETK
:
446 uint16_t keylen
= header
.response
.keylen
;
447 memcached_result_reset(result
);
448 result
->item_cas
= header
.response
.cas
;
450 if ((rc
= memcached_safe_read(ptr
, &result
->item_flags
, sizeof (result
->item_flags
))) != MEMCACHED_SUCCESS
)
452 WATCHPOINT_ERROR(rc
);
453 return MEMCACHED_UNKNOWN_READ_FAILURE
;
456 result
->item_flags
= ntohl(result
->item_flags
);
457 bodylen
-= header
.response
.extlen
;
459 result
->key_length
= keylen
;
460 if (memcached_failed(rc
= memcached_safe_read(ptr
, result
->item_key
, keylen
)))
462 WATCHPOINT_ERROR(rc
);
463 return MEMCACHED_UNKNOWN_READ_FAILURE
;
466 // Only bother with doing this if key_length > 0
467 if (result
->key_length
)
469 if (memcached_array_size(ptr
->root
->_namespace
) and memcached_array_size(ptr
->root
->_namespace
) >= result
->key_length
)
471 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
474 if (memcached_array_size(ptr
->root
->_namespace
))
476 result
->key_length
-= memcached_array_size(ptr
->root
->_namespace
);
477 memmove(result
->item_key
, result
->item_key
+memcached_array_size(ptr
->root
->_namespace
), result
->key_length
);
482 if (memcached_failed(memcached_string_check(&result
->value
, bodylen
)))
484 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
487 char *vptr
= memcached_string_value_mutable(&result
->value
);
488 if (memcached_failed(rc
= memcached_safe_read(ptr
, vptr
, bodylen
)))
490 WATCHPOINT_ERROR(rc
);
491 return MEMCACHED_UNKNOWN_READ_FAILURE
;
494 memcached_string_set_length(&result
->value
, bodylen
);
498 case PROTOCOL_BINARY_CMD_INCREMENT
:
499 case PROTOCOL_BINARY_CMD_DECREMENT
:
501 if (bodylen
!= sizeof(uint64_t) or buffer_length
!= sizeof(uint64_t))
503 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
506 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
508 if ((rc
= memcached_safe_read(ptr
, &val
, sizeof(val
))) != MEMCACHED_SUCCESS
)
510 WATCHPOINT_ERROR(rc
);
511 return MEMCACHED_UNKNOWN_READ_FAILURE
;
514 val
= memcached_ntohll(val
);
515 memcpy(buffer
, &val
, sizeof(val
));
519 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
520 case PROTOCOL_BINARY_CMD_VERSION
:
522 memset(buffer
, 0, buffer_length
);
523 if (bodylen
>= buffer_length
)
525 /* not enough space in buffer.. should not happen... */
526 return MEMCACHED_UNKNOWN_READ_FAILURE
;
528 else if ((rc
= memcached_safe_read(ptr
, buffer
, bodylen
)) != MEMCACHED_SUCCESS
)
530 WATCHPOINT_ERROR(rc
);
531 return MEMCACHED_UNKNOWN_READ_FAILURE
;
535 case PROTOCOL_BINARY_CMD_FLUSH
:
536 case PROTOCOL_BINARY_CMD_QUIT
:
537 case PROTOCOL_BINARY_CMD_SET
:
538 case PROTOCOL_BINARY_CMD_ADD
:
539 case PROTOCOL_BINARY_CMD_REPLACE
:
540 case PROTOCOL_BINARY_CMD_APPEND
:
541 case PROTOCOL_BINARY_CMD_PREPEND
:
542 case PROTOCOL_BINARY_CMD_DELETE
:
543 case PROTOCOL_BINARY_CMD_TOUCH
:
545 WATCHPOINT_ASSERT(bodylen
== 0);
546 return MEMCACHED_SUCCESS
;
549 case PROTOCOL_BINARY_CMD_NOOP
:
551 WATCHPOINT_ASSERT(bodylen
== 0);
552 return MEMCACHED_END
;
555 case PROTOCOL_BINARY_CMD_STAT
:
559 return MEMCACHED_END
;
561 else if (bodylen
+ 1 > buffer_length
)
563 /* not enough space in buffer.. should not happen... */
564 return MEMCACHED_UNKNOWN_READ_FAILURE
;
568 size_t keylen
= header
.response
.keylen
;
569 memset(buffer
, 0, buffer_length
);
570 if ((rc
= memcached_safe_read(ptr
, buffer
, keylen
)) != MEMCACHED_SUCCESS
||
571 (rc
= memcached_safe_read(ptr
, buffer
+ keylen
+ 1, bodylen
- keylen
)) != MEMCACHED_SUCCESS
)
573 WATCHPOINT_ERROR(rc
);
574 return MEMCACHED_UNKNOWN_READ_FAILURE
;
580 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
581 case PROTOCOL_BINARY_CMD_SASL_STEP
:
583 memcached_result_reset(result
);
584 result
->item_cas
= header
.response
.cas
;
586 if (memcached_string_check(&result
->value
,
587 bodylen
) != MEMCACHED_SUCCESS
)
588 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
590 char *vptr
= memcached_string_value_mutable(&result
->value
);
591 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
593 WATCHPOINT_ERROR(rc
);
594 return MEMCACHED_UNKNOWN_READ_FAILURE
;
597 memcached_string_set_length(&result
->value
, bodylen
);
602 /* Command not implemented yet! */
603 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
607 else if (header
.response
.bodylen
)
609 /* What should I do with the error message??? just discard it for now */
610 char hole
[SMALL_STRING_LEN
];
613 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
614 if ((rc
= memcached_safe_read(ptr
, hole
, nr
)) != MEMCACHED_SUCCESS
)
616 WATCHPOINT_ERROR(rc
);
617 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
619 bodylen
-= (uint32_t) nr
;
622 /* This might be an error from one of the quiet commands.. if
623 * so, just throw it away and get the next one. What about creating
624 * a callback to the user with the error information?
626 switch (header
.response
.opcode
)
628 case PROTOCOL_BINARY_CMD_SETQ
:
629 case PROTOCOL_BINARY_CMD_ADDQ
:
630 case PROTOCOL_BINARY_CMD_REPLACEQ
:
631 case PROTOCOL_BINARY_CMD_APPENDQ
:
632 case PROTOCOL_BINARY_CMD_PREPENDQ
:
633 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
640 rc
= MEMCACHED_SUCCESS
;
641 if (header
.response
.status
!= 0)
643 switch (header
.response
.status
)
645 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
646 rc
= MEMCACHED_NOTFOUND
;
649 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
650 rc
= MEMCACHED_DATA_EXISTS
;
653 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
654 rc
= MEMCACHED_NOTSTORED
;
657 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
661 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
662 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
665 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
666 rc
= MEMCACHED_AUTH_CONTINUE
;
669 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
670 rc
= MEMCACHED_AUTH_FAILURE
;
673 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
674 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
676 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
684 static memcached_return_t
_read_one_response(memcached_server_write_instance_st ptr
,
685 char *buffer
, const size_t buffer_length
,
686 memcached_result_st
*result
,
687 uint64_t& numeric_value
)
689 memcached_server_response_decrement(ptr
);
693 memcached_st
*root
= (memcached_st
*)ptr
->root
;
694 result
= &root
->result
;
697 memcached_return_t rc
;
698 if (memcached_is_binary(ptr
->root
))
700 rc
= binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
704 rc
= textual_read_one_response(ptr
, buffer
, buffer_length
, result
, numeric_value
);
705 assert(rc
!= MEMCACHED_PROTOCOL_ERROR
);
708 if (rc
== MEMCACHED_UNKNOWN_READ_FAILURE
or
709 rc
== MEMCACHED_READ_FAILURE
or
710 rc
== MEMCACHED_PROTOCOL_ERROR
or
711 rc
== MEMCACHED_CLIENT_ERROR
or
712 rc
== MEMCACHED_MEMORY_ALLOCATION_FAILURE
)
714 memcached_io_reset(ptr
);
720 memcached_return_t
memcached_read_one_response(memcached_server_write_instance_st ptr
,
721 memcached_result_st
*result
)
723 uint64_t numeric_value
;
724 char buffer
[SMALL_STRING_LEN
];
726 if (memcached_is_udp(ptr
->root
))
728 return memcached_set_error(*ptr
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
732 return _read_one_response(ptr
, buffer
, sizeof(buffer
), result
, numeric_value
);
735 memcached_return_t
memcached_response(memcached_server_write_instance_st ptr
,
736 char *buffer
, size_t buffer_length
,
737 memcached_result_st
*result
)
739 uint64_t numeric_value
;
741 return memcached_response(ptr
, buffer
, buffer_length
, result
, numeric_value
);
744 memcached_return_t
memcached_response(memcached_server_write_instance_st ptr
,
745 char *buffer
, size_t buffer_length
,
746 memcached_result_st
*result
,
747 uint64_t& numeric_value
)
749 if (memcached_is_udp(ptr
->root
))
751 return memcached_set_error(*ptr
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
754 /* We may have old commands in the buffer not set, first purge */
755 if ((ptr
->root
->flags
.no_block
) and (memcached_is_processing_input(ptr
->root
) == false))
757 (void)memcached_io_write(ptr
);
761 * The previous implementation purged all pending requests and just
762 * returned the last one. Purge all pending messages to ensure backwards
765 if (memcached_is_binary(ptr
->root
) == false and memcached_server_response_count(ptr
) > 1)
767 memcached_result_st junked_result
;
768 memcached_result_st
*junked_result_ptr
= memcached_result_create(ptr
->root
, &junked_result
);
770 assert(junked_result_ptr
);
772 while (memcached_server_response_count(ptr
) > 1)
774 memcached_return_t rc
= _read_one_response(ptr
, buffer
, buffer_length
, junked_result_ptr
, numeric_value
);
776 // @TODO should we return an error on another but a bad read case?
777 if (rc
!= MEMCACHED_END
and
778 rc
!= MEMCACHED_STORED
and
779 rc
!= MEMCACHED_SUCCESS
and
780 rc
!= MEMCACHED_STAT
and
781 rc
!= MEMCACHED_DELETED
and
782 rc
!= MEMCACHED_NOTFOUND
and
783 rc
!= MEMCACHED_NOTSTORED
and
784 rc
!= MEMCACHED_DATA_EXISTS
)
786 memcached_result_free(junked_result_ptr
);
790 memcached_result_free(junked_result_ptr
);
793 return _read_one_response(ptr
, buffer
, buffer_length
, result
, numeric_value
);