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
)
74 memcached_io_reset(ptr
);
79 memcached_return_t
memcached_response(memcached_server_write_instance_st ptr
,
80 char *buffer
, size_t buffer_length
,
81 memcached_result_st
*result
)
83 /* We may have old commands in the buffer not set, first purge */
84 if ((ptr
->root
->flags
.no_block
) && (memcached_is_processing_input(ptr
->root
) == false))
86 (void)memcached_io_write(ptr
, NULL
, 0, true);
90 * The previous implementation purged all pending requests and just
91 * returned the last one. Purge all pending messages to ensure backwards
94 if (ptr
->root
->flags
.binary_protocol
== false)
96 while (memcached_server_response_count(ptr
) > 1)
98 memcached_return_t rc
= memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
100 unlikely (rc
!= MEMCACHED_END
&&
101 rc
!= MEMCACHED_STORED
&&
102 rc
!= MEMCACHED_SUCCESS
&&
103 rc
!= MEMCACHED_STAT
&&
104 rc
!= MEMCACHED_DELETED
&&
105 rc
!= MEMCACHED_NOTFOUND
&&
106 rc
!= MEMCACHED_NOTSTORED
&&
107 rc
!= MEMCACHED_DATA_EXISTS
)
112 return memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
115 static memcached_return_t
textual_value_fetch(memcached_server_write_instance_st ptr
,
117 memcached_result_st
*result
)
124 ssize_t read_length
= 0;
126 if (ptr
->root
->flags
.use_udp
)
127 return memcached_set_error(*ptr
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
129 WATCHPOINT_ASSERT(ptr
->root
);
130 end_ptr
= buffer
+ MEMCACHED_DEFAULT_COMMAND_SIZE
;
132 memcached_result_reset(result
);
135 string_ptr
+= 6; /* "VALUE " */
138 /* We load the key */
141 size_t prefix_length
;
143 key
= result
->item_key
;
144 result
->key_length
= 0;
146 for (prefix_length
= memcached_array_size(ptr
->root
->_namespace
); !(iscntrl(*string_ptr
) || isspace(*string_ptr
)) ; string_ptr
++)
148 if (prefix_length
== 0)
152 result
->key_length
++;
157 result
->item_key
[result
->key_length
]= 0;
160 if (end_ptr
== string_ptr
)
163 /* Flags fetch move past space */
165 if (end_ptr
== string_ptr
)
168 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
169 result
->item_flags
= (uint32_t) strtoul(next_ptr
, &string_ptr
, 10);
171 if (end_ptr
== string_ptr
)
174 /* Length fetch move past space*/
176 if (end_ptr
== string_ptr
)
179 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
180 value_length
= (size_t)strtoull(next_ptr
, &string_ptr
, 10);
182 if (end_ptr
== string_ptr
)
186 if (*string_ptr
== '\r')
188 /* Skip past the \r\n */
194 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
195 result
->item_cas
= strtoull(next_ptr
, &string_ptr
, 10);
198 if (end_ptr
< string_ptr
)
201 /* We add two bytes so that we can walk the \r\n */
202 if (memcached_failed(memcached_string_check(&result
->value
, value_length
+2)))
204 return memcached_set_error(*ptr
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
, MEMCACHED_AT
);
208 char *value_ptr
= memcached_string_value_mutable(&result
->value
);
210 We read the \r\n into the string since not doing so is more
211 cycles then the waster of memory to do so.
213 We are null terminating through, which will most likely make
214 some people lazy about using the return length.
216 to_read
= (value_length
) + 2;
217 memcached_return_t rrc
= memcached_io_read(ptr
, value_ptr
, to_read
, &read_length
);
218 if (memcached_failed(rrc
) and rrc
== MEMCACHED_IN_PROGRESS
)
220 memcached_quit_server(ptr
, true);
221 return memcached_set_error(*ptr
, MEMCACHED_IN_PROGRESS
, MEMCACHED_AT
);
223 else if (memcached_failed(rrc
))
229 if (read_length
!= (ssize_t
)(value_length
+ 2))
234 /* This next bit blows the API, but this is internal....*/
237 char_ptr
= memcached_string_value_mutable(&result
->value
);;
238 char_ptr
[value_length
]= 0;
239 char_ptr
[value_length
+1]= 0;
240 memcached_string_set_length(&result
->value
, value_length
);
243 return MEMCACHED_SUCCESS
;
246 memcached_io_reset(ptr
);
248 return MEMCACHED_PARTIAL_READ
;
251 static memcached_return_t
textual_read_one_response(memcached_server_write_instance_st ptr
,
252 char *buffer
, size_t buffer_length
,
253 memcached_result_st
*result
)
256 memcached_return_t rc
= memcached_io_readline(ptr
, buffer
, buffer_length
, total_read
);
258 if (memcached_failed(rc
))
265 case 'V': /* VALUE || VERSION */
266 if (buffer
[1] == 'A') /* VALUE */
268 /* We add back in one because we will need to search for END */
269 memcached_server_response_increment(ptr
);
270 return textual_value_fetch(ptr
, buffer
, result
);
272 else if (buffer
[1] == 'E') /* VERSION */
274 return MEMCACHED_SUCCESS
;
278 WATCHPOINT_STRING(buffer
);
279 return MEMCACHED_UNKNOWN_READ_FAILURE
;
282 return MEMCACHED_SUCCESS
;
283 case 'S': /* STORED STATS SERVER_ERROR */
285 if (buffer
[2] == 'A') /* STORED STATS */
287 memcached_server_response_increment(ptr
);
288 return MEMCACHED_STAT
;
290 else if (buffer
[1] == 'E') /* SERVER_ERROR */
292 if (total_read
== memcached_literal_param_size("SERVER_ERROR"))
294 return MEMCACHED_SERVER_ERROR
;
297 if (total_read
> memcached_literal_param_size("SERVER_ERROR object too large for cache") and
298 (memcmp(buffer
, memcached_literal_param("SERVER_ERROR object too large for cache")) == 0))
300 return MEMCACHED_E2BIG
;
303 // Move past the basic error message and whitespace
304 char *startptr
= buffer
+ memcached_literal_param_size("SERVER_ERROR");
305 if (startptr
[0] == ' ')
310 char *endptr
= startptr
;
311 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
313 return memcached_set_error(*ptr
, MEMCACHED_SERVER_ERROR
, MEMCACHED_AT
, startptr
, size_t(endptr
- startptr
));
315 else if (buffer
[1] == 'T')
317 return MEMCACHED_STORED
;
321 WATCHPOINT_STRING(buffer
);
322 return MEMCACHED_UNKNOWN_READ_FAILURE
;
325 case 'D': /* DELETED */
326 return MEMCACHED_DELETED
;
328 case 'N': /* NOT_FOUND */
330 if (buffer
[4] == 'F')
331 return MEMCACHED_NOTFOUND
;
332 else if (buffer
[4] == 'S')
333 return MEMCACHED_NOTSTORED
;
336 WATCHPOINT_STRING(buffer
);
337 return MEMCACHED_UNKNOWN_READ_FAILURE
;
340 case 'E': /* PROTOCOL ERROR or END */
342 if (buffer
[1] == 'N')
343 return MEMCACHED_END
;
344 else if (buffer
[1] == 'R')
345 return MEMCACHED_PROTOCOL_ERROR
;
346 else if (buffer
[1] == 'X')
347 return MEMCACHED_DATA_EXISTS
;
350 WATCHPOINT_STRING(buffer
);
351 return MEMCACHED_UNKNOWN_READ_FAILURE
;
355 case 'I': /* CLIENT ERROR */
356 /* We add back in one because we will need to search for END */
357 memcached_server_response_increment(ptr
);
358 return MEMCACHED_ITEM
;
359 case 'C': /* CLIENT ERROR */
360 return MEMCACHED_CLIENT_ERROR
;
363 unsigned long long auto_return_value
;
365 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
366 return MEMCACHED_SUCCESS
;
368 WATCHPOINT_STRING(buffer
);
369 return MEMCACHED_UNKNOWN_READ_FAILURE
;
376 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
377 char *buffer
, size_t buffer_length
,
378 memcached_result_st
*result
)
380 memcached_return_t rc
;
381 protocol_binary_response_header header
;
383 if ((rc
= memcached_safe_read(ptr
, &header
.bytes
, sizeof(header
.bytes
))) != MEMCACHED_SUCCESS
)
385 WATCHPOINT_ERROR(rc
);
389 if (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
391 return MEMCACHED_PROTOCOL_ERROR
;
395 ** Convert the header to host local endian!
397 header
.response
.keylen
= ntohs(header
.response
.keylen
);
398 header
.response
.status
= ntohs(header
.response
.status
);
399 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
400 header
.response
.cas
= memcached_ntohll(header
.response
.cas
);
401 uint32_t bodylen
= header
.response
.bodylen
;
403 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
or
404 header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
406 switch (header
.response
.opcode
)
408 case PROTOCOL_BINARY_CMD_GETKQ
:
410 * We didn't increment the response counter for the GETKQ packet
411 * (only the final NOOP), so we need to increment the counter again.
413 memcached_server_response_increment(ptr
);
415 case PROTOCOL_BINARY_CMD_GETK
:
417 uint16_t keylen
= header
.response
.keylen
;
418 memcached_result_reset(result
);
419 result
->item_cas
= header
.response
.cas
;
421 if ((rc
= memcached_safe_read(ptr
, &result
->item_flags
, sizeof (result
->item_flags
))) != MEMCACHED_SUCCESS
)
423 WATCHPOINT_ERROR(rc
);
424 return MEMCACHED_UNKNOWN_READ_FAILURE
;
427 result
->item_flags
= ntohl(result
->item_flags
);
428 bodylen
-= header
.response
.extlen
;
430 result
->key_length
= keylen
;
431 if (memcached_failed(rc
= memcached_safe_read(ptr
, result
->item_key
, keylen
)))
433 WATCHPOINT_ERROR(rc
);
434 return MEMCACHED_UNKNOWN_READ_FAILURE
;
437 // Only bother with doing this if key_length > 0
438 if (result
->key_length
)
440 if (memcached_array_size(ptr
->root
->_namespace
) and memcached_array_size(ptr
->root
->_namespace
) >= result
->key_length
)
442 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
445 if (memcached_array_size(ptr
->root
->_namespace
))
447 result
->key_length
-= memcached_array_size(ptr
->root
->_namespace
);
448 memmove(result
->item_key
, result
->item_key
+memcached_array_size(ptr
->root
->_namespace
), result
->key_length
);
453 if (memcached_failed(memcached_string_check(&result
->value
, bodylen
)))
455 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
458 char *vptr
= memcached_string_value_mutable(&result
->value
);
459 if (memcached_failed(rc
= memcached_safe_read(ptr
, vptr
, bodylen
)))
461 WATCHPOINT_ERROR(rc
);
462 return MEMCACHED_UNKNOWN_READ_FAILURE
;
465 memcached_string_set_length(&result
->value
, bodylen
);
469 case PROTOCOL_BINARY_CMD_INCREMENT
:
470 case PROTOCOL_BINARY_CMD_DECREMENT
:
472 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
474 return MEMCACHED_PROTOCOL_ERROR
;
477 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
479 if ((rc
= memcached_safe_read(ptr
, &val
, sizeof(val
))) != MEMCACHED_SUCCESS
)
481 WATCHPOINT_ERROR(rc
);
482 return MEMCACHED_UNKNOWN_READ_FAILURE
;
485 val
= memcached_ntohll(val
);
486 memcpy(buffer
, &val
, sizeof(val
));
490 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
491 case PROTOCOL_BINARY_CMD_VERSION
:
493 memset(buffer
, 0, buffer_length
);
494 if (bodylen
>= buffer_length
)
496 /* not enough space in buffer.. should not happen... */
497 return MEMCACHED_UNKNOWN_READ_FAILURE
;
499 else if ((rc
= memcached_safe_read(ptr
, buffer
, bodylen
)) != MEMCACHED_SUCCESS
)
501 WATCHPOINT_ERROR(rc
);
502 return MEMCACHED_UNKNOWN_READ_FAILURE
;
506 case PROTOCOL_BINARY_CMD_FLUSH
:
507 case PROTOCOL_BINARY_CMD_QUIT
:
508 case PROTOCOL_BINARY_CMD_SET
:
509 case PROTOCOL_BINARY_CMD_ADD
:
510 case PROTOCOL_BINARY_CMD_REPLACE
:
511 case PROTOCOL_BINARY_CMD_APPEND
:
512 case PROTOCOL_BINARY_CMD_PREPEND
:
513 case PROTOCOL_BINARY_CMD_DELETE
:
515 WATCHPOINT_ASSERT(bodylen
== 0);
516 return MEMCACHED_SUCCESS
;
518 case PROTOCOL_BINARY_CMD_NOOP
:
520 WATCHPOINT_ASSERT(bodylen
== 0);
521 return MEMCACHED_END
;
523 case PROTOCOL_BINARY_CMD_STAT
:
527 return MEMCACHED_END
;
529 else if (bodylen
+ 1 > buffer_length
)
531 /* not enough space in buffer.. should not happen... */
532 return MEMCACHED_UNKNOWN_READ_FAILURE
;
536 size_t keylen
= header
.response
.keylen
;
537 memset(buffer
, 0, buffer_length
);
538 if ((rc
= memcached_safe_read(ptr
, buffer
, keylen
)) != MEMCACHED_SUCCESS
||
539 (rc
= memcached_safe_read(ptr
, buffer
+ keylen
+ 1, bodylen
- keylen
)) != MEMCACHED_SUCCESS
)
541 WATCHPOINT_ERROR(rc
);
542 return MEMCACHED_UNKNOWN_READ_FAILURE
;
548 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
549 case PROTOCOL_BINARY_CMD_SASL_STEP
:
551 memcached_result_reset(result
);
552 result
->item_cas
= header
.response
.cas
;
554 if (memcached_string_check(&result
->value
,
555 bodylen
) != MEMCACHED_SUCCESS
)
556 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
558 char *vptr
= memcached_string_value_mutable(&result
->value
);
559 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
561 WATCHPOINT_ERROR(rc
);
562 return MEMCACHED_UNKNOWN_READ_FAILURE
;
565 memcached_string_set_length(&result
->value
, bodylen
);
570 /* Command not implemented yet! */
571 WATCHPOINT_ASSERT(0);
572 return MEMCACHED_PROTOCOL_ERROR
;
576 else if (header
.response
.bodylen
)
578 /* What should I do with the error message??? just discard it for now */
579 char hole
[SMALL_STRING_LEN
];
582 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
583 if ((rc
= memcached_safe_read(ptr
, hole
, nr
)) != MEMCACHED_SUCCESS
)
585 WATCHPOINT_ERROR(rc
);
586 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
588 bodylen
-= (uint32_t) nr
;
591 /* This might be an error from one of the quiet commands.. if
592 * so, just throw it away and get the next one. What about creating
593 * a callback to the user with the error information?
595 switch (header
.response
.opcode
)
597 case PROTOCOL_BINARY_CMD_SETQ
:
598 case PROTOCOL_BINARY_CMD_ADDQ
:
599 case PROTOCOL_BINARY_CMD_REPLACEQ
:
600 case PROTOCOL_BINARY_CMD_APPENDQ
:
601 case PROTOCOL_BINARY_CMD_PREPENDQ
:
602 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
609 rc
= MEMCACHED_SUCCESS
;
610 if (header
.response
.status
!= 0)
612 switch (header
.response
.status
)
614 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
615 rc
= MEMCACHED_NOTFOUND
;
618 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
619 rc
= MEMCACHED_DATA_EXISTS
;
622 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
623 rc
= MEMCACHED_NOTSTORED
;
626 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
630 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
631 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
634 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
635 rc
= MEMCACHED_AUTH_CONTINUE
;
638 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
639 rc
= MEMCACHED_AUTH_FAILURE
;
642 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
643 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
645 /* @todo fix the error mappings */
646 rc
= MEMCACHED_PROTOCOL_ERROR
;