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_server_write_instance_st ptr
,
43 memcached_result_st
*result
)
46 ssize_t read_length
= 0;
49 if (ptr
->root
->flags
.use_udp
)
51 return memcached_set_error(*ptr
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
54 WATCHPOINT_ASSERT(ptr
->root
);
55 char *end_ptr
= buffer
+ MEMCACHED_DEFAULT_COMMAND_SIZE
;
57 memcached_result_reset(result
);
59 char *string_ptr
= buffer
;
60 string_ptr
+= 6; /* "VALUE " */
68 key
= result
->item_key
;
69 result
->key_length
= 0;
71 for (prefix_length
= memcached_array_size(ptr
->root
->_namespace
); !(iscntrl(*string_ptr
) || isspace(*string_ptr
)) ; string_ptr
++)
73 if (prefix_length
== 0)
82 result
->item_key
[result
->key_length
]= 0;
85 if (end_ptr
== string_ptr
)
90 /* Flags fetch move past space */
92 if (end_ptr
== string_ptr
)
97 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
98 result
->item_flags
= (uint32_t) strtoul(next_ptr
, &string_ptr
, 10);
100 if (end_ptr
== string_ptr
)
105 /* Length fetch move past space*/
107 if (end_ptr
== string_ptr
)
112 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
113 value_length
= (size_t)strtoull(next_ptr
, &string_ptr
, 10);
115 if (end_ptr
== string_ptr
)
121 if (*string_ptr
== '\r')
123 /* Skip past the \r\n */
129 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
130 result
->item_cas
= strtoull(next_ptr
, &string_ptr
, 10);
133 if (end_ptr
< string_ptr
)
138 /* We add two bytes so that we can walk the \r\n */
139 if (memcached_failed(memcached_string_check(&result
->value
, value_length
+2)))
141 return memcached_set_error(*ptr
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
, MEMCACHED_AT
);
145 char *value_ptr
= memcached_string_value_mutable(&result
->value
);
147 We read the \r\n into the string since not doing so is more
148 cycles then the waster of memory to do so.
150 We are null terminating through, which will most likely make
151 some people lazy about using the return length.
153 size_t to_read
= (value_length
) + 2;
154 memcached_return_t rrc
= memcached_io_read(ptr
, value_ptr
, to_read
, &read_length
);
155 if (memcached_failed(rrc
) and rrc
== MEMCACHED_IN_PROGRESS
)
157 memcached_quit_server(ptr
, true);
158 return memcached_set_error(*ptr
, MEMCACHED_IN_PROGRESS
, MEMCACHED_AT
);
160 else if (memcached_failed(rrc
))
166 if (read_length
!= (ssize_t
)(value_length
+ 2))
171 /* This next bit blows the API, but this is internal....*/
174 char_ptr
= memcached_string_value_mutable(&result
->value
);;
175 char_ptr
[value_length
]= 0;
176 char_ptr
[value_length
+1]= 0;
177 memcached_string_set_length(&result
->value
, value_length
);
180 return MEMCACHED_SUCCESS
;
183 memcached_io_reset(ptr
);
185 return MEMCACHED_PARTIAL_READ
;
188 static memcached_return_t
textual_read_one_response(memcached_server_write_instance_st ptr
,
189 char *buffer
, size_t buffer_length
,
190 memcached_result_st
*result
)
193 memcached_return_t rc
= memcached_io_readline(ptr
, buffer
, buffer_length
, total_read
);
195 if (memcached_failed(rc
))
202 case 'V': /* VALUE || VERSION */
203 if (buffer
[1] == 'A' and buffer
[2] == 'L' and buffer
[3] == 'U' and buffer
[4] == 'E') /* VALUE */
205 /* We add back in one because we will need to search for END */
206 memcached_server_response_increment(ptr
);
207 return textual_value_fetch(ptr
, buffer
, result
);
209 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 */
211 return MEMCACHED_SUCCESS
;
216 if (buffer
[1] == 'K')
218 return MEMCACHED_SUCCESS
;
222 case 'S': /* STORED STATS SERVER_ERROR */
224 if (buffer
[1] == 'T' and buffer
[2] == 'A' and buffer
[3] == 'T') /* STORED STATS */
226 memcached_server_response_increment(ptr
);
227 return MEMCACHED_STAT
;
229 else if (buffer
[1] == 'E' and buffer
[2] == 'R' and buffer
[3] == 'V' and buffer
[4] == 'E' and buffer
[5] == 'R'
231 and buffer
[7] == 'E' and buffer
[8] == 'R' and buffer
[9] == 'R' and buffer
[10] == 'O' and buffer
[11] == 'R' ) /* SERVER_ERROR */
233 if (total_read
== memcached_literal_param_size("SERVER_ERROR"))
235 return MEMCACHED_SERVER_ERROR
;
238 if (total_read
> memcached_literal_param_size("SERVER_ERROR object too large for cache") and
239 (memcmp(buffer
, memcached_literal_param("SERVER_ERROR object too large for cache")) == 0))
241 return MEMCACHED_E2BIG
;
244 // Move past the basic error message and whitespace
245 char *startptr
= buffer
+ memcached_literal_param_size("SERVER_ERROR");
246 if (startptr
[0] == ' ')
251 char *endptr
= startptr
;
252 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
254 return memcached_set_error(*ptr
, MEMCACHED_SERVER_ERROR
, MEMCACHED_AT
, startptr
, size_t(endptr
- startptr
));
256 else if (buffer
[1] == 'T' and buffer
[2] == 'O' and buffer
[3] == 'R' and buffer
[4] == 'E' and buffer
[5] == 'D')
258 return MEMCACHED_STORED
;
263 case 'D': /* DELETED */
264 if (buffer
[1] == 'E' and buffer
[2] == 'L' and buffer
[3] == 'E' and buffer
[4] == 'T' and buffer
[5] == 'E' and buffer
[6] == 'D')
266 return MEMCACHED_DELETED
;
270 case 'N': /* NOT_FOUND */
272 if (buffer
[1] == 'O' and buffer
[2] == 'T'
274 and buffer
[4] == 'F' and buffer
[5] == 'O' and buffer
[6] == 'U' and buffer
[7] == 'N' and buffer
[8] == 'D')
276 return MEMCACHED_NOTFOUND
;
278 else if (buffer
[1] == 'O' and buffer
[2] == 'T'
280 and buffer
[4] == 'S' and buffer
[5] == 'T' and buffer
[6] == 'O' and buffer
[7] == 'R' and buffer
[8] == 'E' and buffer
[9] == 'D')
282 return MEMCACHED_NOTSTORED
;
287 case 'E': /* PROTOCOL ERROR or END */
289 if (buffer
[1] == 'N' and buffer
[2] == 'D')
291 return MEMCACHED_END
;
293 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'
295 and buffer
[9] == 'E' and buffer
[10] == 'R' and buffer
[11] == 'R' and buffer
[12] == 'O' and buffer
[13] == 'R')
297 return MEMCACHED_PROTOCOL_ERROR
;
299 else if (buffer
[1] == 'X' and buffer
[2] == 'I' and buffer
[3] == 'S' and buffer
[4] == 'T' and buffer
[5] == 'S')
301 return MEMCACHED_DATA_EXISTS
;
306 case 'T': /* TOUCHED */
308 if (buffer
[1] == 'O' and buffer
[2] == 'U' and buffer
[3] == 'C' and buffer
[4] == 'H' and buffer
[5] == 'E' and buffer
[6] == 'D')
310 return MEMCACHED_SUCCESS
;
316 if (buffer
[1] == 'T' and buffer
[2] == 'E' and buffer
[3] == 'M')
318 /* We add back in one because we will need to search for END */
319 memcached_server_response_increment(ptr
);
320 return MEMCACHED_ITEM
;
324 case 'C': /* CLIENT ERROR */
325 if (buffer
[1] == 'L' and buffer
[2] == 'I' and buffer
[3] == 'E' and buffer
[4] == 'N' and buffer
[5] == 'T')
327 return MEMCACHED_CLIENT_ERROR
;
331 case '0': /* INCR/DECR response */
332 case '1': /* INCR/DECR response */
333 case '2': /* INCR/DECR response */
334 case '3': /* INCR/DECR response */
335 case '4': /* INCR/DECR response */
336 case '5': /* INCR/DECR response */
337 case '6': /* INCR/DECR response */
338 case '7': /* INCR/DECR response */
339 case '8': /* INCR/DECR response */
340 case '9': /* INCR/DECR response */
342 unsigned long long int auto_return_value
= strtoull(buffer
, (char **)NULL
, 10);
344 if (auto_return_value
== ULLONG_MAX
and errno
== ERANGE
)
346 return MEMCACHED_UNKNOWN_READ_FAILURE
;
348 else if (errno
== EINVAL
)
350 return MEMCACHED_UNKNOWN_READ_FAILURE
;
353 WATCHPOINT_STRING(buffer
);
354 return MEMCACHED_SUCCESS
;
361 return MEMCACHED_UNKNOWN_READ_FAILURE
;
364 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
365 char *buffer
, size_t buffer_length
,
366 memcached_result_st
*result
)
368 memcached_return_t rc
;
369 protocol_binary_response_header header
;
371 if ((rc
= memcached_safe_read(ptr
, &header
.bytes
, sizeof(header
.bytes
))) != MEMCACHED_SUCCESS
)
373 WATCHPOINT_ERROR(rc
);
377 if (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
379 return MEMCACHED_PROTOCOL_ERROR
;
383 ** Convert the header to host local endian!
385 header
.response
.keylen
= ntohs(header
.response
.keylen
);
386 header
.response
.status
= ntohs(header
.response
.status
);
387 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
388 header
.response
.cas
= memcached_ntohll(header
.response
.cas
);
389 uint32_t bodylen
= header
.response
.bodylen
;
391 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
or
392 header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
394 switch (header
.response
.opcode
)
396 case PROTOCOL_BINARY_CMD_GETKQ
:
398 * We didn't increment the response counter for the GETKQ packet
399 * (only the final NOOP), so we need to increment the counter again.
401 memcached_server_response_increment(ptr
);
403 case PROTOCOL_BINARY_CMD_GETK
:
405 uint16_t keylen
= header
.response
.keylen
;
406 memcached_result_reset(result
);
407 result
->item_cas
= header
.response
.cas
;
409 if ((rc
= memcached_safe_read(ptr
, &result
->item_flags
, sizeof (result
->item_flags
))) != MEMCACHED_SUCCESS
)
411 WATCHPOINT_ERROR(rc
);
412 return MEMCACHED_UNKNOWN_READ_FAILURE
;
415 result
->item_flags
= ntohl(result
->item_flags
);
416 bodylen
-= header
.response
.extlen
;
418 result
->key_length
= keylen
;
419 if (memcached_failed(rc
= memcached_safe_read(ptr
, result
->item_key
, keylen
)))
421 WATCHPOINT_ERROR(rc
);
422 return MEMCACHED_UNKNOWN_READ_FAILURE
;
425 // Only bother with doing this if key_length > 0
426 if (result
->key_length
)
428 if (memcached_array_size(ptr
->root
->_namespace
) and memcached_array_size(ptr
->root
->_namespace
) >= result
->key_length
)
430 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
433 if (memcached_array_size(ptr
->root
->_namespace
))
435 result
->key_length
-= memcached_array_size(ptr
->root
->_namespace
);
436 memmove(result
->item_key
, result
->item_key
+memcached_array_size(ptr
->root
->_namespace
), result
->key_length
);
441 if (memcached_failed(memcached_string_check(&result
->value
, bodylen
)))
443 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
446 char *vptr
= memcached_string_value_mutable(&result
->value
);
447 if (memcached_failed(rc
= memcached_safe_read(ptr
, vptr
, bodylen
)))
449 WATCHPOINT_ERROR(rc
);
450 return MEMCACHED_UNKNOWN_READ_FAILURE
;
453 memcached_string_set_length(&result
->value
, bodylen
);
457 case PROTOCOL_BINARY_CMD_INCREMENT
:
458 case PROTOCOL_BINARY_CMD_DECREMENT
:
460 if (bodylen
!= sizeof(uint64_t) or buffer_length
!= sizeof(uint64_t))
462 return MEMCACHED_PROTOCOL_ERROR
;
465 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
467 if ((rc
= memcached_safe_read(ptr
, &val
, sizeof(val
))) != MEMCACHED_SUCCESS
)
469 WATCHPOINT_ERROR(rc
);
470 return MEMCACHED_UNKNOWN_READ_FAILURE
;
473 val
= memcached_ntohll(val
);
474 memcpy(buffer
, &val
, sizeof(val
));
478 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
479 case PROTOCOL_BINARY_CMD_VERSION
:
481 memset(buffer
, 0, buffer_length
);
482 if (bodylen
>= buffer_length
)
484 /* not enough space in buffer.. should not happen... */
485 return MEMCACHED_UNKNOWN_READ_FAILURE
;
487 else if ((rc
= memcached_safe_read(ptr
, buffer
, bodylen
)) != MEMCACHED_SUCCESS
)
489 WATCHPOINT_ERROR(rc
);
490 return MEMCACHED_UNKNOWN_READ_FAILURE
;
494 case PROTOCOL_BINARY_CMD_FLUSH
:
495 case PROTOCOL_BINARY_CMD_QUIT
:
496 case PROTOCOL_BINARY_CMD_SET
:
497 case PROTOCOL_BINARY_CMD_ADD
:
498 case PROTOCOL_BINARY_CMD_REPLACE
:
499 case PROTOCOL_BINARY_CMD_APPEND
:
500 case PROTOCOL_BINARY_CMD_PREPEND
:
501 case PROTOCOL_BINARY_CMD_DELETE
:
502 case PROTOCOL_BINARY_CMD_TOUCH
:
504 WATCHPOINT_ASSERT(bodylen
== 0);
505 return MEMCACHED_SUCCESS
;
508 case PROTOCOL_BINARY_CMD_NOOP
:
510 WATCHPOINT_ASSERT(bodylen
== 0);
511 return MEMCACHED_END
;
514 case PROTOCOL_BINARY_CMD_STAT
:
518 return MEMCACHED_END
;
520 else if (bodylen
+ 1 > buffer_length
)
522 /* not enough space in buffer.. should not happen... */
523 return MEMCACHED_UNKNOWN_READ_FAILURE
;
527 size_t keylen
= header
.response
.keylen
;
528 memset(buffer
, 0, buffer_length
);
529 if ((rc
= memcached_safe_read(ptr
, buffer
, keylen
)) != MEMCACHED_SUCCESS
||
530 (rc
= memcached_safe_read(ptr
, buffer
+ keylen
+ 1, bodylen
- keylen
)) != MEMCACHED_SUCCESS
)
532 WATCHPOINT_ERROR(rc
);
533 return MEMCACHED_UNKNOWN_READ_FAILURE
;
539 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
540 case PROTOCOL_BINARY_CMD_SASL_STEP
:
542 memcached_result_reset(result
);
543 result
->item_cas
= header
.response
.cas
;
545 if (memcached_string_check(&result
->value
,
546 bodylen
) != MEMCACHED_SUCCESS
)
547 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
549 char *vptr
= memcached_string_value_mutable(&result
->value
);
550 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
552 WATCHPOINT_ERROR(rc
);
553 return MEMCACHED_UNKNOWN_READ_FAILURE
;
556 memcached_string_set_length(&result
->value
, bodylen
);
561 /* Command not implemented yet! */
562 WATCHPOINT_ASSERT(0);
563 return MEMCACHED_PROTOCOL_ERROR
;
567 else if (header
.response
.bodylen
)
569 /* What should I do with the error message??? just discard it for now */
570 char hole
[SMALL_STRING_LEN
];
573 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
574 if ((rc
= memcached_safe_read(ptr
, hole
, nr
)) != MEMCACHED_SUCCESS
)
576 WATCHPOINT_ERROR(rc
);
577 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
579 bodylen
-= (uint32_t) nr
;
582 /* This might be an error from one of the quiet commands.. if
583 * so, just throw it away and get the next one. What about creating
584 * a callback to the user with the error information?
586 switch (header
.response
.opcode
)
588 case PROTOCOL_BINARY_CMD_SETQ
:
589 case PROTOCOL_BINARY_CMD_ADDQ
:
590 case PROTOCOL_BINARY_CMD_REPLACEQ
:
591 case PROTOCOL_BINARY_CMD_APPENDQ
:
592 case PROTOCOL_BINARY_CMD_PREPENDQ
:
593 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
600 rc
= MEMCACHED_SUCCESS
;
601 if (header
.response
.status
!= 0)
603 switch (header
.response
.status
)
605 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
606 rc
= MEMCACHED_NOTFOUND
;
609 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
610 rc
= MEMCACHED_DATA_EXISTS
;
613 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
614 rc
= MEMCACHED_NOTSTORED
;
617 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
621 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
622 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
625 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
626 rc
= MEMCACHED_AUTH_CONTINUE
;
629 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
630 rc
= MEMCACHED_AUTH_FAILURE
;
633 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
634 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
636 /* @todo fix the error mappings */
637 rc
= MEMCACHED_PROTOCOL_ERROR
;
645 memcached_return_t
memcached_read_one_response(memcached_server_write_instance_st ptr
,
646 char *buffer
, size_t buffer_length
,
647 memcached_result_st
*result
)
649 memcached_server_response_decrement(ptr
);
653 memcached_st
*root
= (memcached_st
*)ptr
->root
;
654 result
= &root
->result
;
657 memcached_return_t rc
;
658 if (ptr
->root
->flags
.binary_protocol
)
660 rc
= binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
664 rc
= textual_read_one_response(ptr
, buffer
, buffer_length
, result
);
667 if (rc
== MEMCACHED_UNKNOWN_READ_FAILURE
or
668 rc
== MEMCACHED_READ_FAILURE
or
669 rc
== MEMCACHED_PROTOCOL_ERROR
or
670 rc
== MEMCACHED_CLIENT_ERROR
or
671 rc
== MEMCACHED_MEMORY_ALLOCATION_FAILURE
)
673 memcached_io_reset(ptr
);
679 memcached_return_t
memcached_response(memcached_server_write_instance_st ptr
,
680 char *buffer
, size_t buffer_length
,
681 memcached_result_st
*result
)
683 /* We may have old commands in the buffer not set, first purge */
684 if ((ptr
->root
->flags
.no_block
) && (memcached_is_processing_input(ptr
->root
) == false))
686 (void)memcached_io_write(ptr
, NULL
, 0, true);
690 * The previous implementation purged all pending requests and just
691 * returned the last one. Purge all pending messages to ensure backwards
694 if (ptr
->root
->flags
.binary_protocol
== false)
696 while (memcached_server_response_count(ptr
) > 1)
698 memcached_return_t rc
= memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
700 if (rc
!= MEMCACHED_END
&&
701 rc
!= MEMCACHED_STORED
&&
702 rc
!= MEMCACHED_SUCCESS
&&
703 rc
!= MEMCACHED_STAT
&&
704 rc
!= MEMCACHED_DELETED
&&
705 rc
!= MEMCACHED_NOTFOUND
&&
706 rc
!= MEMCACHED_NOTSTORED
&&
707 rc
!= MEMCACHED_DATA_EXISTS
)
714 return memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);