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>
40 static memcached_return_t
textual_read_one_response(memcached_server_write_instance_st ptr
,
41 char *buffer
, size_t buffer_length
,
42 memcached_result_st
*result
);
43 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
44 char *buffer
, size_t buffer_length
,
45 memcached_result_st
*result
);
47 memcached_return_t
memcached_read_one_response(memcached_server_write_instance_st ptr
,
48 char *buffer
, size_t buffer_length
,
49 memcached_result_st
*result
)
51 memcached_server_response_decrement(ptr
);
55 memcached_st
*root
= (memcached_st
*)ptr
->root
;
56 result
= &root
->result
;
59 memcached_return_t rc
;
60 if (ptr
->root
->flags
.binary_protocol
)
62 rc
= binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
66 rc
= textual_read_one_response(ptr
, buffer
, buffer_length
, result
);
69 unlikely(rc
== MEMCACHED_UNKNOWN_READ_FAILURE
or
70 rc
== MEMCACHED_PROTOCOL_ERROR
or
71 rc
== MEMCACHED_CLIENT_ERROR
or
72 rc
== MEMCACHED_MEMORY_ALLOCATION_FAILURE
)
73 memcached_io_reset(ptr
);
78 memcached_return_t
memcached_response(memcached_server_write_instance_st ptr
,
79 char *buffer
, size_t buffer_length
,
80 memcached_result_st
*result
)
82 /* We may have old commands in the buffer not set, first purge */
83 if ((ptr
->root
->flags
.no_block
) && (memcached_is_processing_input(ptr
->root
) == false))
85 (void)memcached_io_write(ptr
, NULL
, 0, true);
89 * The previous implementation purged all pending requests and just
90 * returned the last one. Purge all pending messages to ensure backwards
93 if (ptr
->root
->flags
.binary_protocol
== false)
95 while (memcached_server_response_count(ptr
) > 1)
97 memcached_return_t rc
= memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
99 unlikely (rc
!= MEMCACHED_END
&&
100 rc
!= MEMCACHED_STORED
&&
101 rc
!= MEMCACHED_SUCCESS
&&
102 rc
!= MEMCACHED_STAT
&&
103 rc
!= MEMCACHED_DELETED
&&
104 rc
!= MEMCACHED_NOTFOUND
&&
105 rc
!= MEMCACHED_NOTSTORED
&&
106 rc
!= MEMCACHED_DATA_EXISTS
)
111 return memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
114 static memcached_return_t
textual_value_fetch(memcached_server_write_instance_st ptr
,
116 memcached_result_st
*result
)
123 ssize_t read_length
= 0;
125 if (ptr
->root
->flags
.use_udp
)
126 return memcached_set_error(*ptr
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
128 WATCHPOINT_ASSERT(ptr
->root
);
129 end_ptr
= buffer
+ MEMCACHED_DEFAULT_COMMAND_SIZE
;
131 memcached_result_reset(result
);
134 string_ptr
+= 6; /* "VALUE " */
137 /* We load the key */
140 size_t prefix_length
;
142 key
= result
->item_key
;
143 result
->key_length
= 0;
145 for (prefix_length
= memcached_array_size(ptr
->root
->_namespace
); !(iscntrl(*string_ptr
) || isspace(*string_ptr
)) ; string_ptr
++)
147 if (prefix_length
== 0)
151 result
->key_length
++;
156 result
->item_key
[result
->key_length
]= 0;
159 if (end_ptr
== string_ptr
)
162 /* Flags fetch move past space */
164 if (end_ptr
== string_ptr
)
167 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
168 result
->item_flags
= (uint32_t) strtoul(next_ptr
, &string_ptr
, 10);
170 if (end_ptr
== string_ptr
)
173 /* Length fetch move past space*/
175 if (end_ptr
== string_ptr
)
178 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
179 value_length
= (size_t)strtoull(next_ptr
, &string_ptr
, 10);
181 if (end_ptr
== string_ptr
)
185 if (*string_ptr
== '\r')
187 /* Skip past the \r\n */
193 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
194 result
->item_cas
= strtoull(next_ptr
, &string_ptr
, 10);
197 if (end_ptr
< string_ptr
)
200 /* We add two bytes so that we can walk the \r\n */
201 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
)
255 memcached_return_t rc
= memcached_io_readline(ptr
, buffer
, buffer_length
);
256 if (memcached_failed(rc
))
263 case 'V': /* VALUE || VERSION */
264 if (buffer
[1] == 'A') /* VALUE */
266 /* We add back in one because we will need to search for END */
267 memcached_server_response_increment(ptr
);
268 return textual_value_fetch(ptr
, buffer
, result
);
270 else if (buffer
[1] == 'E') /* VERSION */
272 return MEMCACHED_SUCCESS
;
276 WATCHPOINT_STRING(buffer
);
277 return MEMCACHED_UNKNOWN_READ_FAILURE
;
280 return MEMCACHED_SUCCESS
;
281 case 'S': /* STORED STATS SERVER_ERROR */
283 if (buffer
[2] == 'A') /* STORED STATS */
285 memcached_server_response_increment(ptr
);
286 return MEMCACHED_STAT
;
288 else if (buffer
[1] == 'E') /* SERVER_ERROR */
290 char *startptr
= buffer
+ 13, *endptr
= startptr
;
292 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
294 return memcached_set_error(*ptr
, MEMCACHED_SERVER_ERROR
, MEMCACHED_AT
, startptr
, size_t(endptr
- startptr
));
296 else if (buffer
[1] == 'T')
298 return MEMCACHED_STORED
;
302 WATCHPOINT_STRING(buffer
);
303 return MEMCACHED_UNKNOWN_READ_FAILURE
;
306 case 'D': /* DELETED */
307 return MEMCACHED_DELETED
;
309 case 'N': /* NOT_FOUND */
311 if (buffer
[4] == 'F')
312 return MEMCACHED_NOTFOUND
;
313 else if (buffer
[4] == 'S')
314 return MEMCACHED_NOTSTORED
;
317 WATCHPOINT_STRING(buffer
);
318 return MEMCACHED_UNKNOWN_READ_FAILURE
;
321 case 'E': /* PROTOCOL ERROR or END */
323 if (buffer
[1] == 'N')
324 return MEMCACHED_END
;
325 else if (buffer
[1] == 'R')
326 return MEMCACHED_PROTOCOL_ERROR
;
327 else if (buffer
[1] == 'X')
328 return MEMCACHED_DATA_EXISTS
;
331 WATCHPOINT_STRING(buffer
);
332 return MEMCACHED_UNKNOWN_READ_FAILURE
;
336 case 'I': /* CLIENT ERROR */
337 /* We add back in one because we will need to search for END */
338 memcached_server_response_increment(ptr
);
339 return MEMCACHED_ITEM
;
340 case 'C': /* CLIENT ERROR */
341 return MEMCACHED_CLIENT_ERROR
;
344 unsigned long long auto_return_value
;
346 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
347 return MEMCACHED_SUCCESS
;
349 WATCHPOINT_STRING(buffer
);
350 return MEMCACHED_UNKNOWN_READ_FAILURE
;
357 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
358 char *buffer
, size_t buffer_length
,
359 memcached_result_st
*result
)
361 memcached_return_t rc
;
362 protocol_binary_response_header header
;
364 if ((rc
= memcached_safe_read(ptr
, &header
.bytes
, sizeof(header
.bytes
))) != MEMCACHED_SUCCESS
)
366 WATCHPOINT_ERROR(rc
);
370 if (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
372 return MEMCACHED_PROTOCOL_ERROR
;
376 ** Convert the header to host local endian!
378 header
.response
.keylen
= ntohs(header
.response
.keylen
);
379 header
.response
.status
= ntohs(header
.response
.status
);
380 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
381 header
.response
.cas
= memcached_ntohll(header
.response
.cas
);
382 uint32_t bodylen
= header
.response
.bodylen
;
384 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
||
385 header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
387 switch (header
.response
.opcode
)
389 case PROTOCOL_BINARY_CMD_GETKQ
:
391 * We didn't increment the response counter for the GETKQ packet
392 * (only the final NOOP), so we need to increment the counter again.
394 memcached_server_response_increment(ptr
);
396 case PROTOCOL_BINARY_CMD_GETK
:
398 uint16_t keylen
= header
.response
.keylen
;
399 memcached_result_reset(result
);
400 result
->item_cas
= header
.response
.cas
;
402 if ((rc
= memcached_safe_read(ptr
, &result
->item_flags
, sizeof (result
->item_flags
))) != MEMCACHED_SUCCESS
)
404 WATCHPOINT_ERROR(rc
);
405 return MEMCACHED_UNKNOWN_READ_FAILURE
;
408 result
->item_flags
= ntohl(result
->item_flags
);
409 bodylen
-= header
.response
.extlen
;
411 result
->key_length
= keylen
;
412 if (memcached_failed(rc
= memcached_safe_read(ptr
, result
->item_key
, keylen
)))
414 WATCHPOINT_ERROR(rc
);
415 return MEMCACHED_UNKNOWN_READ_FAILURE
;
418 // Only bother with doing this if key_length > 0
419 if (result
->key_length
)
421 if (memcached_array_size(ptr
->root
->_namespace
) and memcached_array_size(ptr
->root
->_namespace
) >= result
->key_length
)
423 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
426 if (memcached_array_size(ptr
->root
->_namespace
))
428 result
->key_length
-= memcached_array_size(ptr
->root
->_namespace
);
429 memmove(result
->item_key
, result
->item_key
+memcached_array_size(ptr
->root
->_namespace
), result
->key_length
);
434 if (memcached_failed(memcached_string_check(&result
->value
, bodylen
)))
436 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
439 char *vptr
= memcached_string_value_mutable(&result
->value
);
440 if (memcached_failed(rc
= memcached_safe_read(ptr
, vptr
, bodylen
)))
442 WATCHPOINT_ERROR(rc
);
443 return MEMCACHED_UNKNOWN_READ_FAILURE
;
446 memcached_string_set_length(&result
->value
, bodylen
);
450 case PROTOCOL_BINARY_CMD_INCREMENT
:
451 case PROTOCOL_BINARY_CMD_DECREMENT
:
453 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
455 return MEMCACHED_PROTOCOL_ERROR
;
458 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
460 if ((rc
= memcached_safe_read(ptr
, &val
, sizeof(val
))) != MEMCACHED_SUCCESS
)
462 WATCHPOINT_ERROR(rc
);
463 return MEMCACHED_UNKNOWN_READ_FAILURE
;
466 val
= memcached_ntohll(val
);
467 memcpy(buffer
, &val
, sizeof(val
));
471 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
472 case PROTOCOL_BINARY_CMD_VERSION
:
474 memset(buffer
, 0, buffer_length
);
475 if (bodylen
>= buffer_length
)
477 /* not enough space in buffer.. should not happen... */
478 return MEMCACHED_UNKNOWN_READ_FAILURE
;
480 else if ((rc
= memcached_safe_read(ptr
, buffer
, bodylen
)) != MEMCACHED_SUCCESS
)
482 WATCHPOINT_ERROR(rc
);
483 return MEMCACHED_UNKNOWN_READ_FAILURE
;
487 case PROTOCOL_BINARY_CMD_FLUSH
:
488 case PROTOCOL_BINARY_CMD_QUIT
:
489 case PROTOCOL_BINARY_CMD_SET
:
490 case PROTOCOL_BINARY_CMD_ADD
:
491 case PROTOCOL_BINARY_CMD_REPLACE
:
492 case PROTOCOL_BINARY_CMD_APPEND
:
493 case PROTOCOL_BINARY_CMD_PREPEND
:
494 case PROTOCOL_BINARY_CMD_DELETE
:
496 WATCHPOINT_ASSERT(bodylen
== 0);
497 return MEMCACHED_SUCCESS
;
499 case PROTOCOL_BINARY_CMD_NOOP
:
501 WATCHPOINT_ASSERT(bodylen
== 0);
502 return MEMCACHED_END
;
504 case PROTOCOL_BINARY_CMD_STAT
:
508 return MEMCACHED_END
;
510 else if (bodylen
+ 1 > buffer_length
)
512 /* not enough space in buffer.. should not happen... */
513 return MEMCACHED_UNKNOWN_READ_FAILURE
;
517 size_t keylen
= header
.response
.keylen
;
518 memset(buffer
, 0, buffer_length
);
519 if ((rc
= memcached_safe_read(ptr
, buffer
, keylen
)) != MEMCACHED_SUCCESS
||
520 (rc
= memcached_safe_read(ptr
, buffer
+ keylen
+ 1, bodylen
- keylen
)) != MEMCACHED_SUCCESS
)
522 WATCHPOINT_ERROR(rc
);
523 return MEMCACHED_UNKNOWN_READ_FAILURE
;
529 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
530 case PROTOCOL_BINARY_CMD_SASL_STEP
:
532 memcached_result_reset(result
);
533 result
->item_cas
= header
.response
.cas
;
535 if (memcached_string_check(&result
->value
,
536 bodylen
) != MEMCACHED_SUCCESS
)
537 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
539 char *vptr
= memcached_string_value_mutable(&result
->value
);
540 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
542 WATCHPOINT_ERROR(rc
);
543 return MEMCACHED_UNKNOWN_READ_FAILURE
;
546 memcached_string_set_length(&result
->value
, bodylen
);
551 /* Command not implemented yet! */
552 WATCHPOINT_ASSERT(0);
553 return MEMCACHED_PROTOCOL_ERROR
;
557 else if (header
.response
.bodylen
)
559 /* What should I do with the error message??? just discard it for now */
560 char hole
[SMALL_STRING_LEN
];
563 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
564 if ((rc
= memcached_safe_read(ptr
, hole
, nr
)) != MEMCACHED_SUCCESS
)
566 WATCHPOINT_ERROR(rc
);
567 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
569 bodylen
-= (uint32_t) nr
;
572 /* This might be an error from one of the quiet commands.. if
573 * so, just throw it away and get the next one. What about creating
574 * a callback to the user with the error information?
576 switch (header
.response
.opcode
)
578 case PROTOCOL_BINARY_CMD_SETQ
:
579 case PROTOCOL_BINARY_CMD_ADDQ
:
580 case PROTOCOL_BINARY_CMD_REPLACEQ
:
581 case PROTOCOL_BINARY_CMD_APPENDQ
:
582 case PROTOCOL_BINARY_CMD_PREPENDQ
:
583 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
589 rc
= MEMCACHED_SUCCESS
;
590 unlikely(header
.response
.status
!= 0)
591 switch (header
.response
.status
)
593 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
594 rc
= MEMCACHED_NOTFOUND
;
596 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
597 rc
= MEMCACHED_DATA_EXISTS
;
599 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
600 rc
= MEMCACHED_NOTSTORED
;
602 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
605 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
606 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
608 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
609 rc
= MEMCACHED_AUTH_CONTINUE
;
611 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
612 rc
= MEMCACHED_AUTH_FAILURE
;
614 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
615 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
617 /* @todo fix the error mappings */
618 rc
= MEMCACHED_PROTOCOL_ERROR
;