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
or
66 rc
== MEMCACHED_PROTOCOL_ERROR
or
67 rc
== MEMCACHED_CLIENT_ERROR
or
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
) and rrc
== MEMCACHED_IN_PROGRESS
)
216 memcached_quit_server(ptr
, true);
217 return memcached_set_error(*ptr
, rrc
, MEMCACHED_AT
);
219 else if (memcached_failed(rrc
))
225 if (read_length
!= (ssize_t
)(value_length
+ 2))
230 /* This next bit blows the API, but this is internal....*/
233 char_ptr
= memcached_string_value_mutable(&result
->value
);;
234 char_ptr
[value_length
]= 0;
235 char_ptr
[value_length
+1]= 0;
236 memcached_string_set_length(&result
->value
, value_length
);
239 return MEMCACHED_SUCCESS
;
242 memcached_io_reset(ptr
);
244 return MEMCACHED_PARTIAL_READ
;
247 static memcached_return_t
textual_read_one_response(memcached_server_write_instance_st ptr
,
248 char *buffer
, size_t buffer_length
,
249 memcached_result_st
*result
)
251 memcached_return_t rc
= memcached_io_readline(ptr
, buffer
, buffer_length
);
252 if (memcached_failed(rc
))
259 case 'V': /* VALUE || VERSION */
260 if (buffer
[1] == 'A') /* VALUE */
262 /* We add back in one because we will need to search for END */
263 memcached_server_response_increment(ptr
);
264 return textual_value_fetch(ptr
, buffer
, result
);
266 else if (buffer
[1] == 'E') /* VERSION */
268 return MEMCACHED_SUCCESS
;
272 WATCHPOINT_STRING(buffer
);
273 return MEMCACHED_UNKNOWN_READ_FAILURE
;
276 return MEMCACHED_SUCCESS
;
277 case 'S': /* STORED STATS SERVER_ERROR */
279 if (buffer
[2] == 'A') /* STORED STATS */
281 memcached_server_response_increment(ptr
);
282 return MEMCACHED_STAT
;
284 else if (buffer
[1] == 'E') /* SERVER_ERROR */
287 char *startptr
= buffer
+ 13, *endptr
= startptr
;
289 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
292 Yes, we could make this "efficent" but to do that we would need
293 to maintain more state for the size of the buffer. Why waste
294 memory in the struct, which is important, for something that
295 rarely should happen?
297 rel_ptr
= (char *)libmemcached_realloc(ptr
->root
,
298 ptr
->cached_server_error
,
299 (size_t) (endptr
- startptr
+ 1));
303 /* If we happened to have some memory, we just null it since we don't know the size */
304 if (ptr
->cached_server_error
)
305 ptr
->cached_server_error
[0]= 0;
306 return MEMCACHED_SERVER_ERROR
;
308 ptr
->cached_server_error
= rel_ptr
;
310 memcpy(ptr
->cached_server_error
, startptr
, (size_t) (endptr
- startptr
));
311 ptr
->cached_server_error
[endptr
- startptr
]= 0;
312 return MEMCACHED_SERVER_ERROR
;
314 else if (buffer
[1] == 'T')
315 return MEMCACHED_STORED
;
318 WATCHPOINT_STRING(buffer
);
319 return MEMCACHED_UNKNOWN_READ_FAILURE
;
322 case 'D': /* DELETED */
323 return MEMCACHED_DELETED
;
324 case 'N': /* NOT_FOUND */
326 if (buffer
[4] == 'F')
327 return MEMCACHED_NOTFOUND
;
328 else if (buffer
[4] == 'S')
329 return MEMCACHED_NOTSTORED
;
332 WATCHPOINT_STRING(buffer
);
333 return MEMCACHED_UNKNOWN_READ_FAILURE
;
336 case 'E': /* PROTOCOL ERROR or END */
338 if (buffer
[1] == 'N')
339 return MEMCACHED_END
;
340 else if (buffer
[1] == 'R')
341 return MEMCACHED_PROTOCOL_ERROR
;
342 else if (buffer
[1] == 'X')
343 return MEMCACHED_DATA_EXISTS
;
346 WATCHPOINT_STRING(buffer
);
347 return MEMCACHED_UNKNOWN_READ_FAILURE
;
351 case 'I': /* CLIENT ERROR */
352 /* We add back in one because we will need to search for END */
353 memcached_server_response_increment(ptr
);
354 return MEMCACHED_ITEM
;
355 case 'C': /* CLIENT ERROR */
356 return MEMCACHED_CLIENT_ERROR
;
359 unsigned long long auto_return_value
;
361 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
362 return MEMCACHED_SUCCESS
;
364 WATCHPOINT_STRING(buffer
);
365 return MEMCACHED_UNKNOWN_READ_FAILURE
;
372 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
373 char *buffer
, size_t buffer_length
,
374 memcached_result_st
*result
)
376 memcached_return_t rc
;
377 protocol_binary_response_header header
;
379 if ((rc
= memcached_safe_read(ptr
, &header
.bytes
, sizeof(header
.bytes
))) != MEMCACHED_SUCCESS
)
381 WATCHPOINT_ERROR(rc
);
385 if (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
387 return MEMCACHED_PROTOCOL_ERROR
;
391 ** Convert the header to host local endian!
393 header
.response
.keylen
= ntohs(header
.response
.keylen
);
394 header
.response
.status
= ntohs(header
.response
.status
);
395 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
396 header
.response
.cas
= memcached_ntohll(header
.response
.cas
);
397 uint32_t bodylen
= header
.response
.bodylen
;
399 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
||
400 header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
402 switch (header
.response
.opcode
)
404 case PROTOCOL_BINARY_CMD_GETKQ
:
406 * We didn't increment the response counter for the GETKQ packet
407 * (only the final NOOP), so we need to increment the counter again.
409 memcached_server_response_increment(ptr
);
411 case PROTOCOL_BINARY_CMD_GETK
:
413 uint16_t keylen
= header
.response
.keylen
;
414 memcached_result_reset(result
);
415 result
->item_cas
= header
.response
.cas
;
417 if ((rc
= memcached_safe_read(ptr
, &result
->item_flags
, sizeof (result
->item_flags
))) != MEMCACHED_SUCCESS
)
419 WATCHPOINT_ERROR(rc
);
420 return MEMCACHED_UNKNOWN_READ_FAILURE
;
423 result
->item_flags
= ntohl(result
->item_flags
);
424 bodylen
-= header
.response
.extlen
;
426 result
->key_length
= keylen
;
427 if ((rc
= memcached_safe_read(ptr
, result
->item_key
, keylen
)) != MEMCACHED_SUCCESS
)
429 WATCHPOINT_ERROR(rc
);
430 return MEMCACHED_UNKNOWN_READ_FAILURE
;
434 if (memcached_string_check(&result
->value
,
435 bodylen
) != MEMCACHED_SUCCESS
)
436 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
438 char *vptr
= memcached_string_value_mutable(&result
->value
);
439 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
441 WATCHPOINT_ERROR(rc
);
442 return MEMCACHED_UNKNOWN_READ_FAILURE
;
445 memcached_string_set_length(&result
->value
, bodylen
);
448 case PROTOCOL_BINARY_CMD_INCREMENT
:
449 case PROTOCOL_BINARY_CMD_DECREMENT
:
451 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
452 return MEMCACHED_PROTOCOL_ERROR
;
454 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
456 if ((rc
= memcached_safe_read(ptr
, &val
, sizeof(val
))) != MEMCACHED_SUCCESS
)
458 WATCHPOINT_ERROR(rc
);
459 return MEMCACHED_UNKNOWN_READ_FAILURE
;
462 val
= memcached_ntohll(val
);
463 memcpy(buffer
, &val
, sizeof(val
));
466 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
467 case PROTOCOL_BINARY_CMD_VERSION
:
469 memset(buffer
, 0, buffer_length
);
470 if (bodylen
>= buffer_length
)
472 /* not enough space in buffer.. should not happen... */
473 return MEMCACHED_UNKNOWN_READ_FAILURE
;
475 else if ((rc
= memcached_safe_read(ptr
, buffer
, bodylen
)) != MEMCACHED_SUCCESS
)
477 WATCHPOINT_ERROR(rc
);
478 return MEMCACHED_UNKNOWN_READ_FAILURE
;
482 case PROTOCOL_BINARY_CMD_FLUSH
:
483 case PROTOCOL_BINARY_CMD_QUIT
:
484 case PROTOCOL_BINARY_CMD_SET
:
485 case PROTOCOL_BINARY_CMD_ADD
:
486 case PROTOCOL_BINARY_CMD_REPLACE
:
487 case PROTOCOL_BINARY_CMD_APPEND
:
488 case PROTOCOL_BINARY_CMD_PREPEND
:
489 case PROTOCOL_BINARY_CMD_DELETE
:
491 WATCHPOINT_ASSERT(bodylen
== 0);
492 return MEMCACHED_SUCCESS
;
494 case PROTOCOL_BINARY_CMD_NOOP
:
496 WATCHPOINT_ASSERT(bodylen
== 0);
497 return MEMCACHED_END
;
499 case PROTOCOL_BINARY_CMD_STAT
:
503 return MEMCACHED_END
;
505 else if (bodylen
+ 1 > buffer_length
)
507 /* not enough space in buffer.. should not happen... */
508 return MEMCACHED_UNKNOWN_READ_FAILURE
;
512 size_t keylen
= header
.response
.keylen
;
513 memset(buffer
, 0, buffer_length
);
514 if ((rc
= memcached_safe_read(ptr
, buffer
, keylen
)) != MEMCACHED_SUCCESS
||
515 (rc
= memcached_safe_read(ptr
, buffer
+ keylen
+ 1, bodylen
- keylen
)) != MEMCACHED_SUCCESS
)
517 WATCHPOINT_ERROR(rc
);
518 return MEMCACHED_UNKNOWN_READ_FAILURE
;
524 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
525 case PROTOCOL_BINARY_CMD_SASL_STEP
:
527 memcached_result_reset(result
);
528 result
->item_cas
= header
.response
.cas
;
530 if (memcached_string_check(&result
->value
,
531 bodylen
) != MEMCACHED_SUCCESS
)
532 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
534 char *vptr
= memcached_string_value_mutable(&result
->value
);
535 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
537 WATCHPOINT_ERROR(rc
);
538 return MEMCACHED_UNKNOWN_READ_FAILURE
;
541 memcached_string_set_length(&result
->value
, bodylen
);
546 /* Command not implemented yet! */
547 WATCHPOINT_ASSERT(0);
548 return MEMCACHED_PROTOCOL_ERROR
;
552 else if (header
.response
.bodylen
)
554 /* What should I do with the error message??? just discard it for now */
555 char hole
[SMALL_STRING_LEN
];
558 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
559 if ((rc
= memcached_safe_read(ptr
, hole
, nr
)) != MEMCACHED_SUCCESS
)
561 WATCHPOINT_ERROR(rc
);
562 return memcached_set_error(*ptr
, MEMCACHED_UNKNOWN_READ_FAILURE
, MEMCACHED_AT
);
564 bodylen
-= (uint32_t) nr
;
567 /* This might be an error from one of the quiet commands.. if
568 * so, just throw it away and get the next one. What about creating
569 * a callback to the user with the error information?
571 switch (header
.response
.opcode
)
573 case PROTOCOL_BINARY_CMD_SETQ
:
574 case PROTOCOL_BINARY_CMD_ADDQ
:
575 case PROTOCOL_BINARY_CMD_REPLACEQ
:
576 case PROTOCOL_BINARY_CMD_APPENDQ
:
577 case PROTOCOL_BINARY_CMD_PREPENDQ
:
578 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
584 rc
= MEMCACHED_SUCCESS
;
585 unlikely(header
.response
.status
!= 0)
586 switch (header
.response
.status
)
588 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
589 rc
= MEMCACHED_NOTFOUND
;
591 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
592 rc
= MEMCACHED_DATA_EXISTS
;
594 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
595 rc
= MEMCACHED_NOTSTORED
;
597 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
600 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
601 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
603 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
604 rc
= MEMCACHED_AUTH_CONTINUE
;
606 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
607 rc
= MEMCACHED_AUTH_FAILURE
;
609 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
610 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
612 /* @todo fix the error mappings */
613 rc
= MEMCACHED_PROTOCOL_ERROR
;