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_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 " */
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
++) {};
94 result
->item_flags
= (uint32_t) strtoul(next_ptr
, &string_ptr
, 10);
96 if (errno
!= 0 or end_ptr
== string_ptr
)
101 /* Length fetch move past space*/
103 if (end_ptr
== string_ptr
)
108 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
110 value_length
= (size_t)strtoull(next_ptr
, &string_ptr
, 10);
112 if (errno
!= 0 or end_ptr
== string_ptr
)
118 if (*string_ptr
== '\r')
120 /* Skip past the \r\n */
126 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
128 result
->item_cas
= strtoull(next_ptr
, &string_ptr
, 10);
131 if (errno
!= 0 or end_ptr
< string_ptr
)
136 /* We add two bytes so that we can walk the \r\n */
137 if (memcached_failed(memcached_string_check(&result
->value
, value_length
+2)))
139 return memcached_set_error(*instance
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
, MEMCACHED_AT
);
143 char *value_ptr
= memcached_string_value_mutable(&result
->value
);
145 We read the \r\n into the string since not doing so is more
146 cycles then the waster of memory to do so.
148 We are null terminating through, which will most likely make
149 some people lazy about using the return length.
151 size_t to_read
= (value_length
) + 2;
152 memcached_return_t rrc
= memcached_io_read(instance
, value_ptr
, to_read
, read_length
);
153 if (memcached_failed(rrc
) and rrc
== MEMCACHED_IN_PROGRESS
)
155 memcached_quit_server(instance
, true);
156 return memcached_set_error(*instance
, MEMCACHED_IN_PROGRESS
, MEMCACHED_AT
);
158 else if (memcached_failed(rrc
))
164 if (read_length
!= (ssize_t
)(value_length
+ 2))
169 /* This next bit blows the API, but this is internal....*/
172 char_ptr
= memcached_string_value_mutable(&result
->value
);;
173 char_ptr
[value_length
]= 0;
174 char_ptr
[value_length
+1]= 0;
175 memcached_string_set_length(&result
->value
, value_length
);
178 if (memcached_is_encrypted(instance
->root
) and memcached_result_length(result
))
180 hashkit_string_st
*destination
;
182 if ((destination
= hashkit_decrypt(&instance
->root
->hashkit
,
183 memcached_result_value(result
), memcached_result_length(result
))) == NULL
)
185 rc
= memcached_set_error(*instance
->root
, MEMCACHED_FAILURE
,
186 MEMCACHED_AT
, memcached_literal_param("hashkit_decrypt() failed"));
190 memcached_result_reset_value(result
);
191 if (memcached_failed(memcached_result_set_value(result
, hashkit_string_c_str(destination
), hashkit_string_length(destination
))))
193 rc
= memcached_set_error(*instance
->root
, MEMCACHED_FAILURE
,
194 MEMCACHED_AT
, memcached_literal_param("hashkit_decrypt() failed"));
198 if (memcached_failed(rc
))
200 memcached_result_reset(result
);
202 hashkit_string_free(destination
);
208 memcached_io_reset(instance
);
210 return MEMCACHED_PARTIAL_READ
;
213 static memcached_return_t
textual_read_one_response(memcached_instance_st
* instance
,
214 char *buffer
, const size_t buffer_length
,
215 memcached_result_st
*result
)
218 memcached_return_t rc
= memcached_io_readline(instance
, buffer
, buffer_length
, total_read
);
220 if (memcached_failed(rc
))
231 if (buffer
[1] == 'A' and buffer
[2] == 'L' and buffer
[3] == 'U' and buffer
[4] == 'E') /* VALUE */
233 /* We add back in one because we will need to search for END */
234 memcached_server_response_increment(instance
);
235 return textual_value_fetch(instance
, buffer
, result
);
238 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 */
240 /* Find the space, and then move one past it to copy version */
241 char *response_ptr
= index(buffer
, ' ');
245 long int version
= strtol(response_ptr
, &endptr
, 10);
246 if (errno
!= 0 or version
== LONG_MIN
or version
== LONG_MAX
or version
> UINT8_MAX
or version
== 0)
248 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
249 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
, memcached_literal_param("strtol() failed to parse major version"));
251 instance
->major_version
= uint8_t(version
);
255 version
= strtol(endptr
, &endptr
, 10);
256 if (errno
!= 0 or version
== LONG_MIN
or version
== LONG_MAX
or version
> UINT8_MAX
)
258 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
259 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
, memcached_literal_param("strtol() failed to parse minor version"));
261 instance
->minor_version
= uint8_t(version
);
265 version
= strtol(endptr
, &endptr
, 10);
266 if (errno
!= 0 or version
== LONG_MIN
or version
== LONG_MAX
or version
> UINT8_MAX
)
268 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
269 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
, memcached_literal_param("strtol() failed to parse micro version"));
271 instance
->micro_version
= uint8_t(version
);
273 return MEMCACHED_SUCCESS
;
281 if (buffer
[1] == 'K')
283 return MEMCACHED_SUCCESS
;
291 if (buffer
[1] == 'T' and buffer
[2] == 'A' and buffer
[3] == 'T') /* STORED STATS */
293 memcached_server_response_increment(instance
);
294 return MEMCACHED_STAT
;
297 else if (buffer
[1] == 'E' and buffer
[2] == 'R' and buffer
[3] == 'V' and buffer
[4] == 'E' and buffer
[5] == 'R'
299 and buffer
[7] == 'E' and buffer
[8] == 'R' and buffer
[9] == 'R' and buffer
[10] == 'O' and buffer
[11] == 'R' )
301 if (total_read
== memcached_literal_param_size("SERVER_ERROR"))
303 return MEMCACHED_SERVER_ERROR
;
306 if (total_read
>= memcached_literal_param_size("SERVER_ERROR object too large for cache") and
307 (memcmp(buffer
, memcached_literal_param("SERVER_ERROR object too large for cache")) == 0))
309 return MEMCACHED_E2BIG
;
312 if (total_read
>= memcached_literal_param_size("SERVER_ERROR out of memory storing object") and
313 (memcmp(buffer
, memcached_literal_param("SERVER_ERROR out of memory storing object")) == 0))
315 return MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE
;
318 // Move past the basic error message and whitespace
319 char *startptr
= buffer
+ memcached_literal_param_size("SERVER_ERROR");
320 if (startptr
[0] == ' ')
325 char *endptr
= startptr
;
326 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
328 return memcached_set_error(*instance
, MEMCACHED_SERVER_ERROR
, MEMCACHED_AT
, startptr
, size_t(endptr
- startptr
));
331 else if (buffer
[1] == 'T' and buffer
[2] == 'O' and buffer
[3] == 'R') // and buffer[4] == 'E' and buffer[5] == 'D')
333 return MEMCACHED_STORED
;
341 if (buffer
[1] == 'E' and buffer
[2] == 'L' and buffer
[3] == 'E' and buffer
[4] == 'T' and buffer
[5] == 'E' and buffer
[6] == 'D')
343 return MEMCACHED_DELETED
;
351 if (buffer
[1] == 'O' and buffer
[2] == 'T'
353 and buffer
[4] == 'F' and buffer
[5] == 'O' and buffer
[6] == 'U' and buffer
[7] == 'N' and buffer
[8] == 'D')
355 return MEMCACHED_NOTFOUND
;
358 else if (buffer
[1] == 'O' and buffer
[2] == 'T'
360 and buffer
[4] == 'S' and buffer
[5] == 'T' and buffer
[6] == 'O' and buffer
[7] == 'R' and buffer
[8] == 'E' and buffer
[9] == 'D')
362 return MEMCACHED_NOTSTORED
;
367 case 'E': /* PROTOCOL ERROR or END */
370 if (buffer
[1] == 'N' and buffer
[2] == 'D')
372 return MEMCACHED_END
;
376 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'
378 and buffer
[9] == 'E' and buffer
[10] == 'R' and buffer
[11] == 'R' and buffer
[12] == 'O' and buffer
[13] == 'R')
380 return MEMCACHED_PROTOCOL_ERROR
;
384 else if (buffer
[1] == 'R' and buffer
[2] == 'R' and buffer
[3] == 'O' and buffer
[4] == 'R')
386 return MEMCACHED_ERROR
;
389 else if (buffer
[1] == 'X' and buffer
[2] == 'I' and buffer
[3] == 'S' and buffer
[4] == 'T' and buffer
[5] == 'S')
391 return MEMCACHED_DATA_EXISTS
;
396 case 'T': /* TOUCHED */
399 if (buffer
[1] == 'O' and buffer
[2] == 'U' and buffer
[3] == 'C' and buffer
[4] == 'H' and buffer
[5] == 'E' and buffer
[6] == 'D')
401 return MEMCACHED_SUCCESS
;
409 if (buffer
[1] == 'T' and buffer
[2] == 'E' and buffer
[3] == 'M')
411 /* We add back in one because we will need to search for END */
412 memcached_server_response_increment(instance
);
413 return MEMCACHED_ITEM
;
418 case 'C': /* CLIENT ERROR */
421 if (buffer
[1] == 'L' and buffer
[2] == 'I' and buffer
[3] == 'E' and buffer
[4] == 'N' and buffer
[5] == 'T'
423 and buffer
[7] == 'E' and buffer
[8] == 'R' and buffer
[9] == 'R' and buffer
[10] == 'O' and buffer
[11] == 'R')
425 // Move past the basic error message and whitespace
426 char *startptr
= buffer
+ memcached_literal_param_size("CLIENT_ERROR");
427 if (startptr
[0] == ' ')
432 char *endptr
= startptr
;
433 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
435 return memcached_set_error(*instance
, MEMCACHED_CLIENT_ERROR
, MEMCACHED_AT
, startptr
, size_t(endptr
- startptr
));
440 case '0': /* INCR/DECR response */
441 case '1': /* INCR/DECR response */
442 case '2': /* INCR/DECR response */
443 case '3': /* INCR/DECR response */
444 case '4': /* INCR/DECR response */
445 case '5': /* INCR/DECR response */
446 case '6': /* INCR/DECR response */
447 case '7': /* INCR/DECR response */
448 case '8': /* INCR/DECR response */
449 case '9': /* INCR/DECR response */
452 unsigned long long int auto_return_value
= strtoull(buffer
, (char **)NULL
, 10);
454 if (auto_return_value
== ULLONG_MAX
and errno
== ERANGE
)
456 result
->numeric_value
= UINT64_MAX
;
457 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
458 memcached_literal_param("Numeric response was out of range"));
460 else if (errno
== EINVAL
)
462 result
->numeric_value
= UINT64_MAX
;
463 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
464 memcached_literal_param("Numeric response was out of range"));
468 result
->numeric_value
= UINT64_MAX
;
469 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
470 memcached_literal_param("Numeric response was out of range"));
473 result
->numeric_value
= uint64_t(auto_return_value
);
475 WATCHPOINT_STRING(buffer
);
476 return MEMCACHED_SUCCESS
;
483 buffer
[total_read
]= 0;
485 if (total_read
>= sizeof("STORSTORED") -1)
487 fprintf(stderr
, "%s:%d '%s', %.*s\n", __FILE__
, __LINE__
,
488 buffer
, MEMCACHED_MAX_BUFFER
, instance
->read_buffer
);
489 assert(memcmp(buffer
,"STORSTORED", sizeof("STORSTORED") -1));
492 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
496 static memcached_return_t
binary_read_one_response(memcached_instance_st
* instance
,
497 char *buffer
, const size_t buffer_length
,
498 memcached_result_st
*result
)
500 memcached_return_t rc
;
501 protocol_binary_response_header header
;
503 if ((rc
= memcached_safe_read(instance
, &header
.bytes
, sizeof(header
.bytes
))) != MEMCACHED_SUCCESS
)
505 WATCHPOINT_ERROR(rc
);
509 if (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
511 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
515 ** Convert the header to host local endian!
517 header
.response
.keylen
= ntohs(header
.response
.keylen
);
518 header
.response
.status
= ntohs(header
.response
.status
);
519 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
520 header
.response
.cas
= memcached_ntohll(header
.response
.cas
);
521 uint32_t bodylen
= header
.response
.bodylen
;
523 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
or
524 header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
526 switch (header
.response
.opcode
)
528 case PROTOCOL_BINARY_CMD_GETKQ
:
530 * We didn't increment the response counter for the GETKQ packet
531 * (only the final NOOP), so we need to increment the counter again.
533 memcached_server_response_increment(instance
);
535 case PROTOCOL_BINARY_CMD_GETK
:
537 uint16_t keylen
= header
.response
.keylen
;
538 memcached_result_reset(result
);
539 result
->item_cas
= header
.response
.cas
;
541 if ((rc
= memcached_safe_read(instance
, &result
->item_flags
, sizeof (result
->item_flags
))) != MEMCACHED_SUCCESS
)
543 WATCHPOINT_ERROR(rc
);
544 return MEMCACHED_UNKNOWN_READ_FAILURE
;
547 result
->item_flags
= ntohl(result
->item_flags
);
548 bodylen
-= header
.response
.extlen
;
550 result
->key_length
= keylen
;
551 if (memcached_failed(rc
= memcached_safe_read(instance
, result
->item_key
, keylen
)))
553 WATCHPOINT_ERROR(rc
);
554 return MEMCACHED_UNKNOWN_READ_FAILURE
;
557 // Only bother with doing this if key_length > 0
558 if (result
->key_length
)
560 if (memcached_array_size(instance
->root
->_namespace
) and memcached_array_size(instance
->root
->_namespace
) >= result
->key_length
)
562 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
565 if (memcached_array_size(instance
->root
->_namespace
))
567 result
->key_length
-= memcached_array_size(instance
->root
->_namespace
);
568 memmove(result
->item_key
, result
->item_key
+memcached_array_size(instance
->root
->_namespace
), result
->key_length
);
573 if (memcached_failed(memcached_string_check(&result
->value
, bodylen
)))
575 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
578 char *vptr
= memcached_string_value_mutable(&result
->value
);
579 if (memcached_failed(rc
= memcached_safe_read(instance
, vptr
, bodylen
)))
581 WATCHPOINT_ERROR(rc
);
582 return MEMCACHED_UNKNOWN_READ_FAILURE
;
585 memcached_string_set_length(&result
->value
, bodylen
);
589 case PROTOCOL_BINARY_CMD_INCREMENT
:
590 case PROTOCOL_BINARY_CMD_DECREMENT
:
592 if (bodylen
!= sizeof(uint64_t))
594 result
->numeric_value
= UINT64_MAX
;
595 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
599 if ((rc
= memcached_safe_read(instance
, &val
, sizeof(val
))) != MEMCACHED_SUCCESS
)
601 result
->numeric_value
= UINT64_MAX
;
602 return MEMCACHED_UNKNOWN_READ_FAILURE
;
605 result
->numeric_value
= memcached_ntohll(val
);
609 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
611 if (header
.response
.keylen
!= 0 || bodylen
+ 1 > buffer_length
)
613 return MEMCACHED_UNKNOWN_READ_FAILURE
;
617 if ((rc
= memcached_safe_read(instance
, buffer
, bodylen
)) != MEMCACHED_SUCCESS
)
619 return MEMCACHED_UNKNOWN_READ_FAILURE
;
625 case PROTOCOL_BINARY_CMD_VERSION
:
627 char version_buffer
[32]; // @todo document this number
628 memset(version_buffer
, 0, sizeof(version_buffer
));
630 if (memcached_safe_read(instance
, version_buffer
, bodylen
) != MEMCACHED_SUCCESS
)
632 return MEMCACHED_UNKNOWN_READ_FAILURE
;
637 long int version
= strtol(version_buffer
, &endptr
, 10);
638 if (errno
!= 0 or version
== LONG_MIN
or version
== LONG_MAX
or version
> UINT8_MAX
or version
== 0)
640 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
641 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
, memcached_literal_param("strtol() failed to parse major version"));
643 instance
->major_version
= uint8_t(version
);
647 version
= strtol(endptr
, &endptr
, 10);
648 if (errno
!= 0 or version
== LONG_MIN
or version
== LONG_MAX
or version
> UINT8_MAX
)
650 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
651 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
, memcached_literal_param("strtol() failed to parse minor version"));
653 instance
->minor_version
= uint8_t(version
);
657 version
= strtol(endptr
, &endptr
, 10);
658 if (errno
!= 0 or version
== LONG_MIN
or version
== LONG_MAX
or version
> UINT8_MAX
)
660 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
661 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
, memcached_literal_param("strtol() failed to parse micro version"));
663 instance
->micro_version
= uint8_t(version
);
667 case PROTOCOL_BINARY_CMD_TOUCH
:
669 rc
= MEMCACHED_SUCCESS
;
670 if (bodylen
== 4) // The four byte read is a bug?
672 char touch_buffer
[4]; // @todo document this number
673 rc
= memcached_safe_read(instance
, touch_buffer
, sizeof(touch_buffer
));
675 fprintf(stderr
, "%s:%d %d %d %d %d %.*s(%d)\n", __FILE__
, __LINE__
,
676 int(touch_buffer
[0]),
677 int(touch_buffer
[1]),
678 int(touch_buffer
[2]),
679 int(touch_buffer
[3]),
680 int(bodylen
), touch_buffer
, int(bodylen
));
683 return memcached_set_error(*instance
, rc
, MEMCACHED_AT
);
686 case PROTOCOL_BINARY_CMD_FLUSH
:
687 case PROTOCOL_BINARY_CMD_QUIT
:
688 case PROTOCOL_BINARY_CMD_SET
:
689 case PROTOCOL_BINARY_CMD_ADD
:
690 case PROTOCOL_BINARY_CMD_REPLACE
:
691 case PROTOCOL_BINARY_CMD_APPEND
:
692 case PROTOCOL_BINARY_CMD_PREPEND
:
693 case PROTOCOL_BINARY_CMD_DELETE
:
695 WATCHPOINT_ASSERT(bodylen
== 0);
696 return MEMCACHED_SUCCESS
;
699 case PROTOCOL_BINARY_CMD_NOOP
:
701 WATCHPOINT_ASSERT(bodylen
== 0);
702 return MEMCACHED_END
;
705 case PROTOCOL_BINARY_CMD_STAT
:
709 return MEMCACHED_END
;
711 else if (bodylen
+ 1 > buffer_length
)
713 /* not enough space in buffer.. should not happen... */
714 return MEMCACHED_UNKNOWN_READ_FAILURE
;
718 size_t keylen
= header
.response
.keylen
;
719 memset(buffer
, 0, buffer_length
);
720 if ((rc
= memcached_safe_read(instance
, buffer
, keylen
)) != MEMCACHED_SUCCESS
||
721 (rc
= memcached_safe_read(instance
, buffer
+ keylen
+ 1, bodylen
- keylen
)) != MEMCACHED_SUCCESS
)
723 WATCHPOINT_ERROR(rc
);
724 return MEMCACHED_UNKNOWN_READ_FAILURE
;
730 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
731 case PROTOCOL_BINARY_CMD_SASL_STEP
:
733 memcached_result_reset(result
);
734 result
->item_cas
= header
.response
.cas
;
736 if (memcached_string_check(&result
->value
,
737 bodylen
) != MEMCACHED_SUCCESS
)
738 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
740 char *vptr
= memcached_string_value_mutable(&result
->value
);
741 if ((rc
= memcached_safe_read(instance
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
743 WATCHPOINT_ERROR(rc
);
744 return MEMCACHED_UNKNOWN_READ_FAILURE
;
747 memcached_string_set_length(&result
->value
, bodylen
);
752 /* Command not implemented yet! */
753 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
757 else if (header
.response
.bodylen
)
759 /* What should I do with the error message??? just discard it for now */
760 char hole
[SMALL_STRING_LEN
];
763 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
764 if ((rc
= memcached_safe_read(instance
, hole
, nr
)) != MEMCACHED_SUCCESS
)
766 WATCHPOINT_ERROR(rc
);
767 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
769 bodylen
-= (uint32_t) nr
;
772 /* This might be an error from one of the quiet commands.. if
773 * so, just throw it away and get the next one. What about creating
774 * a callback to the user with the error information?
776 switch (header
.response
.opcode
)
778 case PROTOCOL_BINARY_CMD_SETQ
:
779 case PROTOCOL_BINARY_CMD_ADDQ
:
780 case PROTOCOL_BINARY_CMD_REPLACEQ
:
781 case PROTOCOL_BINARY_CMD_APPENDQ
:
782 case PROTOCOL_BINARY_CMD_PREPENDQ
:
783 return binary_read_one_response(instance
, buffer
, buffer_length
, result
);
790 rc
= MEMCACHED_SUCCESS
;
791 if (header
.response
.status
!= 0)
793 switch (header
.response
.status
)
795 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
796 rc
= MEMCACHED_NOTFOUND
;
799 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
800 rc
= MEMCACHED_DATA_EXISTS
;
803 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
804 rc
= MEMCACHED_NOTSTORED
;
807 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
811 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
812 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
815 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
816 rc
= MEMCACHED_AUTH_CONTINUE
;
819 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
820 rc
= MEMCACHED_AUTH_FAILURE
;
823 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
824 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
826 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
834 static memcached_return_t
_read_one_response(memcached_instance_st
* instance
,
835 char *buffer
, const size_t buffer_length
,
836 memcached_result_st
*result
)
838 memcached_server_response_decrement(instance
);
842 Memcached
*root
= (Memcached
*)instance
->root
;
843 result
= &root
->result
;
846 memcached_return_t rc
;
847 if (memcached_is_binary(instance
->root
))
849 rc
= binary_read_one_response(instance
, buffer
, buffer_length
, result
);
853 rc
= textual_read_one_response(instance
, buffer
, buffer_length
, result
);
856 if (memcached_fatal(rc
))
858 memcached_io_reset(instance
);
864 memcached_return_t
memcached_read_one_response(memcached_instance_st
* instance
,
865 memcached_result_st
*result
)
867 char buffer
[SMALL_STRING_LEN
];
869 if (memcached_is_udp(instance
->root
))
871 return memcached_set_error(*instance
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
875 return _read_one_response(instance
, buffer
, sizeof(buffer
), result
);
878 memcached_return_t
memcached_response(memcached_instance_st
* instance
,
879 memcached_result_st
*result
)
883 return memcached_response(instance
, buffer
, sizeof(buffer
), result
);
886 memcached_return_t
memcached_response(memcached_instance_st
* instance
,
887 char *buffer
, size_t buffer_length
,
888 memcached_result_st
*result
)
890 if (memcached_is_udp(instance
->root
))
892 return memcached_set_error(*instance
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
895 /* We may have old commands in the buffer not set, first purge */
896 if ((instance
->root
->flags
.no_block
) and (memcached_is_processing_input(instance
->root
) == false))
898 (void)memcached_io_write(instance
);
902 * The previous implementation purged all pending requests and just
903 * returned the last one. Purge all pending messages to ensure backwards
906 if (memcached_is_binary(instance
->root
) == false and memcached_server_response_count(instance
) > 1)
908 memcached_result_st junked_result
;
909 memcached_result_st
*junked_result_ptr
= memcached_result_create(instance
->root
, &junked_result
);
911 assert(junked_result_ptr
);
913 while (memcached_server_response_count(instance
) > 1)
915 memcached_return_t rc
= _read_one_response(instance
, buffer
, buffer_length
, junked_result_ptr
);
917 // @TODO should we return an error on another but a bad read case?
918 if (memcached_fatal(rc
))
920 memcached_result_free(junked_result_ptr
);
924 memcached_result_free(junked_result_ptr
);
927 return _read_one_response(instance
, buffer
, buffer_length
, result
);