2 +--------------------------------------------------------------------+
3 | libmemcached - C/C++ Client Library for memcached |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted under the terms of the BSD license. |
7 | You should have received a copy of the license in a bundled file |
8 | named LICENSE; in case you did not receive a copy you can review |
9 | the terms online at: https://opensource.org/licenses/BSD-3-Clause |
10 +--------------------------------------------------------------------+
11 | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ |
12 | Copyright (c) 2020 Michael Wallner <mike@php.net> |
13 +--------------------------------------------------------------------+
16 #include "libmemcached/common.h"
17 #include "libmemcached/string.hpp"
19 static memcached_return_t
textual_value_fetch(memcached_instance_st
*instance
, char *buffer
,
20 memcached_result_st
*result
) {
22 ssize_t read_length
= 0;
25 WATCHPOINT_ASSERT(instance
->root
);
26 char *end_ptr
= buffer
+ MEMCACHED_DEFAULT_COMMAND_SIZE
;
28 memcached_result_reset(result
);
30 char *string_ptr
= buffer
;
31 string_ptr
+= 6; /* "VALUE " */
33 // Just used for cases of AES decrypt currently
34 memcached_return_t rc
= MEMCACHED_SUCCESS
;
38 char *key
= result
->item_key
;
39 result
->key_length
= 0;
41 for (ptrdiff_t prefix_length
= memcached_array_size(instance
->root
->_namespace
);
42 !(iscntrl(*string_ptr
) || isspace(*string_ptr
)); string_ptr
++)
44 if (prefix_length
== 0) {
51 result
->item_key
[result
->key_length
] = 0;
54 if (end_ptr
== string_ptr
) {
58 /* Flags fetch move past space */
60 if (end_ptr
== string_ptr
) {
64 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {
67 result
->item_flags
= (uint32_t) strtoul(next_ptr
, &string_ptr
, 10);
69 if (errno
or end_ptr
== string_ptr
) {
73 /* Length fetch move past space*/
75 if (end_ptr
== string_ptr
) {
79 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {
82 value_length
= (size_t) strtoull(next_ptr
, &string_ptr
, 10);
84 if (errno
or end_ptr
== string_ptr
) {
89 if (*string_ptr
== '\r') {
90 /* Skip past the \r\n */
94 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {
97 result
->item_cas
= strtoull(next_ptr
, &string_ptr
, 10);
100 if (errno
or end_ptr
< string_ptr
) {
104 /* We add two bytes so that we can walk the \r\n */
105 if (memcached_failed(memcached_string_check(&result
->value
, value_length
+ 2))) {
106 return memcached_set_error(*instance
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
, MEMCACHED_AT
);
110 char *value_ptr
= memcached_string_value_mutable(&result
->value
);
112 We read the \r\n into the string since not doing so is more
113 cycles then the waster of memory to do so.
115 We are null terminating through, which will most likely make
116 some people lazy about using the return length.
118 size_t to_read
= (value_length
) + 2;
119 memcached_return_t rrc
= memcached_io_read(instance
, value_ptr
, to_read
, read_length
);
120 if (memcached_failed(rrc
) and rrc
== MEMCACHED_IN_PROGRESS
) {
121 memcached_quit_server(instance
, true);
122 return memcached_set_error(*instance
, MEMCACHED_IN_PROGRESS
, MEMCACHED_AT
);
123 } else if (memcached_failed(rrc
)) {
128 if (read_length
!= (ssize_t
)(value_length
+ 2)) {
132 /* This next bit blows the API, but this is internal....*/
135 char_ptr
= memcached_string_value_mutable(&result
->value
);
137 char_ptr
[value_length
] = 0;
138 char_ptr
[value_length
+ 1] = 0;
139 memcached_string_set_length(&result
->value
, value_length
);
142 if (memcached_is_encrypted(instance
->root
) and memcached_result_length(result
)) {
143 hashkit_string_st
*destination
;
145 if ((destination
= hashkit_decrypt(&instance
->root
->hashkit
, memcached_result_value(result
),
146 memcached_result_length(result
)))
149 rc
= memcached_set_error(*instance
->root
, MEMCACHED_FAILURE
, MEMCACHED_AT
,
150 memcached_literal_param("hashkit_decrypt() failed"));
152 memcached_result_reset_value(result
);
153 if (memcached_failed(memcached_result_set_value(result
, hashkit_string_c_str(destination
),
154 hashkit_string_length(destination
))))
156 rc
= memcached_set_error(*instance
->root
, MEMCACHED_FAILURE
, MEMCACHED_AT
,
157 memcached_literal_param("hashkit_decrypt() failed"));
161 if (memcached_failed(rc
)) {
162 memcached_result_reset(result
);
164 hashkit_string_free(destination
);
170 memcached_io_reset(instance
);
172 return MEMCACHED_PARTIAL_READ
;
175 static memcached_return_t
textual_read_one_response(memcached_instance_st
*instance
, char *buffer
,
176 const size_t buffer_length
,
177 memcached_result_st
*result
) {
179 memcached_return_t rc
= memcached_io_readline(instance
, buffer
, buffer_length
, total_read
);
181 if (memcached_failed(rc
)) {
189 if (buffer
[1] == 'A' and buffer
[2] == 'L' and buffer
[3] == 'U' and buffer
[4] == 'E') /* VALUE */
191 /* We add back in one because we will need to search for END */
192 memcached_server_response_increment(instance
);
193 return textual_value_fetch(instance
, buffer
, result
);
196 else if (buffer
[1] == 'E' and buffer
[2] == 'R' and buffer
[3] == 'S' and buffer
[4] == 'I'
197 and buffer
[5] == 'O' and buffer
[6] == 'N') /* VERSION */
199 /* Find the space, and then move one past it to copy version */
200 char *response_ptr
= strchr(buffer
, ' ');
204 long int version
= strtol(response_ptr
, &endptr
, 10);
205 if (errno
or version
== LONG_MIN
or version
== LONG_MAX
or version
> UINT8_MAX
207 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
208 return memcached_set_error(
209 *instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
210 memcached_literal_param("strtol() failed to parse major version"));
212 instance
->major_version
= uint8_t(version
);
216 version
= strtol(endptr
, &endptr
, 10);
217 if (errno
or version
== LONG_MIN
or version
== LONG_MAX
or version
> UINT8_MAX
) {
218 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
219 return memcached_set_error(
220 *instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
221 memcached_literal_param("strtol() failed to parse minor version"));
223 instance
->minor_version
= uint8_t(version
);
227 version
= strtol(endptr
, &endptr
, 10);
228 if (errno
or version
== LONG_MIN
or version
== LONG_MAX
or version
> UINT8_MAX
) {
229 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
230 return memcached_set_error(
231 *instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
232 memcached_literal_param("strtol() failed to parse micro version"));
234 instance
->micro_version
= uint8_t(version
);
236 return MEMCACHED_SUCCESS
;
242 if (buffer
[1] == 'K') {
243 return MEMCACHED_SUCCESS
;
249 if (buffer
[1] == 'T' and buffer
[2] == 'A' and buffer
[3] == 'T') /* STORED STATS */ {
250 memcached_server_response_increment(instance
);
251 return MEMCACHED_STAT
;
254 else if (buffer
[1] == 'E' and buffer
[2] == 'R' and buffer
[3] == 'V' and buffer
[4] == 'E'
255 and buffer
[5] == 'R' and buffer
[6] == '_' and buffer
[7] == 'E' and buffer
[8] == 'R'
256 and buffer
[9] == 'R' and buffer
[10] == 'O' and buffer
[11] == 'R')
258 if (total_read
== memcached_literal_param_size("SERVER_ERROR")) {
259 return MEMCACHED_SERVER_ERROR
;
262 if (total_read
>= memcached_literal_param_size("SERVER_ERROR object too large for cache")
263 and (memcmp(buffer
, memcached_literal_param("SERVER_ERROR object too large for cache"))
266 return MEMCACHED_E2BIG
;
269 if (total_read
>= memcached_literal_param_size("SERVER_ERROR out of memory")
270 and ((memcmp(buffer
, memcached_literal_param("SERVER_ERROR out of memory")) == 0)
271 or (memcmp(buffer
, memcached_literal_param("SERVER_ERROR Out of memory")) == 0)))
273 return MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE
;
276 // Move past the basic error message and whitespace
277 char *startptr
= buffer
+ memcached_literal_param_size("SERVER_ERROR");
278 if (startptr
[0] == ' ') {
282 char *endptr
= startptr
;
283 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
285 return memcached_set_error(*instance
, MEMCACHED_SERVER_ERROR
, MEMCACHED_AT
, startptr
,
286 size_t(endptr
- startptr
));
289 else if (buffer
[1] == 'T' and buffer
[2] == 'O'
290 and buffer
[3] == 'R') // and buffer[4] == 'E' and buffer[5] == 'D')
292 return MEMCACHED_STORED
;
298 if (buffer
[1] == 'E' and buffer
[2] == 'L' and buffer
[3] == 'E' and buffer
[4] == 'T'
299 and buffer
[5] == 'E' and buffer
[6] == 'D')
301 return MEMCACHED_DELETED
;
307 if (buffer
[1] == 'O' and buffer
[2] == 'T' and buffer
[3] == '_' and buffer
[4] == 'F'
308 and buffer
[5] == 'O' and buffer
[6] == 'U' and buffer
[7] == 'N' and buffer
[8] == 'D')
310 return MEMCACHED_NOTFOUND
;
313 else if (buffer
[1] == 'O' and buffer
[2] == 'T' and buffer
[3] == '_' and buffer
[4] == 'S'
314 and buffer
[5] == 'T' and buffer
[6] == 'O' and buffer
[7] == 'R' and buffer
[8] == 'E'
315 and buffer
[9] == 'D')
317 return MEMCACHED_NOTSTORED
;
321 case 'E': /* PROTOCOL ERROR or END */
324 if (buffer
[1] == 'N' and buffer
[2] == 'D') {
325 return MEMCACHED_END
;
329 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'
331 and buffer
[9] == 'E' and buffer
[10] == 'R' and buffer
[11] == 'R' and buffer
[12] == 'O' and buffer
[13] == 'R')
333 return MEMCACHED_PROTOCOL_ERROR
;
337 else if (buffer
[1] == 'R' and buffer
[2] == 'R' and buffer
[3] == 'O' and buffer
[4] == 'R')
339 return MEMCACHED_ERROR
;
342 else if (buffer
[1] == 'X' and buffer
[2] == 'I' and buffer
[3] == 'S' and buffer
[4] == 'T'
343 and buffer
[5] == 'S')
345 return MEMCACHED_DATA_EXISTS
;
349 case 'T': /* TOUCHED */
352 if (buffer
[1] == 'O' and buffer
[2] == 'U' and buffer
[3] == 'C' and buffer
[4] == 'H'
353 and buffer
[5] == 'E' and buffer
[6] == 'D')
355 return MEMCACHED_SUCCESS
;
362 if (buffer
[1] == 'T' and buffer
[2] == 'E' and buffer
[3] == 'M') {
363 /* We add back in one because we will need to search for END */
364 memcached_server_response_increment(instance
);
365 return MEMCACHED_ITEM
;
369 case 'C': /* CLIENT ERROR */
372 if (buffer
[1] == 'L' and buffer
[2] == 'I' and buffer
[3] == 'E' and buffer
[4] == 'N'
373 and buffer
[5] == 'T' and buffer
[6] == '_' and buffer
[7] == 'E' and buffer
[8] == 'R'
374 and buffer
[9] == 'R' and buffer
[10] == 'O' and buffer
[11] == 'R')
376 // Move past the basic error message and whitespace
377 char *startptr
= buffer
+ memcached_literal_param_size("CLIENT_ERROR");
378 if (startptr
[0] == ' ') {
382 char *endptr
= startptr
;
383 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
385 return memcached_set_error(*instance
, MEMCACHED_CLIENT_ERROR
, MEMCACHED_AT
, startptr
,
386 size_t(endptr
- startptr
));
390 case '0': /* INCR/DECR response */
391 case '1': /* INCR/DECR response */
392 case '2': /* INCR/DECR response */
393 case '3': /* INCR/DECR response */
394 case '4': /* INCR/DECR response */
395 case '5': /* INCR/DECR response */
396 case '6': /* INCR/DECR response */
397 case '7': /* INCR/DECR response */
398 case '8': /* INCR/DECR response */
399 case '9': /* INCR/DECR response */
402 unsigned long long int auto_return_value
= strtoull(buffer
, (char **) NULL
, 10);
404 if (auto_return_value
== ULLONG_MAX
and errno
== ERANGE
) {
405 result
->numeric_value
= UINT64_MAX
;
406 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
407 memcached_literal_param("Numeric response was out of range"));
408 } else if (errno
== EINVAL
) {
409 result
->numeric_value
= UINT64_MAX
;
410 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
411 memcached_literal_param("Numeric response was out of range"));
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"));
418 result
->numeric_value
= uint64_t(auto_return_value
);
420 WATCHPOINT_STRING(buffer
);
421 return MEMCACHED_SUCCESS
;
428 buffer
[total_read
] = 0;
430 if (total_read
>= sizeof("STORSTORED") -1)
432 fprintf(stderr
, "%s:%d '%s', %.*s\n", __FILE__
, __LINE__
,
433 buffer
, MEMCACHED_MAX_BUFFER
, instance
->read_buffer
);
434 assert(memcmp(buffer
,"STORSTORED", sizeof("STORSTORED") -1));
437 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
, buffer
,
441 static memcached_return_t
binary_read_one_response(memcached_instance_st
*instance
, char *buffer
,
442 const size_t buffer_length
,
443 memcached_result_st
*result
) {
444 memcached_return_t rc
;
445 protocol_binary_response_header header
;
447 assert(memcached_is_binary(instance
->root
));
449 if ((rc
= memcached_safe_read(instance
, &header
.bytes
, sizeof(header
.bytes
)))
450 != MEMCACHED_SUCCESS
) {
451 WATCHPOINT_ERROR(rc
);
455 if (header
.response
.magic
!= PROTOCOL_BINARY_RES
) {
456 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
460 ** Convert the header to host local endian!
462 header
.response
.keylen
= ntohs(header
.response
.keylen
);
463 header
.response
.status
= ntohs(header
.response
.status
);
464 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
465 header
.response
.cas
= memcached_ntohll(header
.response
.cas
);
466 uint32_t bodylen
= header
.response
.bodylen
;
468 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
469 or header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
471 switch (header
.response
.opcode
) {
472 case PROTOCOL_BINARY_CMD_GETKQ
:
474 * We didn't increment the response counter for the GETKQ packet
475 * (only the final NOOP), so we need to increment the counter again.
477 memcached_server_response_increment(instance
);
479 case PROTOCOL_BINARY_CMD_GETK
: {
480 uint16_t keylen
= header
.response
.keylen
;
481 memcached_result_reset(result
);
482 result
->item_cas
= header
.response
.cas
;
484 if ((rc
= memcached_safe_read(instance
, &result
->item_flags
, sizeof(result
->item_flags
)))
485 != MEMCACHED_SUCCESS
)
487 WATCHPOINT_ERROR(rc
);
488 return MEMCACHED_UNKNOWN_READ_FAILURE
;
491 result
->item_flags
= ntohl(result
->item_flags
);
492 bodylen
-= header
.response
.extlen
;
494 result
->key_length
= keylen
;
495 if (memcached_failed(rc
= memcached_safe_read(instance
, result
->item_key
, keylen
))) {
496 WATCHPOINT_ERROR(rc
);
497 return MEMCACHED_UNKNOWN_READ_FAILURE
;
500 // Only bother with doing this if key_length > 0
501 if (result
->key_length
) {
502 if (memcached_array_size(instance
->root
->_namespace
)
503 and memcached_array_size(instance
->root
->_namespace
) >= result
->key_length
)
505 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
508 if (memcached_array_size(instance
->root
->_namespace
)) {
509 result
->key_length
-= memcached_array_size(instance
->root
->_namespace
);
510 memmove(result
->item_key
,
511 result
->item_key
+ memcached_array_size(instance
->root
->_namespace
),
517 if (memcached_failed(memcached_string_check(&result
->value
, bodylen
))) {
518 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
521 char *vptr
= memcached_string_value_mutable(&result
->value
);
522 if (memcached_failed(rc
= memcached_safe_read(instance
, vptr
, bodylen
))) {
523 WATCHPOINT_ERROR(rc
);
524 return MEMCACHED_UNKNOWN_READ_FAILURE
;
527 memcached_string_set_length(&result
->value
, bodylen
);
530 case PROTOCOL_BINARY_CMD_INCREMENT
:
531 case PROTOCOL_BINARY_CMD_DECREMENT
: {
532 if (bodylen
!= sizeof(uint64_t)) {
533 result
->numeric_value
= UINT64_MAX
;
534 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
538 if ((rc
= memcached_safe_read(instance
, &val
, sizeof(val
))) != MEMCACHED_SUCCESS
) {
539 result
->numeric_value
= UINT64_MAX
;
540 return MEMCACHED_UNKNOWN_READ_FAILURE
;
543 result
->numeric_value
= memcached_ntohll(val
);
546 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
: {
547 if (header
.response
.keylen
|| bodylen
+ 1 > buffer_length
) {
548 return MEMCACHED_UNKNOWN_READ_FAILURE
;
550 if ((rc
= memcached_safe_read(instance
, buffer
, bodylen
)) != MEMCACHED_SUCCESS
) {
551 return MEMCACHED_UNKNOWN_READ_FAILURE
;
556 case PROTOCOL_BINARY_CMD_VERSION
: {
557 char version_buffer
[32]; // @todo document this number
558 memset(version_buffer
, 0, sizeof(version_buffer
));
560 if (memcached_safe_read(instance
, version_buffer
, bodylen
) != MEMCACHED_SUCCESS
) {
561 return MEMCACHED_UNKNOWN_READ_FAILURE
;
566 long int version
= strtol(version_buffer
, &endptr
, 10);
567 if (errno
or version
== LONG_MIN
or version
== LONG_MAX
or version
> UINT8_MAX
569 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
570 return memcached_set_error(
571 *instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
572 memcached_literal_param("strtol() failed to parse major version"));
574 instance
->major_version
= uint8_t(version
);
578 version
= strtol(endptr
, &endptr
, 10);
579 if (errno
or version
== LONG_MIN
or version
== LONG_MAX
or version
> UINT8_MAX
) {
580 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
581 return memcached_set_error(
582 *instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
583 memcached_literal_param("strtol() failed to parse minor version"));
585 instance
->minor_version
= uint8_t(version
);
589 version
= strtol(endptr
, &endptr
, 10);
590 if (errno
or version
== LONG_MIN
or version
== LONG_MAX
or version
> UINT8_MAX
) {
591 instance
->major_version
= instance
->minor_version
= instance
->micro_version
= UINT8_MAX
;
592 return memcached_set_error(
593 *instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
,
594 memcached_literal_param("strtol() failed to parse micro version"));
596 instance
->micro_version
= uint8_t(version
);
599 case PROTOCOL_BINARY_CMD_TOUCH
: {
600 rc
= MEMCACHED_SUCCESS
;
601 if (bodylen
== 4) // The four byte read is a bug?
603 char touch_buffer
[4]; // @todo document this number
604 rc
= memcached_safe_read(instance
, touch_buffer
, sizeof(touch_buffer
));
606 fprintf(stderr
, "%s:%d %d %d %d %d %.*s(%d)\n", __FILE__
, __LINE__
,
607 int(touch_buffer
[0]),
608 int(touch_buffer
[1]),
609 int(touch_buffer
[2]),
610 int(touch_buffer
[3]),
611 int(bodylen
), touch_buffer
, int(bodylen
));
614 return memcached_set_error(*instance
, rc
, MEMCACHED_AT
);
617 case PROTOCOL_BINARY_CMD_FLUSH
:
618 case PROTOCOL_BINARY_CMD_QUIT
:
619 case PROTOCOL_BINARY_CMD_SET
:
620 case PROTOCOL_BINARY_CMD_ADD
:
621 case PROTOCOL_BINARY_CMD_REPLACE
:
622 case PROTOCOL_BINARY_CMD_APPEND
:
623 case PROTOCOL_BINARY_CMD_PREPEND
:
624 case PROTOCOL_BINARY_CMD_DELETE
: {
625 WATCHPOINT_ASSERT(bodylen
== 0);
626 return MEMCACHED_SUCCESS
;
629 case PROTOCOL_BINARY_CMD_NOOP
: {
630 WATCHPOINT_ASSERT(bodylen
== 0);
631 return MEMCACHED_END
;
634 case PROTOCOL_BINARY_CMD_STAT
: {
636 return MEMCACHED_END
;
637 } else if (bodylen
+ 1 > buffer_length
) {
638 /* not enough space in buffer.. should not happen... */
639 return MEMCACHED_UNKNOWN_READ_FAILURE
;
641 size_t keylen
= header
.response
.keylen
;
642 memset(buffer
, 0, buffer_length
);
643 if ((rc
= memcached_safe_read(instance
, buffer
, keylen
)) != MEMCACHED_SUCCESS
644 || (rc
= memcached_safe_read(instance
, buffer
+ keylen
+ 1, bodylen
- keylen
))
645 != MEMCACHED_SUCCESS
)
647 WATCHPOINT_ERROR(rc
);
648 return MEMCACHED_UNKNOWN_READ_FAILURE
;
653 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
654 case PROTOCOL_BINARY_CMD_SASL_STEP
: {
655 memcached_result_reset(result
);
656 result
->item_cas
= header
.response
.cas
;
658 if (memcached_string_check(&result
->value
, bodylen
) != MEMCACHED_SUCCESS
)
659 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
661 char *vptr
= memcached_string_value_mutable(&result
->value
);
662 if ((rc
= memcached_safe_read(instance
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
) {
663 WATCHPOINT_ERROR(rc
);
664 return MEMCACHED_UNKNOWN_READ_FAILURE
;
667 memcached_string_set_length(&result
->value
, bodylen
);
670 /* Command not implemented yet! */
671 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
674 } else if (header
.response
.bodylen
) {
675 /* What should I do with the error message??? just discard it for now */
676 char hole
[SMALL_STRING_LEN
];
677 while (bodylen
> 0) {
678 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
679 if ((rc
= memcached_safe_read(instance
, hole
, nr
)) != MEMCACHED_SUCCESS
) {
680 WATCHPOINT_ERROR(rc
);
681 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
683 bodylen
-= (uint32_t) nr
;
686 /* This might be an error from one of the quiet commands.. if
687 * so, just throw it away and get the next one. What about creating
688 * a callback to the user with the error information?
690 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 MEMCACHED_FETCH_NOTFINISHED
;
703 rc
= MEMCACHED_SUCCESS
;
704 if (header
.response
.status
) {
705 switch (header
.response
.status
) {
706 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
707 rc
= MEMCACHED_NOTFOUND
;
710 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
711 rc
= MEMCACHED_DATA_EXISTS
;
714 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
715 rc
= MEMCACHED_NOTSTORED
;
718 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
719 rc
= MEMCACHED_E2BIG
;
722 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
723 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
726 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
727 rc
= MEMCACHED_AUTH_CONTINUE
;
730 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
731 rc
= MEMCACHED_AUTH_FAILURE
;
734 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
735 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
737 return memcached_set_error(*instance
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
745 static memcached_return_t
_read_one_response(memcached_instance_st
*instance
, char *buffer
,
746 const size_t buffer_length
,
747 memcached_result_st
*result
) {
748 memcached_server_response_decrement(instance
);
750 if (result
== NULL
) {
751 Memcached
*root
= (Memcached
*) instance
->root
;
752 result
= &root
->result
;
755 memcached_return_t rc
;
756 if (memcached_is_binary(instance
->root
)) {
758 rc
= binary_read_one_response(instance
, buffer
, buffer_length
, result
);
759 } while (rc
== MEMCACHED_FETCH_NOTFINISHED
);
761 rc
= textual_read_one_response(instance
, buffer
, buffer_length
, result
);
764 if (memcached_fatal(rc
) && rc
!= MEMCACHED_TIMEOUT
) {
765 memcached_io_reset(instance
);
771 memcached_return_t
memcached_read_one_response(memcached_instance_st
*instance
,
772 memcached_result_st
*result
) {
773 char buffer
[SMALL_STRING_LEN
];
775 if (memcached_is_udp(instance
->root
)) {
776 return memcached_set_error(*instance
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
779 return _read_one_response(instance
, buffer
, sizeof(buffer
), result
);
782 memcached_return_t
memcached_response(memcached_instance_st
*instance
,
783 memcached_result_st
*result
) {
786 return memcached_response(instance
, buffer
, sizeof(buffer
), result
);
789 memcached_return_t
memcached_response(memcached_instance_st
*instance
, char *buffer
,
790 size_t buffer_length
, memcached_result_st
*result
) {
791 if (memcached_is_udp(instance
->root
)) {
792 return memcached_set_error(*instance
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
795 /* We may have old commands in the buffer not sent, first purge */
796 if ((instance
->root
->flags
.no_block
) and (memcached_is_processing_input(instance
->root
) == false))
798 (void) memcached_io_write(instance
);
801 /* Before going into loop wait to see if we have any IO waiting for us */
803 memcached_return_t read_rc
= memcached_io_wait_for_read(instance
);
804 fprintf(stderr
, "%s:%d: %s\n", __FILE__
, __LINE__
, memcached_strerror(NULL
, read_rc
));
808 * The previous implementation purged all pending requests and just
809 * returned the last one. Purge all pending messages to ensure backwards
812 if (memcached_is_binary(instance
->root
) == false
813 and memcached_server_response_count(instance
) > 1) {
814 memcached_result_st junked_result
;
815 memcached_result_st
*junked_result_ptr
=
816 memcached_result_create(instance
->root
, &junked_result
);
818 assert(junked_result_ptr
);
820 while (memcached_server_response_count(instance
) > 1) {
821 memcached_return_t rc
=
822 _read_one_response(instance
, buffer
, buffer_length
, junked_result_ptr
);
824 // @TODO should we return an error on another but a bad read case?
825 if (memcached_fatal(rc
)) {
826 memcached_result_free(junked_result_ptr
);
830 memcached_result_free(junked_result_ptr
);
833 return _read_one_response(instance
, buffer
, buffer_length
, result
);