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 instance
,
43 memcached_result_st
*result
)
46 ssize_t read_length
= 0;
49 WATCHPOINT_ASSERT(instance
->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 " */
60 char *key
= result
->item_key
;
61 result
->key_length
= 0;
63 for (size_t prefix_length
= memcached_array_size(instance
->root
->_namespace
); !(iscntrl(*string_ptr
) || isspace(*string_ptr
)) ; string_ptr
++)
65 if (prefix_length
== 0)
74 result
->item_key
[result
->key_length
]= 0;
77 if (end_ptr
== string_ptr
)
82 /* Flags fetch move past space */
84 if (end_ptr
== string_ptr
)
89 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
90 result
->item_flags
= (uint32_t) strtoul(next_ptr
, &string_ptr
, 10);
92 if (end_ptr
== string_ptr
)
97 /* Length fetch move past space*/
99 if (end_ptr
== string_ptr
)
104 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
105 value_length
= (size_t)strtoull(next_ptr
, &string_ptr
, 10);
107 if (end_ptr
== string_ptr
)
113 if (*string_ptr
== '\r')
115 /* Skip past the \r\n */
121 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
122 result
->item_cas
= strtoull(next_ptr
, &string_ptr
, 10);
125 if (end_ptr
< string_ptr
)
130 /* We add two bytes so that we can walk the \r\n */
131 if (memcached_failed(memcached_string_check(&result
->value
, value_length
+2)))
133 return memcached_set_error(*instance
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
, MEMCACHED_AT
);
137 char *value_ptr
= memcached_string_value_mutable(&result
->value
);
139 We read the \r\n into the string since not doing so is more
140 cycles then the waster of memory to do so.
142 We are null terminating through, which will most likely make
143 some people lazy about using the return length.
145 size_t to_read
= (value_length
) + 2;
146 memcached_return_t rrc
= memcached_io_read(instance
, value_ptr
, to_read
, read_length
);
147 if (memcached_failed(rrc
) and rrc
== MEMCACHED_IN_PROGRESS
)
149 memcached_quit_server(instance
, true);
150 return memcached_set_error(*instance
, MEMCACHED_IN_PROGRESS
, MEMCACHED_AT
);
152 else if (memcached_failed(rrc
))
158 if (read_length
!= (ssize_t
)(value_length
+ 2))
163 /* This next bit blows the API, but this is internal....*/
166 char_ptr
= memcached_string_value_mutable(&result
->value
);;
167 char_ptr
[value_length
]= 0;
168 char_ptr
[value_length
+1]= 0;
169 memcached_string_set_length(&result
->value
, value_length
);
172 return MEMCACHED_SUCCESS
;
175 memcached_io_reset(instance
);
177 return MEMCACHED_PARTIAL_READ
;
180 static memcached_return_t
textual_read_one_response(memcached_server_write_instance_st instance
,
181 char *buffer
, const size_t buffer_length
,
182 memcached_result_st
*result
)
185 memcached_return_t rc
= memcached_io_readline(instance
, buffer
, buffer_length
, total_read
);
187 if (memcached_failed(rc
))
198 if (buffer
[1] == 'A' and buffer
[2] == 'L' and buffer
[3] == 'U' and buffer
[4] == 'E') /* VALUE */
200 /* We add back in one because we will need to search for END */
201 memcached_server_response_increment(instance
);
202 return textual_value_fetch(instance
, buffer
, result
);
205 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 */
207 /* Find the space, and then move one past it to copy version */
208 char *response_ptr
= index(buffer
, ' ');
211 long int version
= strtol(response_ptr
, (char **)NULL
, 10);
212 if (version
== LONG_MIN
or version
== LONG_MAX
or errno
== EINVAL
or version
> UINT8_MAX
or version
== 0)
214 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
215 return memcached_set_error(*instance
, MEMCACHED_PROTOCOL_ERROR
, MEMCACHED_AT
, memcached_literal_param("strtol() failed to parse major version"));
217 instance
->major_version
= uint8_t(version
);
219 response_ptr
= index(response_ptr
, '.');
222 version
= strtol(response_ptr
, (char **)NULL
, 10);
223 if (version
== LONG_MIN
or version
== LONG_MAX
or errno
== EINVAL
or version
> UINT8_MAX
)
225 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
226 return memcached_set_error(*instance
, MEMCACHED_PROTOCOL_ERROR
, MEMCACHED_AT
, memcached_literal_param("strtol() failed to parse minor version"));
228 instance
->minor_version
= uint8_t(version
);
230 response_ptr
= index(response_ptr
, '.');
233 version
= strtol(response_ptr
, (char **)NULL
, 10);
234 if (version
== LONG_MIN
or version
== LONG_MAX
or errno
== EINVAL
or version
> UINT8_MAX
)
236 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
237 return memcached_set_error(*instance
, MEMCACHED_PROTOCOL_ERROR
, MEMCACHED_AT
, memcached_literal_param("strtol() failed to parse micro version"));
239 instance
->micro_version
= uint8_t(version
);
241 return MEMCACHED_SUCCESS
;
249 if (buffer
[1] == 'K')
251 return MEMCACHED_SUCCESS
;
259 if (buffer
[1] == 'T' and buffer
[2] == 'A' and buffer
[3] == 'T') /* STORED STATS */
261 memcached_server_response_increment(instance
);
262 return MEMCACHED_STAT
;
265 else if (buffer
[1] == 'E' and buffer
[2] == 'R' and buffer
[3] == 'V' and buffer
[4] == 'E' and buffer
[5] == 'R'
267 and buffer
[7] == 'E' and buffer
[8] == 'R' and buffer
[9] == 'R' and buffer
[10] == 'O' and buffer
[11] == 'R' )
269 if (total_read
== memcached_literal_param_size("SERVER_ERROR"))
271 return MEMCACHED_SERVER_ERROR
;
274 if (total_read
>= memcached_literal_param_size("SERVER_ERROR object too large for cache") and
275 (memcmp(buffer
, memcached_literal_param("SERVER_ERROR object too large for cache")) == 0))
277 return MEMCACHED_E2BIG
;
280 if (total_read
>= memcached_literal_param_size("SERVER_ERROR out of memory storing object") and
281 (memcmp(buffer
, memcached_literal_param("SERVER_ERROR out of memory storing object")) == 0))
283 return MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE
;
286 // Move past the basic error message and whitespace
287 char *startptr
= buffer
+ memcached_literal_param_size("SERVER_ERROR");
288 if (startptr
[0] == ' ')
293 char *endptr
= startptr
;
294 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
296 return memcached_set_error(*instance
, MEMCACHED_SERVER_ERROR
, MEMCACHED_AT
, startptr
, size_t(endptr
- startptr
));
299 else if (buffer
[1] == 'T' and buffer
[2] == 'O' and buffer
[3] == 'R') // and buffer[4] == 'E' and buffer[5] == 'D')
301 return MEMCACHED_STORED
;
309 if (buffer
[1] == 'E' and buffer
[2] == 'L' and buffer
[3] == 'E' and buffer
[4] == 'T' and buffer
[5] == 'E' and buffer
[6] == 'D')
311 return MEMCACHED_DELETED
;
319 if (buffer
[1] == 'O' and buffer
[2] == 'T'
321 and buffer
[4] == 'F' and buffer
[5] == 'O' and buffer
[6] == 'U' and buffer
[7] == 'N' and buffer
[8] == 'D')
323 return MEMCACHED_NOTFOUND
;
326 else if (buffer
[1] == 'O' and buffer
[2] == 'T'
328 and buffer
[4] == 'S' and buffer
[5] == 'T' and buffer
[6] == 'O' and buffer
[7] == 'R' and buffer
[8] == 'E' and buffer
[9] == 'D')
330 return MEMCACHED_NOTSTORED
;
335 case 'E': /* PROTOCOL ERROR or END */
338 if (buffer
[1] == 'N' and buffer
[2] == 'D')
340 return MEMCACHED_END
;
344 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'
346 and buffer
[9] == 'E' and buffer
[10] == 'R' and buffer
[11] == 'R' and buffer
[12] == 'O' and buffer
[13] == 'R')
348 return MEMCACHED_PROTOCOL_ERROR
;
352 else if (buffer
[1] == 'R' and buffer
[2] == 'R' and buffer
[3] == 'O' and buffer
[4] == 'R')
354 return MEMCACHED_ERROR
;
357 else if (buffer
[1] == 'X' and buffer
[2] == 'I' and buffer
[3] == 'S' and buffer
[4] == 'T' and buffer
[5] == 'S')
359 return MEMCACHED_DATA_EXISTS
;
364 case 'T': /* TOUCHED */
367 if (buffer
[1] == 'O' and buffer
[2] == 'U' and buffer
[3] == 'C' and buffer
[4] == 'H' and buffer
[5] == 'E' and buffer
[6] == 'D')
369 return MEMCACHED_SUCCESS
;
377 if (buffer
[1] == 'T' and buffer
[2] == 'E' and buffer
[3] == 'M')
379 /* We add back in one because we will need to search for END */
380 memcached_server_response_increment(instance
);
381 return MEMCACHED_ITEM
;
386 case 'C': /* CLIENT ERROR */
389 if (buffer
[1] == 'L' and buffer
[2] == 'I' and buffer
[3] == 'E' and buffer
[4] == 'N' and buffer
[5] == 'T'
391 and buffer
[7] == 'E' and buffer
[8] == 'R' and buffer
[9] == 'R' and buffer
[10] == 'O' and buffer
[11] == 'R')
393 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 result
->numeric_value
= UINT64_MAX
;
414 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
415 memcached_literal_param("Numeric response was out of range"));
417 else if (errno
== EINVAL
)
419 result
->numeric_value
= UINT64_MAX
;
420 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
421 memcached_literal_param("Numeric response was out of range"));
424 result
->numeric_value
= uint64_t(auto_return_value
);
426 WATCHPOINT_STRING(buffer
);
427 return MEMCACHED_SUCCESS
;
434 buffer
[total_read
]= 0;
436 if (total_read
>= sizeof("STORSTORED") -1)
438 fprintf(stderr
, "%s:%d '%s', %.*s\n", __FILE__
, __LINE__
,
439 buffer
, MEMCACHED_MAX_BUFFER
, instance
->read_buffer
);
440 assert(memcmp(buffer
,"STORSTORED", sizeof("STORSTORED") -1));
443 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
447 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st instance
,
448 char *buffer
, const size_t buffer_length
,
449 memcached_result_st
*result
)
451 memcached_return_t rc
;
452 protocol_binary_response_header header
;
454 if ((rc
= memcached_safe_read(instance
, &header
.bytes
, sizeof(header
.bytes
))) != MEMCACHED_SUCCESS
)
456 WATCHPOINT_ERROR(rc
);
460 if (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
462 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
466 ** Convert the header to host local endian!
468 header
.response
.keylen
= ntohs(header
.response
.keylen
);
469 header
.response
.status
= ntohs(header
.response
.status
);
470 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
471 header
.response
.cas
= memcached_ntohll(header
.response
.cas
);
472 uint32_t bodylen
= header
.response
.bodylen
;
474 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
or
475 header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
477 switch (header
.response
.opcode
)
479 case PROTOCOL_BINARY_CMD_GETKQ
:
481 * We didn't increment the response counter for the GETKQ packet
482 * (only the final NOOP), so we need to increment the counter again.
484 memcached_server_response_increment(instance
);
486 case PROTOCOL_BINARY_CMD_GETK
:
488 uint16_t keylen
= header
.response
.keylen
;
489 memcached_result_reset(result
);
490 result
->item_cas
= header
.response
.cas
;
492 if ((rc
= memcached_safe_read(instance
, &result
->item_flags
, sizeof (result
->item_flags
))) != MEMCACHED_SUCCESS
)
494 WATCHPOINT_ERROR(rc
);
495 return MEMCACHED_UNKNOWN_READ_FAILURE
;
498 result
->item_flags
= ntohl(result
->item_flags
);
499 bodylen
-= header
.response
.extlen
;
501 result
->key_length
= keylen
;
502 if (memcached_failed(rc
= memcached_safe_read(instance
, result
->item_key
, keylen
)))
504 WATCHPOINT_ERROR(rc
);
505 return MEMCACHED_UNKNOWN_READ_FAILURE
;
508 // Only bother with doing this if key_length > 0
509 if (result
->key_length
)
511 if (memcached_array_size(instance
->root
->_namespace
) and memcached_array_size(instance
->root
->_namespace
) >= result
->key_length
)
513 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
516 if (memcached_array_size(instance
->root
->_namespace
))
518 result
->key_length
-= memcached_array_size(instance
->root
->_namespace
);
519 memmove(result
->item_key
, result
->item_key
+memcached_array_size(instance
->root
->_namespace
), result
->key_length
);
524 if (memcached_failed(memcached_string_check(&result
->value
, bodylen
)))
526 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
529 char *vptr
= memcached_string_value_mutable(&result
->value
);
530 if (memcached_failed(rc
= memcached_safe_read(instance
, vptr
, bodylen
)))
532 WATCHPOINT_ERROR(rc
);
533 return MEMCACHED_UNKNOWN_READ_FAILURE
;
536 memcached_string_set_length(&result
->value
, bodylen
);
540 case PROTOCOL_BINARY_CMD_INCREMENT
:
541 case PROTOCOL_BINARY_CMD_DECREMENT
:
543 if (bodylen
!= sizeof(uint64_t))
545 result
->numeric_value
= UINT64_MAX
;
546 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
550 if ((rc
= memcached_safe_read(instance
, &val
, sizeof(val
))) != MEMCACHED_SUCCESS
)
552 result
->numeric_value
= UINT64_MAX
;
553 return MEMCACHED_UNKNOWN_READ_FAILURE
;
556 result
->numeric_value
= memcached_ntohll(val
);
560 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
561 case PROTOCOL_BINARY_CMD_VERSION
:
563 char version_buffer
[32]; // @todo document this number
564 memset(version_buffer
, 0, sizeof(version_buffer
));
566 if (memcached_safe_read(instance
, version_buffer
, bodylen
) != MEMCACHED_SUCCESS
)
568 return MEMCACHED_UNKNOWN_READ_FAILURE
;
572 long int version
= strtol(version_buffer
, &p
, 10);
573 if (version
== LONG_MIN
or version
== LONG_MAX
or errno
== EINVAL
or version
> UINT8_MAX
or version
== 0)
575 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
576 return memcached_set_error(*instance
, MEMCACHED_PROTOCOL_ERROR
, MEMCACHED_AT
, memcached_literal_param("strtol() failed to parse major version"));
578 instance
->major_version
= uint8_t(version
);
580 version
= strtol(p
+1, &p
, 10);
581 if (version
== LONG_MIN
or version
== LONG_MAX
or errno
== EINVAL
or version
> UINT8_MAX
)
583 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
584 return memcached_set_error(*instance
, MEMCACHED_PROTOCOL_ERROR
, MEMCACHED_AT
, memcached_literal_param("strtol() failed to parse micro version"));
586 instance
->minor_version
= uint8_t(version
);
588 version
= strtol(p
+ 1, NULL
, 10);
591 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
592 return memcached_set_error(*instance
, MEMCACHED_PROTOCOL_ERROR
, MEMCACHED_AT
, memcached_literal_param("strtol() failed to parse micro version"));
594 instance
->micro_version
= uint8_t(version
);
598 case PROTOCOL_BINARY_CMD_FLUSH
:
599 case PROTOCOL_BINARY_CMD_QUIT
:
600 case PROTOCOL_BINARY_CMD_SET
:
601 case PROTOCOL_BINARY_CMD_ADD
:
602 case PROTOCOL_BINARY_CMD_REPLACE
:
603 case PROTOCOL_BINARY_CMD_APPEND
:
604 case PROTOCOL_BINARY_CMD_PREPEND
:
605 case PROTOCOL_BINARY_CMD_DELETE
:
606 case PROTOCOL_BINARY_CMD_TOUCH
:
608 WATCHPOINT_ASSERT(bodylen
== 0);
609 return MEMCACHED_SUCCESS
;
612 case PROTOCOL_BINARY_CMD_NOOP
:
614 WATCHPOINT_ASSERT(bodylen
== 0);
615 return MEMCACHED_END
;
618 case PROTOCOL_BINARY_CMD_STAT
:
622 return MEMCACHED_END
;
624 else if (bodylen
+ 1 > buffer_length
)
626 /* not enough space in buffer.. should not happen... */
627 return MEMCACHED_UNKNOWN_READ_FAILURE
;
631 size_t keylen
= header
.response
.keylen
;
632 memset(buffer
, 0, buffer_length
);
633 if ((rc
= memcached_safe_read(instance
, buffer
, keylen
)) != MEMCACHED_SUCCESS
||
634 (rc
= memcached_safe_read(instance
, buffer
+ keylen
+ 1, bodylen
- keylen
)) != MEMCACHED_SUCCESS
)
636 WATCHPOINT_ERROR(rc
);
637 return MEMCACHED_UNKNOWN_READ_FAILURE
;
643 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
644 case PROTOCOL_BINARY_CMD_SASL_STEP
:
646 memcached_result_reset(result
);
647 result
->item_cas
= header
.response
.cas
;
649 if (memcached_string_check(&result
->value
,
650 bodylen
) != MEMCACHED_SUCCESS
)
651 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
653 char *vptr
= memcached_string_value_mutable(&result
->value
);
654 if ((rc
= memcached_safe_read(instance
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
656 WATCHPOINT_ERROR(rc
);
657 return MEMCACHED_UNKNOWN_READ_FAILURE
;
660 memcached_string_set_length(&result
->value
, bodylen
);
665 /* Command not implemented yet! */
666 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
670 else if (header
.response
.bodylen
)
672 /* What should I do with the error message??? just discard it for now */
673 char hole
[SMALL_STRING_LEN
];
676 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
677 if ((rc
= memcached_safe_read(instance
, hole
, nr
)) != MEMCACHED_SUCCESS
)
679 WATCHPOINT_ERROR(rc
);
680 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
682 bodylen
-= (uint32_t) nr
;
685 /* This might be an error from one of the quiet commands.. if
686 * so, just throw it away and get the next one. What about creating
687 * a callback to the user with the error information?
689 switch (header
.response
.opcode
)
691 case PROTOCOL_BINARY_CMD_SETQ
:
692 case PROTOCOL_BINARY_CMD_ADDQ
:
693 case PROTOCOL_BINARY_CMD_REPLACEQ
:
694 case PROTOCOL_BINARY_CMD_APPENDQ
:
695 case PROTOCOL_BINARY_CMD_PREPENDQ
:
696 return binary_read_one_response(instance
, buffer
, buffer_length
, result
);
703 rc
= MEMCACHED_SUCCESS
;
704 if (header
.response
.status
!= 0)
706 switch (header
.response
.status
)
708 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
709 rc
= MEMCACHED_NOTFOUND
;
712 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
713 rc
= MEMCACHED_DATA_EXISTS
;
716 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
717 rc
= MEMCACHED_NOTSTORED
;
720 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
724 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
725 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
728 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
729 rc
= MEMCACHED_AUTH_CONTINUE
;
732 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
733 rc
= MEMCACHED_AUTH_FAILURE
;
736 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
737 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
739 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
747 static memcached_return_t
_read_one_response(memcached_server_write_instance_st instance
,
748 char *buffer
, const size_t buffer_length
,
749 memcached_result_st
*result
)
751 memcached_server_response_decrement(instance
);
755 memcached_st
*root
= (memcached_st
*)instance
->root
;
756 result
= &root
->result
;
759 memcached_return_t rc
;
760 if (memcached_is_binary(instance
->root
))
762 rc
= binary_read_one_response(instance
, buffer
, buffer_length
, result
);
766 rc
= textual_read_one_response(instance
, buffer
, buffer_length
, result
);
767 assert(rc
!= MEMCACHED_PROTOCOL_ERROR
);
770 if (memcached_fatal(rc
))
772 memcached_io_reset(instance
);
778 memcached_return_t
memcached_read_one_response(memcached_server_write_instance_st instance
,
779 memcached_result_st
*result
)
781 char buffer
[SMALL_STRING_LEN
];
783 if (memcached_is_udp(instance
->root
))
785 return memcached_set_error(*instance
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
789 return _read_one_response(instance
, buffer
, sizeof(buffer
), result
);
792 memcached_return_t
memcached_response(memcached_server_write_instance_st instance
,
793 memcached_result_st
*result
)
797 return memcached_response(instance
, buffer
, sizeof(buffer
), result
);
800 memcached_return_t
memcached_response(memcached_server_write_instance_st instance
,
801 char *buffer
, size_t buffer_length
,
802 memcached_result_st
*result
)
804 if (memcached_is_udp(instance
->root
))
806 return memcached_set_error(*instance
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
809 /* We may have old commands in the buffer not set, first purge */
810 if ((instance
->root
->flags
.no_block
) and (memcached_is_processing_input(instance
->root
) == false))
812 (void)memcached_io_write(instance
);
816 * The previous implementation purged all pending requests and just
817 * returned the last one. Purge all pending messages to ensure backwards
820 if (memcached_is_binary(instance
->root
) == false and memcached_server_response_count(instance
) > 1)
822 memcached_result_st junked_result
;
823 memcached_result_st
*junked_result_ptr
= memcached_result_create(instance
->root
, &junked_result
);
825 assert(junked_result_ptr
);
827 while (memcached_server_response_count(instance
) > 1)
829 memcached_return_t rc
= _read_one_response(instance
, buffer
, buffer_length
, junked_result_ptr
);
831 // @TODO should we return an error on another but a bad read case?
832 if (memcached_fatal(rc
))
834 memcached_result_free(junked_result_ptr
);
838 memcached_result_free(junked_result_ptr
);
841 return _read_one_response(instance
, buffer
, buffer_length
, result
);