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(org::libmemcached::Instance
* 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 " */
58 // Just used for cases of AES decrypt currently
59 memcached_return_t rc
= MEMCACHED_SUCCESS
;
63 char *key
= result
->item_key
;
64 result
->key_length
= 0;
66 for (ptrdiff_t prefix_length
= memcached_array_size(instance
->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(*instance
, 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(instance
, value_ptr
, to_read
, read_length
);
150 if (memcached_failed(rrc
) and rrc
== MEMCACHED_IN_PROGRESS
)
152 memcached_quit_server(instance
, true);
153 return memcached_set_error(*instance
, 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 if (memcached_is_encrypted(instance
->root
) and memcached_result_length(result
))
177 hashkit_string_st
*destination
;
179 if ((destination
= hashkit_decrypt(&instance
->root
->hashkit
,
180 memcached_result_value(result
), memcached_result_length(result
))) == NULL
)
182 rc
= memcached_set_error(*instance
->root
, MEMCACHED_FAILURE
,
183 MEMCACHED_AT
, memcached_literal_param("hashkit_decrypt() failed"));
187 memcached_result_reset_value(result
);
188 if (memcached_failed(memcached_result_set_value(result
, hashkit_string_c_str(destination
), hashkit_string_length(destination
))))
190 rc
= memcached_set_error(*instance
->root
, MEMCACHED_FAILURE
,
191 MEMCACHED_AT
, memcached_literal_param("hashkit_decrypt() failed"));
195 if (memcached_failed(rc
))
197 memcached_result_reset(result
);
199 hashkit_string_free(destination
);
205 memcached_io_reset(instance
);
207 return MEMCACHED_PARTIAL_READ
;
210 static memcached_return_t
textual_read_one_response(org::libmemcached::Instance
* instance
,
211 char *buffer
, const size_t buffer_length
,
212 memcached_result_st
*result
)
215 memcached_return_t rc
= memcached_io_readline(instance
, buffer
, buffer_length
, total_read
);
217 if (memcached_failed(rc
))
228 if (buffer
[1] == 'A' and buffer
[2] == 'L' and buffer
[3] == 'U' and buffer
[4] == 'E') /* VALUE */
230 /* We add back in one because we will need to search for END */
231 memcached_server_response_increment(instance
);
232 return textual_value_fetch(instance
, buffer
, result
);
235 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 */
237 /* Find the space, and then move one past it to copy version */
238 char *response_ptr
= index(buffer
, ' ');
241 long int version
= strtol(response_ptr
, &endptr
, 10);
242 if (version
== LONG_MIN
or version
== LONG_MAX
or errno
== EINVAL
or version
> UINT8_MAX
or version
== 0)
244 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
245 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
, memcached_literal_param("strtol() failed to parse major version"));
247 instance
->major_version
= uint8_t(version
);
250 version
= strtol(endptr
, &endptr
, 10);
251 if (version
== LONG_MIN
or version
== LONG_MAX
or errno
== EINVAL
or version
> UINT8_MAX
)
253 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
254 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
, memcached_literal_param("strtol() failed to parse minor version"));
256 instance
->minor_version
= uint8_t(version
);
259 version
= strtol(endptr
, &endptr
, 10);
260 if (version
== LONG_MIN
or version
== LONG_MAX
or errno
== EINVAL
or version
> UINT8_MAX
)
262 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
263 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
, memcached_literal_param("strtol() failed to parse micro version"));
265 instance
->micro_version
= uint8_t(version
);
267 return MEMCACHED_SUCCESS
;
275 if (buffer
[1] == 'K')
277 return MEMCACHED_SUCCESS
;
285 if (buffer
[1] == 'T' and buffer
[2] == 'A' and buffer
[3] == 'T') /* STORED STATS */
287 memcached_server_response_increment(instance
);
288 return MEMCACHED_STAT
;
291 else if (buffer
[1] == 'E' and buffer
[2] == 'R' and buffer
[3] == 'V' and buffer
[4] == 'E' and buffer
[5] == 'R'
293 and buffer
[7] == 'E' and buffer
[8] == 'R' and buffer
[9] == 'R' and buffer
[10] == 'O' and buffer
[11] == 'R' )
295 if (total_read
== memcached_literal_param_size("SERVER_ERROR"))
297 return MEMCACHED_SERVER_ERROR
;
300 if (total_read
>= memcached_literal_param_size("SERVER_ERROR object too large for cache") and
301 (memcmp(buffer
, memcached_literal_param("SERVER_ERROR object too large for cache")) == 0))
303 return MEMCACHED_E2BIG
;
306 if (total_read
>= memcached_literal_param_size("SERVER_ERROR out of memory storing object") and
307 (memcmp(buffer
, memcached_literal_param("SERVER_ERROR out of memory storing object")) == 0))
309 return MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE
;
312 // Move past the basic error message and whitespace
313 char *startptr
= buffer
+ memcached_literal_param_size("SERVER_ERROR");
314 if (startptr
[0] == ' ')
319 char *endptr
= startptr
;
320 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
322 return memcached_set_error(*instance
, 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
;
335 if (buffer
[1] == 'E' and buffer
[2] == 'L' and buffer
[3] == 'E' and buffer
[4] == 'T' and buffer
[5] == 'E' and buffer
[6] == 'D')
337 return MEMCACHED_DELETED
;
345 if (buffer
[1] == 'O' and buffer
[2] == 'T'
347 and buffer
[4] == 'F' and buffer
[5] == 'O' and buffer
[6] == 'U' and buffer
[7] == 'N' and buffer
[8] == 'D')
349 return MEMCACHED_NOTFOUND
;
352 else if (buffer
[1] == 'O' and buffer
[2] == 'T'
354 and buffer
[4] == 'S' and buffer
[5] == 'T' and buffer
[6] == 'O' and buffer
[7] == 'R' and buffer
[8] == 'E' and buffer
[9] == 'D')
356 return MEMCACHED_NOTSTORED
;
361 case 'E': /* PROTOCOL ERROR or END */
364 if (buffer
[1] == 'N' and buffer
[2] == 'D')
366 return MEMCACHED_END
;
370 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'
372 and buffer
[9] == 'E' and buffer
[10] == 'R' and buffer
[11] == 'R' and buffer
[12] == 'O' and buffer
[13] == 'R')
374 return MEMCACHED_PROTOCOL_ERROR
;
378 else if (buffer
[1] == 'R' and buffer
[2] == 'R' and buffer
[3] == 'O' and buffer
[4] == 'R')
380 return MEMCACHED_ERROR
;
383 else if (buffer
[1] == 'X' and buffer
[2] == 'I' and buffer
[3] == 'S' and buffer
[4] == 'T' and buffer
[5] == 'S')
385 return MEMCACHED_DATA_EXISTS
;
390 case 'T': /* TOUCHED */
393 if (buffer
[1] == 'O' and buffer
[2] == 'U' and buffer
[3] == 'C' and buffer
[4] == 'H' and buffer
[5] == 'E' and buffer
[6] == 'D')
395 return MEMCACHED_SUCCESS
;
403 if (buffer
[1] == 'T' and buffer
[2] == 'E' and buffer
[3] == 'M')
405 /* We add back in one because we will need to search for END */
406 memcached_server_response_increment(instance
);
407 return MEMCACHED_ITEM
;
412 case 'C': /* CLIENT ERROR */
415 if (buffer
[1] == 'L' and buffer
[2] == 'I' and buffer
[3] == 'E' and buffer
[4] == 'N' and buffer
[5] == 'T'
417 and buffer
[7] == 'E' and buffer
[8] == 'R' and buffer
[9] == 'R' and buffer
[10] == 'O' and buffer
[11] == 'R')
419 // Move past the basic error message and whitespace
420 char *startptr
= buffer
+ memcached_literal_param_size("CLIENT_ERROR");
421 if (startptr
[0] == ' ')
426 char *endptr
= startptr
;
427 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
429 return memcached_set_error(*instance
, MEMCACHED_CLIENT_ERROR
, MEMCACHED_AT
, startptr
, size_t(endptr
- startptr
));
434 case '0': /* INCR/DECR response */
435 case '1': /* INCR/DECR response */
436 case '2': /* INCR/DECR response */
437 case '3': /* INCR/DECR response */
438 case '4': /* INCR/DECR response */
439 case '5': /* INCR/DECR response */
440 case '6': /* INCR/DECR response */
441 case '7': /* INCR/DECR response */
442 case '8': /* INCR/DECR response */
443 case '9': /* INCR/DECR response */
445 unsigned long long int auto_return_value
= strtoull(buffer
, (char **)NULL
, 10);
447 if (auto_return_value
== ULLONG_MAX
and errno
== ERANGE
)
449 result
->numeric_value
= UINT64_MAX
;
450 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
451 memcached_literal_param("Numeric response was out of range"));
453 else if (errno
== EINVAL
)
455 result
->numeric_value
= UINT64_MAX
;
456 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
457 memcached_literal_param("Numeric response was out of range"));
460 result
->numeric_value
= uint64_t(auto_return_value
);
462 WATCHPOINT_STRING(buffer
);
463 return MEMCACHED_SUCCESS
;
470 buffer
[total_read
]= 0;
472 if (total_read
>= sizeof("STORSTORED") -1)
474 fprintf(stderr
, "%s:%d '%s', %.*s\n", __FILE__
, __LINE__
,
475 buffer
, MEMCACHED_MAX_BUFFER
, instance
->read_buffer
);
476 assert(memcmp(buffer
,"STORSTORED", sizeof("STORSTORED") -1));
479 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
483 static memcached_return_t
binary_read_one_response(org::libmemcached::Instance
* instance
,
484 char *buffer
, const size_t buffer_length
,
485 memcached_result_st
*result
)
487 memcached_return_t rc
;
488 protocol_binary_response_header header
;
490 if ((rc
= memcached_safe_read(instance
, &header
.bytes
, sizeof(header
.bytes
))) != MEMCACHED_SUCCESS
)
492 WATCHPOINT_ERROR(rc
);
496 if (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
498 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
502 ** Convert the header to host local endian!
504 header
.response
.keylen
= ntohs(header
.response
.keylen
);
505 header
.response
.status
= ntohs(header
.response
.status
);
506 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
507 header
.response
.cas
= memcached_ntohll(header
.response
.cas
);
508 uint32_t bodylen
= header
.response
.bodylen
;
510 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
or
511 header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
513 switch (header
.response
.opcode
)
515 case PROTOCOL_BINARY_CMD_GETKQ
:
517 * We didn't increment the response counter for the GETKQ packet
518 * (only the final NOOP), so we need to increment the counter again.
520 memcached_server_response_increment(instance
);
522 case PROTOCOL_BINARY_CMD_GETK
:
524 uint16_t keylen
= header
.response
.keylen
;
525 memcached_result_reset(result
);
526 result
->item_cas
= header
.response
.cas
;
528 if ((rc
= memcached_safe_read(instance
, &result
->item_flags
, sizeof (result
->item_flags
))) != MEMCACHED_SUCCESS
)
530 WATCHPOINT_ERROR(rc
);
531 return MEMCACHED_UNKNOWN_READ_FAILURE
;
534 result
->item_flags
= ntohl(result
->item_flags
);
535 bodylen
-= header
.response
.extlen
;
537 result
->key_length
= keylen
;
538 if (memcached_failed(rc
= memcached_safe_read(instance
, result
->item_key
, keylen
)))
540 WATCHPOINT_ERROR(rc
);
541 return MEMCACHED_UNKNOWN_READ_FAILURE
;
544 // Only bother with doing this if key_length > 0
545 if (result
->key_length
)
547 if (memcached_array_size(instance
->root
->_namespace
) and memcached_array_size(instance
->root
->_namespace
) >= result
->key_length
)
549 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
552 if (memcached_array_size(instance
->root
->_namespace
))
554 result
->key_length
-= memcached_array_size(instance
->root
->_namespace
);
555 memmove(result
->item_key
, result
->item_key
+memcached_array_size(instance
->root
->_namespace
), result
->key_length
);
560 if (memcached_failed(memcached_string_check(&result
->value
, bodylen
)))
562 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
565 char *vptr
= memcached_string_value_mutable(&result
->value
);
566 if (memcached_failed(rc
= memcached_safe_read(instance
, vptr
, bodylen
)))
568 WATCHPOINT_ERROR(rc
);
569 return MEMCACHED_UNKNOWN_READ_FAILURE
;
572 memcached_string_set_length(&result
->value
, bodylen
);
576 case PROTOCOL_BINARY_CMD_INCREMENT
:
577 case PROTOCOL_BINARY_CMD_DECREMENT
:
579 if (bodylen
!= sizeof(uint64_t))
581 result
->numeric_value
= UINT64_MAX
;
582 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
586 if ((rc
= memcached_safe_read(instance
, &val
, sizeof(val
))) != MEMCACHED_SUCCESS
)
588 result
->numeric_value
= UINT64_MAX
;
589 return MEMCACHED_UNKNOWN_READ_FAILURE
;
592 result
->numeric_value
= memcached_ntohll(val
);
596 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
598 if (header
.response
.keylen
!= 0 || bodylen
+ 1 > buffer_length
)
600 return MEMCACHED_UNKNOWN_READ_FAILURE
;
604 if ((rc
= memcached_safe_read(instance
, buffer
, bodylen
)) != MEMCACHED_SUCCESS
)
606 return MEMCACHED_UNKNOWN_READ_FAILURE
;
612 case PROTOCOL_BINARY_CMD_VERSION
:
614 char version_buffer
[32]; // @todo document this number
615 memset(version_buffer
, 0, sizeof(version_buffer
));
617 if (memcached_safe_read(instance
, version_buffer
, bodylen
) != MEMCACHED_SUCCESS
)
619 return MEMCACHED_UNKNOWN_READ_FAILURE
;
623 long int version
= strtol(version_buffer
, &endptr
, 10);
624 if (version
== LONG_MIN
or version
== LONG_MAX
or errno
== EINVAL
or version
> UINT8_MAX
or version
== 0)
626 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
627 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
, memcached_literal_param("strtol() failed to parse major version"));
629 instance
->major_version
= uint8_t(version
);
632 version
= strtol(endptr
, &endptr
, 10);
633 if (version
== LONG_MIN
or version
== LONG_MAX
or errno
== EINVAL
or version
> UINT8_MAX
)
635 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
636 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
, memcached_literal_param("strtol() failed to parse minor version"));
638 instance
->minor_version
= uint8_t(version
);
641 version
= strtol(endptr
, &endptr
, 10);
642 if (version
== LONG_MIN
or version
== LONG_MAX
or errno
== EINVAL
or version
> UINT8_MAX
)
644 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
645 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
, memcached_literal_param("strtol() failed to parse micro version"));
647 instance
->micro_version
= uint8_t(version
);
651 case PROTOCOL_BINARY_CMD_TOUCH
:
653 rc
= MEMCACHED_SUCCESS
;
654 if (bodylen
== 4) // The four byte read is a bug?
656 char touch_buffer
[4]; // @todo document this number
657 rc
= memcached_safe_read(instance
, touch_buffer
, sizeof(touch_buffer
));
659 fprintf(stderr
, "%s:%d %d %d %d %d %.*s(%d)\n", __FILE__
, __LINE__
,
660 int(touch_buffer
[0]),
661 int(touch_buffer
[1]),
662 int(touch_buffer
[2]),
663 int(touch_buffer
[3]),
664 int(bodylen
), touch_buffer
, int(bodylen
));
667 return memcached_set_error(*instance
, rc
, MEMCACHED_AT
);
670 case PROTOCOL_BINARY_CMD_FLUSH
:
671 case PROTOCOL_BINARY_CMD_QUIT
:
672 case PROTOCOL_BINARY_CMD_SET
:
673 case PROTOCOL_BINARY_CMD_ADD
:
674 case PROTOCOL_BINARY_CMD_REPLACE
:
675 case PROTOCOL_BINARY_CMD_APPEND
:
676 case PROTOCOL_BINARY_CMD_PREPEND
:
677 case PROTOCOL_BINARY_CMD_DELETE
:
679 WATCHPOINT_ASSERT(bodylen
== 0);
680 return MEMCACHED_SUCCESS
;
683 case PROTOCOL_BINARY_CMD_NOOP
:
685 WATCHPOINT_ASSERT(bodylen
== 0);
686 return MEMCACHED_END
;
689 case PROTOCOL_BINARY_CMD_STAT
:
693 return MEMCACHED_END
;
695 else if (bodylen
+ 1 > buffer_length
)
697 /* not enough space in buffer.. should not happen... */
698 return MEMCACHED_UNKNOWN_READ_FAILURE
;
702 size_t keylen
= header
.response
.keylen
;
703 memset(buffer
, 0, buffer_length
);
704 if ((rc
= memcached_safe_read(instance
, buffer
, keylen
)) != MEMCACHED_SUCCESS
||
705 (rc
= memcached_safe_read(instance
, buffer
+ keylen
+ 1, bodylen
- keylen
)) != MEMCACHED_SUCCESS
)
707 WATCHPOINT_ERROR(rc
);
708 return MEMCACHED_UNKNOWN_READ_FAILURE
;
714 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
715 case PROTOCOL_BINARY_CMD_SASL_STEP
:
717 memcached_result_reset(result
);
718 result
->item_cas
= header
.response
.cas
;
720 if (memcached_string_check(&result
->value
,
721 bodylen
) != MEMCACHED_SUCCESS
)
722 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
724 char *vptr
= memcached_string_value_mutable(&result
->value
);
725 if ((rc
= memcached_safe_read(instance
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
727 WATCHPOINT_ERROR(rc
);
728 return MEMCACHED_UNKNOWN_READ_FAILURE
;
731 memcached_string_set_length(&result
->value
, bodylen
);
736 /* Command not implemented yet! */
737 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
741 else if (header
.response
.bodylen
)
743 /* What should I do with the error message??? just discard it for now */
744 char hole
[SMALL_STRING_LEN
];
747 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
748 if ((rc
= memcached_safe_read(instance
, hole
, nr
)) != MEMCACHED_SUCCESS
)
750 WATCHPOINT_ERROR(rc
);
751 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
753 bodylen
-= (uint32_t) nr
;
756 /* This might be an error from one of the quiet commands.. if
757 * so, just throw it away and get the next one. What about creating
758 * a callback to the user with the error information?
760 switch (header
.response
.opcode
)
762 case PROTOCOL_BINARY_CMD_SETQ
:
763 case PROTOCOL_BINARY_CMD_ADDQ
:
764 case PROTOCOL_BINARY_CMD_REPLACEQ
:
765 case PROTOCOL_BINARY_CMD_APPENDQ
:
766 case PROTOCOL_BINARY_CMD_PREPENDQ
:
767 return binary_read_one_response(instance
, buffer
, buffer_length
, result
);
774 rc
= MEMCACHED_SUCCESS
;
775 if (header
.response
.status
!= 0)
777 switch (header
.response
.status
)
779 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
780 rc
= MEMCACHED_NOTFOUND
;
783 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
784 rc
= MEMCACHED_DATA_EXISTS
;
787 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
788 rc
= MEMCACHED_NOTSTORED
;
791 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
795 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
796 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
799 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
800 rc
= MEMCACHED_AUTH_CONTINUE
;
803 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
804 rc
= MEMCACHED_AUTH_FAILURE
;
807 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
808 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
810 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
818 static memcached_return_t
_read_one_response(org::libmemcached::Instance
* instance
,
819 char *buffer
, const size_t buffer_length
,
820 memcached_result_st
*result
)
822 memcached_server_response_decrement(instance
);
826 Memcached
*root
= (Memcached
*)instance
->root
;
827 result
= &root
->result
;
830 memcached_return_t rc
;
831 if (memcached_is_binary(instance
->root
))
833 rc
= binary_read_one_response(instance
, buffer
, buffer_length
, result
);
837 rc
= textual_read_one_response(instance
, buffer
, buffer_length
, result
);
840 if (memcached_fatal(rc
))
842 memcached_io_reset(instance
);
848 memcached_return_t
memcached_read_one_response(org::libmemcached::Instance
* instance
,
849 memcached_result_st
*result
)
851 char buffer
[SMALL_STRING_LEN
];
853 if (memcached_is_udp(instance
->root
))
855 return memcached_set_error(*instance
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
859 return _read_one_response(instance
, buffer
, sizeof(buffer
), result
);
862 memcached_return_t
memcached_response(org::libmemcached::Instance
* instance
,
863 memcached_result_st
*result
)
867 return memcached_response(instance
, buffer
, sizeof(buffer
), result
);
870 memcached_return_t
memcached_response(org::libmemcached::Instance
* instance
,
871 char *buffer
, size_t buffer_length
,
872 memcached_result_st
*result
)
874 if (memcached_is_udp(instance
->root
))
876 return memcached_set_error(*instance
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
879 /* We may have old commands in the buffer not set, first purge */
880 if ((instance
->root
->flags
.no_block
) and (memcached_is_processing_input(instance
->root
) == false))
882 (void)memcached_io_write(instance
);
886 * The previous implementation purged all pending requests and just
887 * returned the last one. Purge all pending messages to ensure backwards
890 if (memcached_is_binary(instance
->root
) == false and memcached_server_response_count(instance
) > 1)
892 memcached_result_st junked_result
;
893 memcached_result_st
*junked_result_ptr
= memcached_result_create(instance
->root
, &junked_result
);
895 assert(junked_result_ptr
);
897 while (memcached_server_response_count(instance
) > 1)
899 memcached_return_t rc
= _read_one_response(instance
, buffer
, buffer_length
, junked_result_ptr
);
901 // @TODO should we return an error on another but a bad read case?
902 if (memcached_fatal(rc
))
904 memcached_result_free(junked_result_ptr
);
908 memcached_result_free(junked_result_ptr
);
911 return _read_one_response(instance
, buffer
, buffer_length
, result
);