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_read_one_response(memcached_server_write_instance_st ptr
,
42 char *buffer
, size_t buffer_length
,
43 memcached_result_st
*result
);
44 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
45 char *buffer
, size_t buffer_length
,
46 memcached_result_st
*result
);
48 memcached_return_t
memcached_read_one_response(memcached_server_write_instance_st ptr
,
49 char *buffer
, size_t buffer_length
,
50 memcached_result_st
*result
)
52 memcached_server_response_decrement(ptr
);
56 memcached_st
*root
= (memcached_st
*)ptr
->root
;
57 result
= &root
->result
;
60 memcached_return_t rc
;
61 if (ptr
->root
->flags
.binary_protocol
)
63 rc
= binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
67 rc
= textual_read_one_response(ptr
, buffer
, buffer_length
, result
);
70 unlikely(rc
== MEMCACHED_UNKNOWN_READ_FAILURE
or
71 rc
== MEMCACHED_PROTOCOL_ERROR
or
72 rc
== MEMCACHED_CLIENT_ERROR
or
73 rc
== MEMCACHED_MEMORY_ALLOCATION_FAILURE
)
75 memcached_io_reset(ptr
);
81 memcached_return_t
memcached_response(memcached_server_write_instance_st ptr
,
82 char *buffer
, size_t buffer_length
,
83 memcached_result_st
*result
)
85 /* We may have old commands in the buffer not set, first purge */
86 if ((ptr
->root
->flags
.no_block
) && (memcached_is_processing_input(ptr
->root
) == false))
88 (void)memcached_io_write(ptr
, NULL
, 0, true);
92 * The previous implementation purged all pending requests and just
93 * returned the last one. Purge all pending messages to ensure backwards
96 if (ptr
->root
->flags
.binary_protocol
== false)
98 while (memcached_server_response_count(ptr
) > 1)
100 memcached_return_t rc
= memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
102 unlikely (rc
!= MEMCACHED_END
&&
103 rc
!= MEMCACHED_STORED
&&
104 rc
!= MEMCACHED_SUCCESS
&&
105 rc
!= MEMCACHED_STAT
&&
106 rc
!= MEMCACHED_DELETED
&&
107 rc
!= MEMCACHED_NOTFOUND
&&
108 rc
!= MEMCACHED_NOTSTORED
&&
109 rc
!= MEMCACHED_DATA_EXISTS
)
114 return memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
117 static memcached_return_t
textual_value_fetch(memcached_server_write_instance_st ptr
,
119 memcached_result_st
*result
)
126 ssize_t read_length
= 0;
128 if (ptr
->root
->flags
.use_udp
)
130 return memcached_set_error(*ptr
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
133 WATCHPOINT_ASSERT(ptr
->root
);
134 end_ptr
= buffer
+ MEMCACHED_DEFAULT_COMMAND_SIZE
;
136 memcached_result_reset(result
);
139 string_ptr
+= 6; /* "VALUE " */
142 /* We load the key */
145 size_t prefix_length
;
147 key
= result
->item_key
;
148 result
->key_length
= 0;
150 for (prefix_length
= memcached_array_size(ptr
->root
->_namespace
); !(iscntrl(*string_ptr
) || isspace(*string_ptr
)) ; string_ptr
++)
152 if (prefix_length
== 0)
156 result
->key_length
++;
161 result
->item_key
[result
->key_length
]= 0;
164 if (end_ptr
== string_ptr
)
167 /* Flags fetch move past space */
169 if (end_ptr
== string_ptr
)
172 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
173 result
->item_flags
= (uint32_t) strtoul(next_ptr
, &string_ptr
, 10);
175 if (end_ptr
== string_ptr
)
178 /* Length fetch move past space*/
180 if (end_ptr
== string_ptr
)
183 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
184 value_length
= (size_t)strtoull(next_ptr
, &string_ptr
, 10);
186 if (end_ptr
== string_ptr
)
190 if (*string_ptr
== '\r')
192 /* Skip past the \r\n */
198 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
199 result
->item_cas
= strtoull(next_ptr
, &string_ptr
, 10);
202 if (end_ptr
< string_ptr
)
205 /* We add two bytes so that we can walk the \r\n */
206 if (memcached_failed(memcached_string_check(&result
->value
, value_length
+2)))
208 return memcached_set_error(*ptr
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
, MEMCACHED_AT
);
212 char *value_ptr
= memcached_string_value_mutable(&result
->value
);
214 We read the \r\n into the string since not doing so is more
215 cycles then the waster of memory to do so.
217 We are null terminating through, which will most likely make
218 some people lazy about using the return length.
220 to_read
= (value_length
) + 2;
221 memcached_return_t rrc
= memcached_io_read(ptr
, value_ptr
, to_read
, &read_length
);
222 if (memcached_failed(rrc
) and rrc
== MEMCACHED_IN_PROGRESS
)
224 memcached_quit_server(ptr
, true);
225 return memcached_set_error(*ptr
, MEMCACHED_IN_PROGRESS
, MEMCACHED_AT
);
227 else if (memcached_failed(rrc
))
233 if (read_length
!= (ssize_t
)(value_length
+ 2))
238 /* This next bit blows the API, but this is internal....*/
241 char_ptr
= memcached_string_value_mutable(&result
->value
);;
242 char_ptr
[value_length
]= 0;
243 char_ptr
[value_length
+1]= 0;
244 memcached_string_set_length(&result
->value
, value_length
);
247 return MEMCACHED_SUCCESS
;
250 memcached_io_reset(ptr
);
252 return MEMCACHED_PARTIAL_READ
;
255 static memcached_return_t
textual_read_one_response(memcached_server_write_instance_st ptr
,
256 char *buffer
, size_t buffer_length
,
257 memcached_result_st
*result
)
260 memcached_return_t rc
= memcached_io_readline(ptr
, buffer
, buffer_length
, total_read
);
262 if (memcached_failed(rc
))
269 case 'V': /* VALUE || VERSION */
270 if (buffer
[1] == 'A') /* VALUE */
272 /* We add back in one because we will need to search for END */
273 memcached_server_response_increment(ptr
);
274 return textual_value_fetch(ptr
, buffer
, result
);
276 else if (buffer
[1] == 'E') /* VERSION */
278 return MEMCACHED_SUCCESS
;
282 WATCHPOINT_STRING(buffer
);
283 return MEMCACHED_UNKNOWN_READ_FAILURE
;
286 return MEMCACHED_SUCCESS
;
288 case 'S': /* STORED STATS SERVER_ERROR */
290 if (buffer
[2] == 'A') /* STORED STATS */
292 memcached_server_response_increment(ptr
);
293 return MEMCACHED_STAT
;
295 else if (buffer
[1] == 'E') /* SERVER_ERROR */
297 if (total_read
== memcached_literal_param_size("SERVER_ERROR"))
299 return MEMCACHED_SERVER_ERROR
;
302 if (total_read
> memcached_literal_param_size("SERVER_ERROR object too large for cache") and
303 (memcmp(buffer
, memcached_literal_param("SERVER_ERROR object too large for cache")) == 0))
305 return MEMCACHED_E2BIG
;
308 // Move past the basic error message and whitespace
309 char *startptr
= buffer
+ memcached_literal_param_size("SERVER_ERROR");
310 if (startptr
[0] == ' ')
315 char *endptr
= startptr
;
316 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
318 return memcached_set_error(*ptr
, MEMCACHED_SERVER_ERROR
, MEMCACHED_AT
, startptr
, size_t(endptr
- startptr
));
320 else if (buffer
[1] == 'T')
322 return MEMCACHED_STORED
;
326 WATCHPOINT_STRING(buffer
);
327 return MEMCACHED_UNKNOWN_READ_FAILURE
;
330 case 'D': /* DELETED */
331 return MEMCACHED_DELETED
;
333 case 'N': /* NOT_FOUND */
335 if (buffer
[4] == 'F')
337 return MEMCACHED_NOTFOUND
;
339 else if (buffer
[4] == 'S')
341 return MEMCACHED_NOTSTORED
;
345 WATCHPOINT_STRING(buffer
);
346 return MEMCACHED_UNKNOWN_READ_FAILURE
;
349 case 'E': /* PROTOCOL ERROR or END */
351 if (buffer
[1] == 'N')
353 return MEMCACHED_END
;
355 else if (buffer
[1] == 'R')
357 return MEMCACHED_PROTOCOL_ERROR
;
359 else if (buffer
[1] == 'X')
361 return MEMCACHED_DATA_EXISTS
;
365 WATCHPOINT_STRING(buffer
);
366 return MEMCACHED_UNKNOWN_READ_FAILURE
;
370 case 'T': /* TOUCHED */
372 if (buffer
[1] == 'O' and buffer
[2] == 'U'
373 and buffer
[3] == 'C' and buffer
[4] == 'H'
374 and buffer
[5] == 'E' and buffer
[6] == 'D')
376 return MEMCACHED_SUCCESS
;
379 return MEMCACHED_UNKNOWN_READ_FAILURE
;
381 case 'I': /* CLIENT ERROR */
382 /* We add back in one because we will need to search for END */
383 memcached_server_response_increment(ptr
);
384 return MEMCACHED_ITEM
;
386 case 'C': /* CLIENT ERROR */
387 return MEMCACHED_CLIENT_ERROR
;
391 unsigned long long auto_return_value
;
393 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
394 return MEMCACHED_SUCCESS
;
396 WATCHPOINT_STRING(buffer
);
397 return MEMCACHED_UNKNOWN_READ_FAILURE
;
404 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
405 char *buffer
, size_t buffer_length
,
406 memcached_result_st
*result
)
408 memcached_return_t rc
;
409 protocol_binary_response_header header
;
411 if ((rc
= memcached_safe_read(ptr
, &header
.bytes
, sizeof(header
.bytes
))) != MEMCACHED_SUCCESS
)
413 WATCHPOINT_ERROR(rc
);
417 if (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
419 return MEMCACHED_PROTOCOL_ERROR
;
423 ** Convert the header to host local endian!
425 header
.response
.keylen
= ntohs(header
.response
.keylen
);
426 header
.response
.status
= ntohs(header
.response
.status
);
427 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
428 header
.response
.cas
= memcached_ntohll(header
.response
.cas
);
429 uint32_t bodylen
= header
.response
.bodylen
;
431 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
or
432 header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
434 switch (header
.response
.opcode
)
436 case PROTOCOL_BINARY_CMD_GETKQ
:
438 * We didn't increment the response counter for the GETKQ packet
439 * (only the final NOOP), so we need to increment the counter again.
441 memcached_server_response_increment(ptr
);
443 case PROTOCOL_BINARY_CMD_GETK
:
445 uint16_t keylen
= header
.response
.keylen
;
446 memcached_result_reset(result
);
447 result
->item_cas
= header
.response
.cas
;
449 if ((rc
= memcached_safe_read(ptr
, &result
->item_flags
, sizeof (result
->item_flags
))) != MEMCACHED_SUCCESS
)
451 WATCHPOINT_ERROR(rc
);
452 return MEMCACHED_UNKNOWN_READ_FAILURE
;
455 result
->item_flags
= ntohl(result
->item_flags
);
456 bodylen
-= header
.response
.extlen
;
458 result
->key_length
= keylen
;
459 if (memcached_failed(rc
= memcached_safe_read(ptr
, result
->item_key
, keylen
)))
461 WATCHPOINT_ERROR(rc
);
462 return MEMCACHED_UNKNOWN_READ_FAILURE
;
465 // Only bother with doing this if key_length > 0
466 if (result
->key_length
)
468 if (memcached_array_size(ptr
->root
->_namespace
) and memcached_array_size(ptr
->root
->_namespace
) >= result
->key_length
)
470 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
473 if (memcached_array_size(ptr
->root
->_namespace
))
475 result
->key_length
-= memcached_array_size(ptr
->root
->_namespace
);
476 memmove(result
->item_key
, result
->item_key
+memcached_array_size(ptr
->root
->_namespace
), result
->key_length
);
481 if (memcached_failed(memcached_string_check(&result
->value
, bodylen
)))
483 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
486 char *vptr
= memcached_string_value_mutable(&result
->value
);
487 if (memcached_failed(rc
= memcached_safe_read(ptr
, vptr
, bodylen
)))
489 WATCHPOINT_ERROR(rc
);
490 return MEMCACHED_UNKNOWN_READ_FAILURE
;
493 memcached_string_set_length(&result
->value
, bodylen
);
497 case PROTOCOL_BINARY_CMD_INCREMENT
:
498 case PROTOCOL_BINARY_CMD_DECREMENT
:
500 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
502 return MEMCACHED_PROTOCOL_ERROR
;
505 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
507 if ((rc
= memcached_safe_read(ptr
, &val
, sizeof(val
))) != MEMCACHED_SUCCESS
)
509 WATCHPOINT_ERROR(rc
);
510 return MEMCACHED_UNKNOWN_READ_FAILURE
;
513 val
= memcached_ntohll(val
);
514 memcpy(buffer
, &val
, sizeof(val
));
518 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
519 case PROTOCOL_BINARY_CMD_VERSION
:
521 memset(buffer
, 0, buffer_length
);
522 if (bodylen
>= buffer_length
)
524 /* not enough space in buffer.. should not happen... */
525 return MEMCACHED_UNKNOWN_READ_FAILURE
;
527 else if ((rc
= memcached_safe_read(ptr
, buffer
, bodylen
)) != MEMCACHED_SUCCESS
)
529 WATCHPOINT_ERROR(rc
);
530 return MEMCACHED_UNKNOWN_READ_FAILURE
;
534 case PROTOCOL_BINARY_CMD_FLUSH
:
535 case PROTOCOL_BINARY_CMD_QUIT
:
536 case PROTOCOL_BINARY_CMD_SET
:
537 case PROTOCOL_BINARY_CMD_ADD
:
538 case PROTOCOL_BINARY_CMD_REPLACE
:
539 case PROTOCOL_BINARY_CMD_APPEND
:
540 case PROTOCOL_BINARY_CMD_PREPEND
:
541 case PROTOCOL_BINARY_CMD_DELETE
:
542 case PROTOCOL_BINARY_CMD_TOUCH
:
544 WATCHPOINT_ASSERT(bodylen
== 0);
545 return MEMCACHED_SUCCESS
;
548 case PROTOCOL_BINARY_CMD_NOOP
:
550 WATCHPOINT_ASSERT(bodylen
== 0);
551 return MEMCACHED_END
;
554 case PROTOCOL_BINARY_CMD_STAT
:
558 return MEMCACHED_END
;
560 else if (bodylen
+ 1 > buffer_length
)
562 /* not enough space in buffer.. should not happen... */
563 return MEMCACHED_UNKNOWN_READ_FAILURE
;
567 size_t keylen
= header
.response
.keylen
;
568 memset(buffer
, 0, buffer_length
);
569 if ((rc
= memcached_safe_read(ptr
, buffer
, keylen
)) != MEMCACHED_SUCCESS
||
570 (rc
= memcached_safe_read(ptr
, buffer
+ keylen
+ 1, bodylen
- keylen
)) != MEMCACHED_SUCCESS
)
572 WATCHPOINT_ERROR(rc
);
573 return MEMCACHED_UNKNOWN_READ_FAILURE
;
579 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
580 case PROTOCOL_BINARY_CMD_SASL_STEP
:
582 memcached_result_reset(result
);
583 result
->item_cas
= header
.response
.cas
;
585 if (memcached_string_check(&result
->value
,
586 bodylen
) != MEMCACHED_SUCCESS
)
587 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
589 char *vptr
= memcached_string_value_mutable(&result
->value
);
590 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
592 WATCHPOINT_ERROR(rc
);
593 return MEMCACHED_UNKNOWN_READ_FAILURE
;
596 memcached_string_set_length(&result
->value
, bodylen
);
601 /* Command not implemented yet! */
602 WATCHPOINT_ASSERT(0);
603 return MEMCACHED_PROTOCOL_ERROR
;
607 else if (header
.response
.bodylen
)
609 /* What should I do with the error message??? just discard it for now */
610 char hole
[SMALL_STRING_LEN
];
613 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
614 if ((rc
= memcached_safe_read(ptr
, hole
, nr
)) != MEMCACHED_SUCCESS
)
616 WATCHPOINT_ERROR(rc
);
617 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
619 bodylen
-= (uint32_t) nr
;
622 /* This might be an error from one of the quiet commands.. if
623 * so, just throw it away and get the next one. What about creating
624 * a callback to the user with the error information?
626 switch (header
.response
.opcode
)
628 case PROTOCOL_BINARY_CMD_SETQ
:
629 case PROTOCOL_BINARY_CMD_ADDQ
:
630 case PROTOCOL_BINARY_CMD_REPLACEQ
:
631 case PROTOCOL_BINARY_CMD_APPENDQ
:
632 case PROTOCOL_BINARY_CMD_PREPENDQ
:
633 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
640 rc
= MEMCACHED_SUCCESS
;
641 if (header
.response
.status
!= 0)
643 switch (header
.response
.status
)
645 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
646 rc
= MEMCACHED_NOTFOUND
;
649 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
650 rc
= MEMCACHED_DATA_EXISTS
;
653 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
654 rc
= MEMCACHED_NOTSTORED
;
657 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
661 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
662 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
665 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
666 rc
= MEMCACHED_AUTH_CONTINUE
;
669 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
670 rc
= MEMCACHED_AUTH_FAILURE
;
673 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
674 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
676 /* @todo fix the error mappings */
677 rc
= MEMCACHED_PROTOCOL_ERROR
;