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
)
61 rc
= binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
63 rc
= textual_read_one_response(ptr
, buffer
, buffer_length
, result
);
65 unlikely(rc
== MEMCACHED_UNKNOWN_READ_FAILURE
||
66 rc
== MEMCACHED_PROTOCOL_ERROR
||
67 rc
== MEMCACHED_CLIENT_ERROR
||
68 rc
== MEMCACHED_MEMORY_ALLOCATION_FAILURE
)
69 memcached_io_reset(ptr
);
74 memcached_return_t
memcached_response(memcached_server_write_instance_st ptr
,
75 char *buffer
, size_t buffer_length
,
76 memcached_result_st
*result
)
78 /* We may have old commands in the buffer not set, first purge */
79 if ((ptr
->root
->flags
.no_block
) && (memcached_is_processing_input(ptr
->root
) == false))
81 (void)memcached_io_write(ptr
, NULL
, 0, true);
85 * The previous implementation purged all pending requests and just
86 * returned the last one. Purge all pending messages to ensure backwards
89 if (ptr
->root
->flags
.binary_protocol
== false)
91 while (memcached_server_response_count(ptr
) > 1)
93 memcached_return_t rc
= memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
95 unlikely (rc
!= MEMCACHED_END
&&
96 rc
!= MEMCACHED_STORED
&&
97 rc
!= MEMCACHED_SUCCESS
&&
98 rc
!= MEMCACHED_STAT
&&
99 rc
!= MEMCACHED_DELETED
&&
100 rc
!= MEMCACHED_NOTFOUND
&&
101 rc
!= MEMCACHED_NOTSTORED
&&
102 rc
!= MEMCACHED_DATA_EXISTS
)
107 return memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
110 static memcached_return_t
textual_value_fetch(memcached_server_write_instance_st ptr
,
112 memcached_result_st
*result
)
114 memcached_return_t rc
= MEMCACHED_SUCCESS
;
121 ssize_t read_length
= 0;
122 memcached_return_t rrc
;
124 if (ptr
->root
->flags
.use_udp
)
125 return memcached_set_error((memcached_st
*)ptr
->root
, MEMCACHED_NOT_SUPPORTED
);
127 WATCHPOINT_ASSERT(ptr
->root
);
128 end_ptr
= buffer
+ MEMCACHED_DEFAULT_COMMAND_SIZE
;
130 memcached_result_reset(result
);
133 string_ptr
+= 6; /* "VALUE " */
136 /* We load the key */
139 size_t prefix_length
;
141 key
= result
->item_key
;
142 result
->key_length
= 0;
144 for (prefix_length
= memcached_array_size(ptr
->root
->prefix_key
); !(iscntrl(*string_ptr
) || isspace(*string_ptr
)) ; string_ptr
++)
146 if (prefix_length
== 0)
150 result
->key_length
++;
155 result
->item_key
[result
->key_length
]= 0;
158 if (end_ptr
== string_ptr
)
161 /* Flags fetch move past space */
163 if (end_ptr
== string_ptr
)
166 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
167 result
->item_flags
= (uint32_t) strtoul(next_ptr
, &string_ptr
, 10);
169 if (end_ptr
== string_ptr
)
172 /* Length fetch move past space*/
174 if (end_ptr
== string_ptr
)
177 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
178 value_length
= (size_t)strtoull(next_ptr
, &string_ptr
, 10);
180 if (end_ptr
== string_ptr
)
184 if (*string_ptr
== '\r')
186 /* Skip past the \r\n */
192 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
193 result
->item_cas
= strtoull(next_ptr
, &string_ptr
, 10);
196 if (end_ptr
< string_ptr
)
199 /* We add two bytes so that we can walk the \r\n */
200 rc
= memcached_string_check(&result
->value
, value_length
+2);
201 if (rc
!= MEMCACHED_SUCCESS
)
204 return memcached_set_error((memcached_st
*)ptr
->root
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
);
207 value_ptr
= memcached_string_value_mutable(&result
->value
);
209 We read the \r\n into the string since not doing so is more
210 cycles then the waster of memory to do so.
212 We are null terminating through, which will most likely make
213 some people lazy about using the return length.
215 to_read
= (value_length
) + 2;
216 rrc
= memcached_io_read(ptr
, value_ptr
, to_read
, &read_length
);
217 if (rrc
!= MEMCACHED_SUCCESS
)
220 if (read_length
!= (ssize_t
)(value_length
+ 2))
225 /* This next bit blows the API, but this is internal....*/
228 char_ptr
= memcached_string_value_mutable(&result
->value
);;
229 char_ptr
[value_length
]= 0;
230 char_ptr
[value_length
+ 1]= 0;
231 memcached_string_set_length(&result
->value
, value_length
);
234 return MEMCACHED_SUCCESS
;
237 memcached_io_reset(ptr
);
239 return MEMCACHED_PARTIAL_READ
;
242 static memcached_return_t
textual_read_one_response(memcached_server_write_instance_st ptr
,
243 char *buffer
, size_t buffer_length
,
244 memcached_result_st
*result
)
246 memcached_return_t rc
= memcached_io_readline(ptr
, buffer
, buffer_length
);
247 if (rc
!= MEMCACHED_SUCCESS
)
252 case 'V': /* VALUE || VERSION */
253 if (buffer
[1] == 'A') /* VALUE */
255 /* We add back in one because we will need to search for END */
256 memcached_server_response_increment(ptr
);
257 return textual_value_fetch(ptr
, buffer
, result
);
259 else if (buffer
[1] == 'E') /* VERSION */
261 return MEMCACHED_SUCCESS
;
265 WATCHPOINT_STRING(buffer
);
266 return MEMCACHED_UNKNOWN_READ_FAILURE
;
269 return MEMCACHED_SUCCESS
;
270 case 'S': /* STORED STATS SERVER_ERROR */
272 if (buffer
[2] == 'A') /* STORED STATS */
274 memcached_server_response_increment(ptr
);
275 return MEMCACHED_STAT
;
277 else if (buffer
[1] == 'E') /* SERVER_ERROR */
280 char *startptr
= buffer
+ 13, *endptr
= startptr
;
282 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
285 Yes, we could make this "efficent" but to do that we would need
286 to maintain more state for the size of the buffer. Why waste
287 memory in the struct, which is important, for something that
288 rarely should happen?
290 rel_ptr
= (char *)libmemcached_realloc(ptr
->root
,
291 ptr
->cached_server_error
,
292 (size_t) (endptr
- startptr
+ 1));
296 /* If we happened to have some memory, we just null it since we don't know the size */
297 if (ptr
->cached_server_error
)
298 ptr
->cached_server_error
[0]= 0;
299 return MEMCACHED_SERVER_ERROR
;
301 ptr
->cached_server_error
= rel_ptr
;
303 memcpy(ptr
->cached_server_error
, startptr
, (size_t) (endptr
- startptr
));
304 ptr
->cached_server_error
[endptr
- startptr
]= 0;
305 return MEMCACHED_SERVER_ERROR
;
307 else if (buffer
[1] == 'T')
308 return MEMCACHED_STORED
;
311 WATCHPOINT_STRING(buffer
);
312 return MEMCACHED_UNKNOWN_READ_FAILURE
;
315 case 'D': /* DELETED */
316 return MEMCACHED_DELETED
;
317 case 'N': /* NOT_FOUND */
319 if (buffer
[4] == 'F')
320 return MEMCACHED_NOTFOUND
;
321 else if (buffer
[4] == 'S')
322 return MEMCACHED_NOTSTORED
;
325 WATCHPOINT_STRING(buffer
);
326 return MEMCACHED_UNKNOWN_READ_FAILURE
;
329 case 'E': /* PROTOCOL ERROR or END */
331 if (buffer
[1] == 'N')
332 return MEMCACHED_END
;
333 else if (buffer
[1] == 'R')
334 return MEMCACHED_PROTOCOL_ERROR
;
335 else if (buffer
[1] == 'X')
336 return MEMCACHED_DATA_EXISTS
;
339 WATCHPOINT_STRING(buffer
);
340 return MEMCACHED_UNKNOWN_READ_FAILURE
;
344 case 'I': /* CLIENT ERROR */
345 /* We add back in one because we will need to search for END */
346 memcached_server_response_increment(ptr
);
347 return MEMCACHED_ITEM
;
348 case 'C': /* CLIENT ERROR */
349 return MEMCACHED_CLIENT_ERROR
;
352 unsigned long long auto_return_value
;
354 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
355 return MEMCACHED_SUCCESS
;
357 WATCHPOINT_STRING(buffer
);
358 return MEMCACHED_UNKNOWN_READ_FAILURE
;
365 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
366 char *buffer
, size_t buffer_length
,
367 memcached_result_st
*result
)
369 memcached_return_t rc
;
370 protocol_binary_response_header header
;
372 if ((rc
= memcached_safe_read(ptr
, &header
.bytes
, sizeof(header
.bytes
))) != MEMCACHED_SUCCESS
)
374 WATCHPOINT_ERROR(rc
);
378 if (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
380 return MEMCACHED_PROTOCOL_ERROR
;
384 ** Convert the header to host local endian!
386 header
.response
.keylen
= ntohs(header
.response
.keylen
);
387 header
.response
.status
= ntohs(header
.response
.status
);
388 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
389 header
.response
.cas
= ntohll(header
.response
.cas
);
390 uint32_t bodylen
= header
.response
.bodylen
;
392 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
||
393 header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
395 switch (header
.response
.opcode
)
397 case PROTOCOL_BINARY_CMD_GETKQ
:
399 * We didn't increment the response counter for the GETKQ packet
400 * (only the final NOOP), so we need to increment the counter again.
402 memcached_server_response_increment(ptr
);
404 case PROTOCOL_BINARY_CMD_GETK
:
406 uint16_t keylen
= header
.response
.keylen
;
407 memcached_result_reset(result
);
408 result
->item_cas
= header
.response
.cas
;
410 if ((rc
= memcached_safe_read(ptr
, &result
->item_flags
, sizeof (result
->item_flags
))) != MEMCACHED_SUCCESS
)
412 WATCHPOINT_ERROR(rc
);
413 return MEMCACHED_UNKNOWN_READ_FAILURE
;
416 result
->item_flags
= ntohl(result
->item_flags
);
417 bodylen
-= header
.response
.extlen
;
419 result
->key_length
= keylen
;
420 if ((rc
= memcached_safe_read(ptr
, result
->item_key
, keylen
)) != MEMCACHED_SUCCESS
)
422 WATCHPOINT_ERROR(rc
);
423 return MEMCACHED_UNKNOWN_READ_FAILURE
;
427 if (memcached_string_check(&result
->value
,
428 bodylen
) != MEMCACHED_SUCCESS
)
429 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
431 char *vptr
= memcached_string_value_mutable(&result
->value
);
432 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
434 WATCHPOINT_ERROR(rc
);
435 return MEMCACHED_UNKNOWN_READ_FAILURE
;
438 memcached_string_set_length(&result
->value
, bodylen
);
441 case PROTOCOL_BINARY_CMD_INCREMENT
:
442 case PROTOCOL_BINARY_CMD_DECREMENT
:
444 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
445 return MEMCACHED_PROTOCOL_ERROR
;
447 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
449 if ((rc
= memcached_safe_read(ptr
, &val
, sizeof(val
))) != MEMCACHED_SUCCESS
)
451 WATCHPOINT_ERROR(rc
);
452 return MEMCACHED_UNKNOWN_READ_FAILURE
;
456 memcpy(buffer
, &val
, sizeof(val
));
459 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
460 case PROTOCOL_BINARY_CMD_VERSION
:
462 memset(buffer
, 0, buffer_length
);
463 if (bodylen
>= buffer_length
)
465 /* not enough space in buffer.. should not happen... */
466 return MEMCACHED_UNKNOWN_READ_FAILURE
;
468 else if ((rc
= memcached_safe_read(ptr
, buffer
, bodylen
)) != MEMCACHED_SUCCESS
)
470 WATCHPOINT_ERROR(rc
);
471 return MEMCACHED_UNKNOWN_READ_FAILURE
;
475 case PROTOCOL_BINARY_CMD_FLUSH
:
476 case PROTOCOL_BINARY_CMD_QUIT
:
477 case PROTOCOL_BINARY_CMD_SET
:
478 case PROTOCOL_BINARY_CMD_ADD
:
479 case PROTOCOL_BINARY_CMD_REPLACE
:
480 case PROTOCOL_BINARY_CMD_APPEND
:
481 case PROTOCOL_BINARY_CMD_PREPEND
:
482 case PROTOCOL_BINARY_CMD_DELETE
:
484 WATCHPOINT_ASSERT(bodylen
== 0);
485 return MEMCACHED_SUCCESS
;
487 case PROTOCOL_BINARY_CMD_NOOP
:
489 WATCHPOINT_ASSERT(bodylen
== 0);
490 return MEMCACHED_END
;
492 case PROTOCOL_BINARY_CMD_STAT
:
496 return MEMCACHED_END
;
498 else if (bodylen
+ 1 > buffer_length
)
500 /* not enough space in buffer.. should not happen... */
501 return MEMCACHED_UNKNOWN_READ_FAILURE
;
505 size_t keylen
= header
.response
.keylen
;
506 memset(buffer
, 0, buffer_length
);
507 if ((rc
= memcached_safe_read(ptr
, buffer
, keylen
)) != MEMCACHED_SUCCESS
||
508 (rc
= memcached_safe_read(ptr
, buffer
+ keylen
+ 1, bodylen
- keylen
)) != MEMCACHED_SUCCESS
)
510 WATCHPOINT_ERROR(rc
);
511 return MEMCACHED_UNKNOWN_READ_FAILURE
;
517 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
518 case PROTOCOL_BINARY_CMD_SASL_STEP
:
520 memcached_result_reset(result
);
521 result
->item_cas
= header
.response
.cas
;
523 if (memcached_string_check(&result
->value
,
524 bodylen
) != MEMCACHED_SUCCESS
)
525 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
527 char *vptr
= memcached_string_value_mutable(&result
->value
);
528 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
530 WATCHPOINT_ERROR(rc
);
531 return MEMCACHED_UNKNOWN_READ_FAILURE
;
534 memcached_string_set_length(&result
->value
, bodylen
);
539 /* Command not implemented yet! */
540 WATCHPOINT_ASSERT(0);
541 return MEMCACHED_PROTOCOL_ERROR
;
545 else if (header
.response
.bodylen
)
547 /* What should I do with the error message??? just discard it for now */
548 char hole
[SMALL_STRING_LEN
];
551 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
552 if ((rc
= memcached_safe_read(ptr
, hole
, nr
)) != MEMCACHED_SUCCESS
)
554 WATCHPOINT_ERROR(rc
);
555 return memcached_set_error((memcached_st
*)ptr
->root
, MEMCACHED_UNKNOWN_READ_FAILURE
);
557 bodylen
-= (uint32_t) nr
;
560 /* This might be an error from one of the quiet commands.. if
561 * so, just throw it away and get the next one. What about creating
562 * a callback to the user with the error information?
564 switch (header
.response
.opcode
)
566 case PROTOCOL_BINARY_CMD_SETQ
:
567 case PROTOCOL_BINARY_CMD_ADDQ
:
568 case PROTOCOL_BINARY_CMD_REPLACEQ
:
569 case PROTOCOL_BINARY_CMD_APPENDQ
:
570 case PROTOCOL_BINARY_CMD_PREPENDQ
:
571 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
577 rc
= MEMCACHED_SUCCESS
;
578 unlikely(header
.response
.status
!= 0)
579 switch (header
.response
.status
)
581 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
582 rc
= MEMCACHED_NOTFOUND
;
584 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
585 rc
= MEMCACHED_DATA_EXISTS
;
587 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
588 rc
= MEMCACHED_NOTSTORED
;
590 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
593 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
594 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
596 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
597 rc
= MEMCACHED_AUTH_CONTINUE
;
599 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
600 rc
= MEMCACHED_AUTH_FAILURE
;
602 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
603 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
605 /* @todo fix the error mappings */
606 rc
= MEMCACHED_PROTOCOL_ERROR
;