2 * Copyright (C) 2006-2009 Brian Aker
5 * Use and distribution licensed under the BSD license. See
6 * the COPYING file in the parent directory for full text.
8 * Summary: memcached_response() is used to determine the return result from an issued command.
14 static memcached_return_t
textual_read_one_response(memcached_server_write_instance_st ptr
,
15 char *buffer
, size_t buffer_length
,
16 memcached_result_st
*result
);
17 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
18 char *buffer
, size_t buffer_length
,
19 memcached_result_st
*result
);
21 memcached_return_t
memcached_read_one_response(memcached_server_write_instance_st ptr
,
22 char *buffer
, size_t buffer_length
,
23 memcached_result_st
*result
)
25 memcached_server_response_decrement(ptr
);
29 memcached_st
*root
= (memcached_st
*)ptr
->root
;
30 result
= &root
->result
;
33 memcached_return_t rc
;
34 if (ptr
->root
->flags
.binary_protocol
)
35 rc
= binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
37 rc
= textual_read_one_response(ptr
, buffer
, buffer_length
, result
);
39 unlikely(rc
== MEMCACHED_UNKNOWN_READ_FAILURE
||
40 rc
== MEMCACHED_PROTOCOL_ERROR
||
41 rc
== MEMCACHED_CLIENT_ERROR
||
42 rc
== MEMCACHED_MEMORY_ALLOCATION_FAILURE
)
43 memcached_io_reset(ptr
);
48 memcached_return_t
memcached_response(memcached_server_write_instance_st ptr
,
49 char *buffer
, size_t buffer_length
,
50 memcached_result_st
*result
)
52 /* We may have old commands in the buffer not set, first purge */
53 if ((ptr
->root
->flags
.no_block
) && (memcached_is_processing_input(ptr
->root
) == false))
55 (void)memcached_io_write(ptr
, NULL
, 0, true);
59 * The previous implementation purged all pending requests and just
60 * returned the last one. Purge all pending messages to ensure backwards
63 if (ptr
->root
->flags
.binary_protocol
== false)
64 while (memcached_server_response_count(ptr
) > 1)
66 memcached_return_t rc
= memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
68 unlikely (rc
!= MEMCACHED_END
&&
69 rc
!= MEMCACHED_STORED
&&
70 rc
!= MEMCACHED_SUCCESS
&&
71 rc
!= MEMCACHED_STAT
&&
72 rc
!= MEMCACHED_DELETED
&&
73 rc
!= MEMCACHED_NOTFOUND
&&
74 rc
!= MEMCACHED_NOTSTORED
&&
75 rc
!= MEMCACHED_DATA_EXISTS
)
79 return memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
82 static memcached_return_t
textual_value_fetch(memcached_server_write_instance_st ptr
,
84 memcached_result_st
*result
)
86 memcached_return_t rc
= MEMCACHED_SUCCESS
;
93 ssize_t read_length
= 0;
94 memcached_return_t rrc
;
96 if (ptr
->root
->flags
.use_udp
)
97 return MEMCACHED_NOT_SUPPORTED
;
99 WATCHPOINT_ASSERT(ptr
->root
);
100 end_ptr
= buffer
+ MEMCACHED_DEFAULT_COMMAND_SIZE
;
102 memcached_result_reset(result
);
105 string_ptr
+= 6; /* "VALUE " */
108 /* We load the key */
111 size_t prefix_length
;
113 key
= result
->item_key
;
114 result
->key_length
= 0;
116 for (prefix_length
= ptr
->root
->prefix_key_length
; !(iscntrl(*string_ptr
) || isspace(*string_ptr
)) ; string_ptr
++)
118 if (prefix_length
== 0)
122 result
->key_length
++;
127 result
->item_key
[result
->key_length
]= 0;
130 if (end_ptr
== string_ptr
)
133 /* Flags fetch move past space */
135 if (end_ptr
== string_ptr
)
137 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++);
138 result
->item_flags
= (uint32_t) strtoul(next_ptr
, &string_ptr
, 10);
140 if (end_ptr
== string_ptr
)
143 /* Length fetch move past space*/
145 if (end_ptr
== string_ptr
)
148 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++);
149 value_length
= (size_t)strtoull(next_ptr
, &string_ptr
, 10);
151 if (end_ptr
== string_ptr
)
155 if (*string_ptr
== '\r')
157 /* Skip past the \r\n */
163 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++);
164 result
->item_cas
= strtoull(next_ptr
, &string_ptr
, 10);
167 if (end_ptr
< string_ptr
)
170 /* We add two bytes so that we can walk the \r\n */
171 rc
= memcached_string_check(&result
->value
, value_length
+2);
172 if (rc
!= MEMCACHED_SUCCESS
)
175 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
178 value_ptr
= memcached_string_value_mutable(&result
->value
);
180 We read the \r\n into the string since not doing so is more
181 cycles then the waster of memory to do so.
183 We are null terminating through, which will most likely make
184 some people lazy about using the return length.
186 to_read
= (value_length
) + 2;
187 rrc
= memcached_io_read(ptr
, value_ptr
, to_read
, &read_length
);
188 if (rrc
!= MEMCACHED_SUCCESS
)
191 if (read_length
!= (ssize_t
)(value_length
+ 2))
196 /* This next bit blows the API, but this is internal....*/
199 char_ptr
= memcached_string_value_mutable(&result
->value
);;
200 char_ptr
[value_length
]= 0;
201 char_ptr
[value_length
+ 1]= 0;
202 memcached_string_set_length(&result
->value
, value_length
);
205 return MEMCACHED_SUCCESS
;
208 memcached_io_reset(ptr
);
210 return MEMCACHED_PARTIAL_READ
;
213 static memcached_return_t
textual_read_one_response(memcached_server_write_instance_st ptr
,
214 char *buffer
, size_t buffer_length
,
215 memcached_result_st
*result
)
217 memcached_return_t rc
= memcached_io_readline(ptr
, buffer
, buffer_length
);
218 if (rc
!= MEMCACHED_SUCCESS
)
223 case 'V': /* VALUE || VERSION */
224 if (buffer
[1] == 'A') /* VALUE */
226 /* We add back in one because we will need to search for END */
227 memcached_server_response_increment(ptr
);
228 return textual_value_fetch(ptr
, buffer
, result
);
230 else if (buffer
[1] == 'E') /* VERSION */
232 return MEMCACHED_SUCCESS
;
236 WATCHPOINT_STRING(buffer
);
237 return MEMCACHED_UNKNOWN_READ_FAILURE
;
240 return MEMCACHED_SUCCESS
;
241 case 'S': /* STORED STATS SERVER_ERROR */
243 if (buffer
[2] == 'A') /* STORED STATS */
245 memcached_server_response_increment(ptr
);
246 return MEMCACHED_STAT
;
248 else if (buffer
[1] == 'E') /* SERVER_ERROR */
251 char *startptr
= buffer
+ 13, *endptr
= startptr
;
253 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
256 Yes, we could make this "efficent" but to do that we would need
257 to maintain more state for the size of the buffer. Why waste
258 memory in the struct, which is important, for something that
259 rarely should happen?
261 rel_ptr
= (char *)libmemcached_realloc(ptr
->root
,
262 ptr
->cached_server_error
,
263 (size_t) (endptr
- startptr
+ 1));
267 /* If we happened to have some memory, we just null it since we don't know the size */
268 if (ptr
->cached_server_error
)
269 ptr
->cached_server_error
[0]= 0;
270 return MEMCACHED_SERVER_ERROR
;
272 ptr
->cached_server_error
= rel_ptr
;
274 memcpy(ptr
->cached_server_error
, startptr
, (size_t) (endptr
- startptr
));
275 ptr
->cached_server_error
[endptr
- startptr
]= 0;
276 return MEMCACHED_SERVER_ERROR
;
278 else if (buffer
[1] == 'T')
279 return MEMCACHED_STORED
;
282 WATCHPOINT_STRING(buffer
);
283 return MEMCACHED_UNKNOWN_READ_FAILURE
;
286 case 'D': /* DELETED */
287 return MEMCACHED_DELETED
;
288 case 'N': /* NOT_FOUND */
290 if (buffer
[4] == 'F')
291 return MEMCACHED_NOTFOUND
;
292 else if (buffer
[4] == 'S')
293 return MEMCACHED_NOTSTORED
;
296 WATCHPOINT_STRING(buffer
);
297 return MEMCACHED_UNKNOWN_READ_FAILURE
;
300 case 'E': /* PROTOCOL ERROR or END */
302 if (buffer
[1] == 'N')
303 return MEMCACHED_END
;
304 else if (buffer
[1] == 'R')
305 return MEMCACHED_PROTOCOL_ERROR
;
306 else if (buffer
[1] == 'X')
307 return MEMCACHED_DATA_EXISTS
;
310 WATCHPOINT_STRING(buffer
);
311 return MEMCACHED_UNKNOWN_READ_FAILURE
;
315 case 'I': /* CLIENT ERROR */
316 /* We add back in one because we will need to search for END */
317 memcached_server_response_increment(ptr
);
318 return MEMCACHED_ITEM
;
319 case 'C': /* CLIENT ERROR */
320 return MEMCACHED_CLIENT_ERROR
;
323 unsigned long long auto_return_value
;
325 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
326 return MEMCACHED_SUCCESS
;
328 WATCHPOINT_STRING(buffer
);
329 return MEMCACHED_UNKNOWN_READ_FAILURE
;
336 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
337 char *buffer
, size_t buffer_length
,
338 memcached_result_st
*result
)
340 memcached_return_t rc
;
341 protocol_binary_response_header header
;
343 if ((rc
= memcached_safe_read(ptr
, &header
.bytes
, sizeof(header
.bytes
))) != MEMCACHED_SUCCESS
)
345 WATCHPOINT_ERROR(rc
);
349 if (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
351 return MEMCACHED_PROTOCOL_ERROR
;
355 ** Convert the header to host local endian!
357 header
.response
.keylen
= ntohs(header
.response
.keylen
);
358 header
.response
.status
= ntohs(header
.response
.status
);
359 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
360 header
.response
.cas
= ntohll(header
.response
.cas
);
361 uint32_t bodylen
= header
.response
.bodylen
;
363 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
||
364 header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
366 switch (header
.response
.opcode
)
368 case PROTOCOL_BINARY_CMD_GETKQ
:
370 * We didn't increment the response counter for the GETKQ packet
371 * (only the final NOOP), so we need to increment the counter again.
373 memcached_server_response_increment(ptr
);
375 case PROTOCOL_BINARY_CMD_GETK
:
377 uint16_t keylen
= header
.response
.keylen
;
378 memcached_result_reset(result
);
379 result
->item_cas
= header
.response
.cas
;
381 if ((rc
= memcached_safe_read(ptr
, &result
->item_flags
, sizeof (result
->item_flags
))) != MEMCACHED_SUCCESS
)
383 WATCHPOINT_ERROR(rc
);
384 return MEMCACHED_UNKNOWN_READ_FAILURE
;
387 result
->item_flags
= ntohl(result
->item_flags
);
388 bodylen
-= header
.response
.extlen
;
390 result
->key_length
= keylen
;
391 if ((rc
= memcached_safe_read(ptr
, result
->item_key
, keylen
)) != MEMCACHED_SUCCESS
)
393 WATCHPOINT_ERROR(rc
);
394 return MEMCACHED_UNKNOWN_READ_FAILURE
;
398 if (memcached_string_check(&result
->value
,
399 bodylen
) != MEMCACHED_SUCCESS
)
400 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
402 char *vptr
= memcached_string_value_mutable(&result
->value
);
403 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
405 WATCHPOINT_ERROR(rc
);
406 return MEMCACHED_UNKNOWN_READ_FAILURE
;
409 memcached_string_set_length(&result
->value
, bodylen
);
412 case PROTOCOL_BINARY_CMD_INCREMENT
:
413 case PROTOCOL_BINARY_CMD_DECREMENT
:
415 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
416 return MEMCACHED_PROTOCOL_ERROR
;
418 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
420 if ((rc
= memcached_safe_read(ptr
, &val
, sizeof(val
))) != MEMCACHED_SUCCESS
)
422 WATCHPOINT_ERROR(rc
);
423 return MEMCACHED_UNKNOWN_READ_FAILURE
;
427 memcpy(buffer
, &val
, sizeof(val
));
430 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
431 case PROTOCOL_BINARY_CMD_VERSION
:
433 memset(buffer
, 0, buffer_length
);
434 if (bodylen
>= buffer_length
)
436 /* not enough space in buffer.. should not happen... */
437 return MEMCACHED_UNKNOWN_READ_FAILURE
;
439 else if ((rc
= memcached_safe_read(ptr
, buffer
, bodylen
)) != MEMCACHED_SUCCESS
)
441 WATCHPOINT_ERROR(rc
);
442 return MEMCACHED_UNKNOWN_READ_FAILURE
;
446 case PROTOCOL_BINARY_CMD_FLUSH
:
447 case PROTOCOL_BINARY_CMD_QUIT
:
448 case PROTOCOL_BINARY_CMD_SET
:
449 case PROTOCOL_BINARY_CMD_ADD
:
450 case PROTOCOL_BINARY_CMD_REPLACE
:
451 case PROTOCOL_BINARY_CMD_APPEND
:
452 case PROTOCOL_BINARY_CMD_PREPEND
:
453 case PROTOCOL_BINARY_CMD_DELETE
:
455 WATCHPOINT_ASSERT(bodylen
== 0);
456 return MEMCACHED_SUCCESS
;
458 case PROTOCOL_BINARY_CMD_NOOP
:
460 WATCHPOINT_ASSERT(bodylen
== 0);
461 return MEMCACHED_END
;
463 case PROTOCOL_BINARY_CMD_STAT
:
467 return MEMCACHED_END
;
469 else if (bodylen
+ 1 > buffer_length
)
471 /* not enough space in buffer.. should not happen... */
472 return MEMCACHED_UNKNOWN_READ_FAILURE
;
476 size_t keylen
= header
.response
.keylen
;
477 memset(buffer
, 0, buffer_length
);
478 if ((rc
= memcached_safe_read(ptr
, buffer
, keylen
)) != MEMCACHED_SUCCESS
||
479 (rc
= memcached_safe_read(ptr
, buffer
+ keylen
+ 1, bodylen
- keylen
)) != MEMCACHED_SUCCESS
)
481 WATCHPOINT_ERROR(rc
);
482 return MEMCACHED_UNKNOWN_READ_FAILURE
;
488 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
489 case PROTOCOL_BINARY_CMD_SASL_STEP
:
491 memcached_result_reset(result
);
492 result
->item_cas
= header
.response
.cas
;
494 if (memcached_string_check(&result
->value
,
495 bodylen
) != MEMCACHED_SUCCESS
)
496 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
498 char *vptr
= memcached_string_value_mutable(&result
->value
);
499 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
501 WATCHPOINT_ERROR(rc
);
502 return MEMCACHED_UNKNOWN_READ_FAILURE
;
505 memcached_string_set_length(&result
->value
, bodylen
);
510 /* Command not implemented yet! */
511 WATCHPOINT_ASSERT(0);
512 return MEMCACHED_PROTOCOL_ERROR
;
516 else if (header
.response
.bodylen
)
518 /* What should I do with the error message??? just discard it for now */
519 char hole
[SMALL_STRING_LEN
];
522 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
523 if ((rc
= memcached_safe_read(ptr
, hole
, nr
)) != MEMCACHED_SUCCESS
)
525 WATCHPOINT_ERROR(rc
);
526 return MEMCACHED_UNKNOWN_READ_FAILURE
;
528 bodylen
-= (uint32_t) nr
;
531 /* This might be an error from one of the quiet commands.. if
532 * so, just throw it away and get the next one. What about creating
533 * a callback to the user with the error information?
535 switch (header
.response
.opcode
)
537 case PROTOCOL_BINARY_CMD_SETQ
:
538 case PROTOCOL_BINARY_CMD_ADDQ
:
539 case PROTOCOL_BINARY_CMD_REPLACEQ
:
540 case PROTOCOL_BINARY_CMD_APPENDQ
:
541 case PROTOCOL_BINARY_CMD_PREPENDQ
:
542 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
548 rc
= MEMCACHED_SUCCESS
;
549 unlikely(header
.response
.status
!= 0)
550 switch (header
.response
.status
)
552 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
553 rc
= MEMCACHED_NOTFOUND
;
555 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
556 rc
= MEMCACHED_DATA_EXISTS
;
558 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
559 rc
= MEMCACHED_NOTSTORED
;
561 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
564 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
565 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
567 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
568 rc
= MEMCACHED_AUTH_CONTINUE
;
570 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
571 rc
= MEMCACHED_AUTH_FAILURE
;
573 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
574 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
576 /* @todo fix the error mappings */
577 rc
= MEMCACHED_PROTOCOL_ERROR
;