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
)
119 ssize_t read_length
= 0;
121 if (ptr
->root
->flags
.use_udp
)
122 return memcached_set_error(*ptr
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
124 WATCHPOINT_ASSERT(ptr
->root
);
125 end_ptr
= buffer
+ MEMCACHED_DEFAULT_COMMAND_SIZE
;
127 memcached_result_reset(result
);
130 string_ptr
+= 6; /* "VALUE " */
133 /* We load the key */
136 size_t prefix_length
;
138 key
= result
->item_key
;
139 result
->key_length
= 0;
141 for (prefix_length
= memcached_array_size(ptr
->root
->prefix_key
); !(iscntrl(*string_ptr
) || isspace(*string_ptr
)) ; string_ptr
++)
143 if (prefix_length
== 0)
147 result
->key_length
++;
152 result
->item_key
[result
->key_length
]= 0;
155 if (end_ptr
== string_ptr
)
158 /* Flags fetch move past space */
160 if (end_ptr
== string_ptr
)
163 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
164 result
->item_flags
= (uint32_t) strtoul(next_ptr
, &string_ptr
, 10);
166 if (end_ptr
== string_ptr
)
169 /* Length fetch move past space*/
171 if (end_ptr
== string_ptr
)
174 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
175 value_length
= (size_t)strtoull(next_ptr
, &string_ptr
, 10);
177 if (end_ptr
== string_ptr
)
181 if (*string_ptr
== '\r')
183 /* Skip past the \r\n */
189 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++) {};
190 result
->item_cas
= strtoull(next_ptr
, &string_ptr
, 10);
193 if (end_ptr
< string_ptr
)
196 /* We add two bytes so that we can walk the \r\n */
197 if (memcached_failed(memcached_string_check(&result
->value
, value_length
+2)))
200 return memcached_set_error(*ptr
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
, MEMCACHED_AT
);
204 char *value_ptr
= memcached_string_value_mutable(&result
->value
);
206 We read the \r\n into the string since not doing so is more
207 cycles then the waster of memory to do so.
209 We are null terminating through, which will most likely make
210 some people lazy about using the return length.
212 to_read
= (value_length
) + 2;
213 memcached_return_t rrc
= memcached_io_read(ptr
, value_ptr
, to_read
, &read_length
);
214 if (memcached_failed(rrc
))
218 if (read_length
!= (ssize_t
)(value_length
+ 2))
223 /* This next bit blows the API, but this is internal....*/
226 char_ptr
= memcached_string_value_mutable(&result
->value
);;
227 char_ptr
[value_length
]= 0;
228 char_ptr
[value_length
+ 1]= 0;
229 memcached_string_set_length(&result
->value
, value_length
);
232 return MEMCACHED_SUCCESS
;
235 memcached_io_reset(ptr
);
237 return MEMCACHED_PARTIAL_READ
;
240 static memcached_return_t
textual_read_one_response(memcached_server_write_instance_st ptr
,
241 char *buffer
, size_t buffer_length
,
242 memcached_result_st
*result
)
244 memcached_return_t rc
= memcached_io_readline(ptr
, buffer
, buffer_length
);
245 if (rc
!= MEMCACHED_SUCCESS
)
250 case 'V': /* VALUE || VERSION */
251 if (buffer
[1] == 'A') /* VALUE */
253 /* We add back in one because we will need to search for END */
254 memcached_server_response_increment(ptr
);
255 return textual_value_fetch(ptr
, buffer
, result
);
257 else if (buffer
[1] == 'E') /* VERSION */
259 return MEMCACHED_SUCCESS
;
263 WATCHPOINT_STRING(buffer
);
264 return MEMCACHED_UNKNOWN_READ_FAILURE
;
267 return MEMCACHED_SUCCESS
;
268 case 'S': /* STORED STATS SERVER_ERROR */
270 if (buffer
[2] == 'A') /* STORED STATS */
272 memcached_server_response_increment(ptr
);
273 return MEMCACHED_STAT
;
275 else if (buffer
[1] == 'E') /* SERVER_ERROR */
278 char *startptr
= buffer
+ 13, *endptr
= startptr
;
280 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
283 Yes, we could make this "efficent" but to do that we would need
284 to maintain more state for the size of the buffer. Why waste
285 memory in the struct, which is important, for something that
286 rarely should happen?
288 rel_ptr
= (char *)libmemcached_realloc(ptr
->root
,
289 ptr
->cached_server_error
,
290 (size_t) (endptr
- startptr
+ 1));
294 /* If we happened to have some memory, we just null it since we don't know the size */
295 if (ptr
->cached_server_error
)
296 ptr
->cached_server_error
[0]= 0;
297 return MEMCACHED_SERVER_ERROR
;
299 ptr
->cached_server_error
= rel_ptr
;
301 memcpy(ptr
->cached_server_error
, startptr
, (size_t) (endptr
- startptr
));
302 ptr
->cached_server_error
[endptr
- startptr
]= 0;
303 return MEMCACHED_SERVER_ERROR
;
305 else if (buffer
[1] == 'T')
306 return MEMCACHED_STORED
;
309 WATCHPOINT_STRING(buffer
);
310 return MEMCACHED_UNKNOWN_READ_FAILURE
;
313 case 'D': /* DELETED */
314 return MEMCACHED_DELETED
;
315 case 'N': /* NOT_FOUND */
317 if (buffer
[4] == 'F')
318 return MEMCACHED_NOTFOUND
;
319 else if (buffer
[4] == 'S')
320 return MEMCACHED_NOTSTORED
;
323 WATCHPOINT_STRING(buffer
);
324 return MEMCACHED_UNKNOWN_READ_FAILURE
;
327 case 'E': /* PROTOCOL ERROR or END */
329 if (buffer
[1] == 'N')
330 return MEMCACHED_END
;
331 else if (buffer
[1] == 'R')
332 return MEMCACHED_PROTOCOL_ERROR
;
333 else if (buffer
[1] == 'X')
334 return MEMCACHED_DATA_EXISTS
;
337 WATCHPOINT_STRING(buffer
);
338 return MEMCACHED_UNKNOWN_READ_FAILURE
;
342 case 'I': /* CLIENT ERROR */
343 /* We add back in one because we will need to search for END */
344 memcached_server_response_increment(ptr
);
345 return MEMCACHED_ITEM
;
346 case 'C': /* CLIENT ERROR */
347 return MEMCACHED_CLIENT_ERROR
;
350 unsigned long long auto_return_value
;
352 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
353 return MEMCACHED_SUCCESS
;
355 WATCHPOINT_STRING(buffer
);
356 return MEMCACHED_UNKNOWN_READ_FAILURE
;
363 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
364 char *buffer
, size_t buffer_length
,
365 memcached_result_st
*result
)
367 memcached_return_t rc
;
368 protocol_binary_response_header header
;
370 if ((rc
= memcached_safe_read(ptr
, &header
.bytes
, sizeof(header
.bytes
))) != MEMCACHED_SUCCESS
)
372 WATCHPOINT_ERROR(rc
);
376 if (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
378 return MEMCACHED_PROTOCOL_ERROR
;
382 ** Convert the header to host local endian!
384 header
.response
.keylen
= ntohs(header
.response
.keylen
);
385 header
.response
.status
= ntohs(header
.response
.status
);
386 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
387 header
.response
.cas
= ntohll(header
.response
.cas
);
388 uint32_t bodylen
= header
.response
.bodylen
;
390 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
||
391 header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
393 switch (header
.response
.opcode
)
395 case PROTOCOL_BINARY_CMD_GETKQ
:
397 * We didn't increment the response counter for the GETKQ packet
398 * (only the final NOOP), so we need to increment the counter again.
400 memcached_server_response_increment(ptr
);
402 case PROTOCOL_BINARY_CMD_GETK
:
404 uint16_t keylen
= header
.response
.keylen
;
405 memcached_result_reset(result
);
406 result
->item_cas
= header
.response
.cas
;
408 if ((rc
= memcached_safe_read(ptr
, &result
->item_flags
, sizeof (result
->item_flags
))) != MEMCACHED_SUCCESS
)
410 WATCHPOINT_ERROR(rc
);
411 return MEMCACHED_UNKNOWN_READ_FAILURE
;
414 result
->item_flags
= ntohl(result
->item_flags
);
415 bodylen
-= header
.response
.extlen
;
417 result
->key_length
= keylen
;
418 if ((rc
= memcached_safe_read(ptr
, result
->item_key
, keylen
)) != MEMCACHED_SUCCESS
)
420 WATCHPOINT_ERROR(rc
);
421 return MEMCACHED_UNKNOWN_READ_FAILURE
;
425 if (memcached_string_check(&result
->value
,
426 bodylen
) != MEMCACHED_SUCCESS
)
427 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
429 char *vptr
= memcached_string_value_mutable(&result
->value
);
430 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
432 WATCHPOINT_ERROR(rc
);
433 return MEMCACHED_UNKNOWN_READ_FAILURE
;
436 memcached_string_set_length(&result
->value
, bodylen
);
439 case PROTOCOL_BINARY_CMD_INCREMENT
:
440 case PROTOCOL_BINARY_CMD_DECREMENT
:
442 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
443 return MEMCACHED_PROTOCOL_ERROR
;
445 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
447 if ((rc
= memcached_safe_read(ptr
, &val
, sizeof(val
))) != MEMCACHED_SUCCESS
)
449 WATCHPOINT_ERROR(rc
);
450 return MEMCACHED_UNKNOWN_READ_FAILURE
;
454 memcpy(buffer
, &val
, sizeof(val
));
457 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
458 case PROTOCOL_BINARY_CMD_VERSION
:
460 memset(buffer
, 0, buffer_length
);
461 if (bodylen
>= buffer_length
)
463 /* not enough space in buffer.. should not happen... */
464 return MEMCACHED_UNKNOWN_READ_FAILURE
;
466 else if ((rc
= memcached_safe_read(ptr
, buffer
, bodylen
)) != MEMCACHED_SUCCESS
)
468 WATCHPOINT_ERROR(rc
);
469 return MEMCACHED_UNKNOWN_READ_FAILURE
;
473 case PROTOCOL_BINARY_CMD_FLUSH
:
474 case PROTOCOL_BINARY_CMD_QUIT
:
475 case PROTOCOL_BINARY_CMD_SET
:
476 case PROTOCOL_BINARY_CMD_ADD
:
477 case PROTOCOL_BINARY_CMD_REPLACE
:
478 case PROTOCOL_BINARY_CMD_APPEND
:
479 case PROTOCOL_BINARY_CMD_PREPEND
:
480 case PROTOCOL_BINARY_CMD_DELETE
:
482 WATCHPOINT_ASSERT(bodylen
== 0);
483 return MEMCACHED_SUCCESS
;
485 case PROTOCOL_BINARY_CMD_NOOP
:
487 WATCHPOINT_ASSERT(bodylen
== 0);
488 return MEMCACHED_END
;
490 case PROTOCOL_BINARY_CMD_STAT
:
494 return MEMCACHED_END
;
496 else if (bodylen
+ 1 > buffer_length
)
498 /* not enough space in buffer.. should not happen... */
499 return MEMCACHED_UNKNOWN_READ_FAILURE
;
503 size_t keylen
= header
.response
.keylen
;
504 memset(buffer
, 0, buffer_length
);
505 if ((rc
= memcached_safe_read(ptr
, buffer
, keylen
)) != MEMCACHED_SUCCESS
||
506 (rc
= memcached_safe_read(ptr
, buffer
+ keylen
+ 1, bodylen
- keylen
)) != MEMCACHED_SUCCESS
)
508 WATCHPOINT_ERROR(rc
);
509 return MEMCACHED_UNKNOWN_READ_FAILURE
;
515 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
516 case PROTOCOL_BINARY_CMD_SASL_STEP
:
518 memcached_result_reset(result
);
519 result
->item_cas
= header
.response
.cas
;
521 if (memcached_string_check(&result
->value
,
522 bodylen
) != MEMCACHED_SUCCESS
)
523 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
525 char *vptr
= memcached_string_value_mutable(&result
->value
);
526 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
528 WATCHPOINT_ERROR(rc
);
529 return MEMCACHED_UNKNOWN_READ_FAILURE
;
532 memcached_string_set_length(&result
->value
, bodylen
);
537 /* Command not implemented yet! */
538 WATCHPOINT_ASSERT(0);
539 return MEMCACHED_PROTOCOL_ERROR
;
543 else if (header
.response
.bodylen
)
545 /* What should I do with the error message??? just discard it for now */
546 char hole
[SMALL_STRING_LEN
];
549 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
550 if ((rc
= memcached_safe_read(ptr
, hole
, nr
)) != MEMCACHED_SUCCESS
)
552 WATCHPOINT_ERROR(rc
);
553 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
555 bodylen
-= (uint32_t) nr
;
558 /* This might be an error from one of the quiet commands.. if
559 * so, just throw it away and get the next one. What about creating
560 * a callback to the user with the error information?
562 switch (header
.response
.opcode
)
564 case PROTOCOL_BINARY_CMD_SETQ
:
565 case PROTOCOL_BINARY_CMD_ADDQ
:
566 case PROTOCOL_BINARY_CMD_REPLACEQ
:
567 case PROTOCOL_BINARY_CMD_APPENDQ
:
568 case PROTOCOL_BINARY_CMD_PREPENDQ
:
569 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
575 rc
= MEMCACHED_SUCCESS
;
576 unlikely(header
.response
.status
!= 0)
577 switch (header
.response
.status
)
579 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
580 rc
= MEMCACHED_NOTFOUND
;
582 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
583 rc
= MEMCACHED_DATA_EXISTS
;
585 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
586 rc
= MEMCACHED_NOTSTORED
;
588 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
591 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
592 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
594 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
595 rc
= MEMCACHED_AUTH_CONTINUE
;
597 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
598 rc
= MEMCACHED_AUTH_FAILURE
;
600 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
601 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
603 /* @todo fix the error mappings */
604 rc
= MEMCACHED_PROTOCOL_ERROR
;