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)
65 while (memcached_server_response_count(ptr
) > 1)
67 memcached_return_t rc
= memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
69 unlikely (rc
!= MEMCACHED_END
&&
70 rc
!= MEMCACHED_STORED
&&
71 rc
!= MEMCACHED_SUCCESS
&&
72 rc
!= MEMCACHED_STAT
&&
73 rc
!= MEMCACHED_DELETED
&&
74 rc
!= MEMCACHED_NOTFOUND
&&
75 rc
!= MEMCACHED_NOTSTORED
&&
76 rc
!= MEMCACHED_DATA_EXISTS
)
81 return memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
84 static memcached_return_t
textual_value_fetch(memcached_server_write_instance_st ptr
,
86 memcached_result_st
*result
)
88 memcached_return_t rc
= MEMCACHED_SUCCESS
;
95 ssize_t read_length
= 0;
96 memcached_return_t rrc
;
98 if (ptr
->root
->flags
.use_udp
)
99 return MEMCACHED_NOT_SUPPORTED
;
101 WATCHPOINT_ASSERT(ptr
->root
);
102 end_ptr
= buffer
+ MEMCACHED_DEFAULT_COMMAND_SIZE
;
104 memcached_result_reset(result
);
107 string_ptr
+= 6; /* "VALUE " */
110 /* We load the key */
113 size_t prefix_length
;
115 key
= result
->item_key
;
116 result
->key_length
= 0;
118 for (prefix_length
= ptr
->root
->prefix_key_length
; !(iscntrl(*string_ptr
) || isspace(*string_ptr
)) ; string_ptr
++)
120 if (prefix_length
== 0)
124 result
->key_length
++;
129 result
->item_key
[result
->key_length
]= 0;
132 if (end_ptr
== string_ptr
)
135 /* Flags fetch move past space */
137 if (end_ptr
== string_ptr
)
139 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++);
140 result
->item_flags
= (uint32_t) strtoul(next_ptr
, &string_ptr
, 10);
142 if (end_ptr
== string_ptr
)
145 /* Length fetch move past space*/
147 if (end_ptr
== string_ptr
)
150 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++);
151 value_length
= (size_t)strtoull(next_ptr
, &string_ptr
, 10);
153 if (end_ptr
== string_ptr
)
157 if (*string_ptr
== '\r')
159 /* Skip past the \r\n */
165 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++);
166 result
->item_cas
= strtoull(next_ptr
, &string_ptr
, 10);
169 if (end_ptr
< string_ptr
)
172 /* We add two bytes so that we can walk the \r\n */
173 rc
= memcached_string_check(&result
->value
, value_length
+2);
174 if (rc
!= MEMCACHED_SUCCESS
)
177 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
180 value_ptr
= memcached_string_value_mutable(&result
->value
);
182 We read the \r\n into the string since not doing so is more
183 cycles then the waster of memory to do so.
185 We are null terminating through, which will most likely make
186 some people lazy about using the return length.
188 to_read
= (value_length
) + 2;
189 rrc
= memcached_io_read(ptr
, value_ptr
, to_read
, &read_length
);
190 if (rrc
!= MEMCACHED_SUCCESS
)
193 if (read_length
!= (ssize_t
)(value_length
+ 2))
198 /* This next bit blows the API, but this is internal....*/
201 char_ptr
= memcached_string_value_mutable(&result
->value
);;
202 char_ptr
[value_length
]= 0;
203 char_ptr
[value_length
+ 1]= 0;
204 memcached_string_set_length(&result
->value
, value_length
);
207 return MEMCACHED_SUCCESS
;
210 memcached_io_reset(ptr
);
212 return MEMCACHED_PARTIAL_READ
;
215 static memcached_return_t
textual_read_one_response(memcached_server_write_instance_st ptr
,
216 char *buffer
, size_t buffer_length
,
217 memcached_result_st
*result
)
219 memcached_return_t rc
= memcached_io_readline(ptr
, buffer
, buffer_length
);
220 if (rc
!= MEMCACHED_SUCCESS
)
225 case 'V': /* VALUE || VERSION */
226 if (buffer
[1] == 'A') /* VALUE */
228 /* We add back in one because we will need to search for END */
229 memcached_server_response_increment(ptr
);
230 return textual_value_fetch(ptr
, buffer
, result
);
232 else if (buffer
[1] == 'E') /* VERSION */
234 return MEMCACHED_SUCCESS
;
238 WATCHPOINT_STRING(buffer
);
239 return MEMCACHED_UNKNOWN_READ_FAILURE
;
242 return MEMCACHED_SUCCESS
;
243 case 'S': /* STORED STATS SERVER_ERROR */
245 if (buffer
[2] == 'A') /* STORED STATS */
247 memcached_server_response_increment(ptr
);
248 return MEMCACHED_STAT
;
250 else if (buffer
[1] == 'E') /* SERVER_ERROR */
253 char *startptr
= buffer
+ 13, *endptr
= startptr
;
255 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
258 Yes, we could make this "efficent" but to do that we would need
259 to maintain more state for the size of the buffer. Why waste
260 memory in the struct, which is important, for something that
261 rarely should happen?
263 rel_ptr
= (char *)libmemcached_realloc(ptr
->root
,
264 ptr
->cached_server_error
,
265 (size_t) (endptr
- startptr
+ 1));
269 /* If we happened to have some memory, we just null it since we don't know the size */
270 if (ptr
->cached_server_error
)
271 ptr
->cached_server_error
[0]= 0;
272 return MEMCACHED_SERVER_ERROR
;
274 ptr
->cached_server_error
= rel_ptr
;
276 memcpy(ptr
->cached_server_error
, startptr
, (size_t) (endptr
- startptr
));
277 ptr
->cached_server_error
[endptr
- startptr
]= 0;
278 return MEMCACHED_SERVER_ERROR
;
280 else if (buffer
[1] == 'T')
281 return MEMCACHED_STORED
;
284 WATCHPOINT_STRING(buffer
);
285 return MEMCACHED_UNKNOWN_READ_FAILURE
;
288 case 'D': /* DELETED */
289 return MEMCACHED_DELETED
;
290 case 'N': /* NOT_FOUND */
292 if (buffer
[4] == 'F')
293 return MEMCACHED_NOTFOUND
;
294 else if (buffer
[4] == 'S')
295 return MEMCACHED_NOTSTORED
;
298 WATCHPOINT_STRING(buffer
);
299 return MEMCACHED_UNKNOWN_READ_FAILURE
;
302 case 'E': /* PROTOCOL ERROR or END */
304 if (buffer
[1] == 'N')
305 return MEMCACHED_END
;
306 else if (buffer
[1] == 'R')
307 return MEMCACHED_PROTOCOL_ERROR
;
308 else if (buffer
[1] == 'X')
309 return MEMCACHED_DATA_EXISTS
;
312 WATCHPOINT_STRING(buffer
);
313 return MEMCACHED_UNKNOWN_READ_FAILURE
;
317 case 'I': /* CLIENT ERROR */
318 /* We add back in one because we will need to search for END */
319 memcached_server_response_increment(ptr
);
320 return MEMCACHED_ITEM
;
321 case 'C': /* CLIENT ERROR */
322 return MEMCACHED_CLIENT_ERROR
;
325 unsigned long long auto_return_value
;
327 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
328 return MEMCACHED_SUCCESS
;
330 WATCHPOINT_STRING(buffer
);
331 return MEMCACHED_UNKNOWN_READ_FAILURE
;
338 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
339 char *buffer
, size_t buffer_length
,
340 memcached_result_st
*result
)
342 memcached_return_t rc
;
343 protocol_binary_response_header header
;
345 if ((rc
= memcached_safe_read(ptr
, &header
.bytes
, sizeof(header
.bytes
))) != MEMCACHED_SUCCESS
)
347 WATCHPOINT_ERROR(rc
);
351 if (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
353 return MEMCACHED_PROTOCOL_ERROR
;
357 ** Convert the header to host local endian!
359 header
.response
.keylen
= ntohs(header
.response
.keylen
);
360 header
.response
.status
= ntohs(header
.response
.status
);
361 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
362 header
.response
.cas
= ntohll(header
.response
.cas
);
363 uint32_t bodylen
= header
.response
.bodylen
;
365 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
||
366 header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
368 switch (header
.response
.opcode
)
370 case PROTOCOL_BINARY_CMD_GETKQ
:
372 * We didn't increment the response counter for the GETKQ packet
373 * (only the final NOOP), so we need to increment the counter again.
375 memcached_server_response_increment(ptr
);
377 case PROTOCOL_BINARY_CMD_GETK
:
379 uint16_t keylen
= header
.response
.keylen
;
380 memcached_result_reset(result
);
381 result
->item_cas
= header
.response
.cas
;
383 if ((rc
= memcached_safe_read(ptr
, &result
->item_flags
, sizeof (result
->item_flags
))) != MEMCACHED_SUCCESS
)
385 WATCHPOINT_ERROR(rc
);
386 return MEMCACHED_UNKNOWN_READ_FAILURE
;
389 result
->item_flags
= ntohl(result
->item_flags
);
390 bodylen
-= header
.response
.extlen
;
392 result
->key_length
= keylen
;
393 if ((rc
= memcached_safe_read(ptr
, result
->item_key
, keylen
)) != MEMCACHED_SUCCESS
)
395 WATCHPOINT_ERROR(rc
);
396 return MEMCACHED_UNKNOWN_READ_FAILURE
;
400 if (memcached_string_check(&result
->value
,
401 bodylen
) != MEMCACHED_SUCCESS
)
402 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
404 char *vptr
= memcached_string_value_mutable(&result
->value
);
405 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
407 WATCHPOINT_ERROR(rc
);
408 return MEMCACHED_UNKNOWN_READ_FAILURE
;
411 memcached_string_set_length(&result
->value
, bodylen
);
414 case PROTOCOL_BINARY_CMD_INCREMENT
:
415 case PROTOCOL_BINARY_CMD_DECREMENT
:
417 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
418 return MEMCACHED_PROTOCOL_ERROR
;
420 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
422 if ((rc
= memcached_safe_read(ptr
, &val
, sizeof(val
))) != MEMCACHED_SUCCESS
)
424 WATCHPOINT_ERROR(rc
);
425 return MEMCACHED_UNKNOWN_READ_FAILURE
;
429 memcpy(buffer
, &val
, sizeof(val
));
432 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
433 case PROTOCOL_BINARY_CMD_VERSION
:
435 memset(buffer
, 0, buffer_length
);
436 if (bodylen
>= buffer_length
)
438 /* not enough space in buffer.. should not happen... */
439 return MEMCACHED_UNKNOWN_READ_FAILURE
;
441 else if ((rc
= memcached_safe_read(ptr
, buffer
, bodylen
)) != MEMCACHED_SUCCESS
)
443 WATCHPOINT_ERROR(rc
);
444 return MEMCACHED_UNKNOWN_READ_FAILURE
;
448 case PROTOCOL_BINARY_CMD_FLUSH
:
449 case PROTOCOL_BINARY_CMD_QUIT
:
450 case PROTOCOL_BINARY_CMD_SET
:
451 case PROTOCOL_BINARY_CMD_ADD
:
452 case PROTOCOL_BINARY_CMD_REPLACE
:
453 case PROTOCOL_BINARY_CMD_APPEND
:
454 case PROTOCOL_BINARY_CMD_PREPEND
:
455 case PROTOCOL_BINARY_CMD_DELETE
:
457 WATCHPOINT_ASSERT(bodylen
== 0);
458 return MEMCACHED_SUCCESS
;
460 case PROTOCOL_BINARY_CMD_NOOP
:
462 WATCHPOINT_ASSERT(bodylen
== 0);
463 return MEMCACHED_END
;
465 case PROTOCOL_BINARY_CMD_STAT
:
469 return MEMCACHED_END
;
471 else if (bodylen
+ 1 > buffer_length
)
473 /* not enough space in buffer.. should not happen... */
474 return MEMCACHED_UNKNOWN_READ_FAILURE
;
478 size_t keylen
= header
.response
.keylen
;
479 memset(buffer
, 0, buffer_length
);
480 if ((rc
= memcached_safe_read(ptr
, buffer
, keylen
)) != MEMCACHED_SUCCESS
||
481 (rc
= memcached_safe_read(ptr
, buffer
+ keylen
+ 1, bodylen
- keylen
)) != MEMCACHED_SUCCESS
)
483 WATCHPOINT_ERROR(rc
);
484 return MEMCACHED_UNKNOWN_READ_FAILURE
;
490 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
491 case PROTOCOL_BINARY_CMD_SASL_STEP
:
493 memcached_result_reset(result
);
494 result
->item_cas
= header
.response
.cas
;
496 if (memcached_string_check(&result
->value
,
497 bodylen
) != MEMCACHED_SUCCESS
)
498 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
500 char *vptr
= memcached_string_value_mutable(&result
->value
);
501 if ((rc
= memcached_safe_read(ptr
, vptr
, bodylen
)) != MEMCACHED_SUCCESS
)
503 WATCHPOINT_ERROR(rc
);
504 return MEMCACHED_UNKNOWN_READ_FAILURE
;
507 memcached_string_set_length(&result
->value
, bodylen
);
512 /* Command not implemented yet! */
513 WATCHPOINT_ASSERT(0);
514 return MEMCACHED_PROTOCOL_ERROR
;
518 else if (header
.response
.bodylen
)
520 /* What should I do with the error message??? just discard it for now */
521 char hole
[SMALL_STRING_LEN
];
524 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
525 if ((rc
= memcached_safe_read(ptr
, hole
, nr
)) != MEMCACHED_SUCCESS
)
527 WATCHPOINT_ERROR(rc
);
528 return MEMCACHED_UNKNOWN_READ_FAILURE
;
530 bodylen
-= (uint32_t) nr
;
533 /* This might be an error from one of the quiet commands.. if
534 * so, just throw it away and get the next one. What about creating
535 * a callback to the user with the error information?
537 switch (header
.response
.opcode
)
539 case PROTOCOL_BINARY_CMD_SETQ
:
540 case PROTOCOL_BINARY_CMD_ADDQ
:
541 case PROTOCOL_BINARY_CMD_REPLACEQ
:
542 case PROTOCOL_BINARY_CMD_APPENDQ
:
543 case PROTOCOL_BINARY_CMD_PREPENDQ
:
544 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
550 rc
= MEMCACHED_SUCCESS
;
551 unlikely(header
.response
.status
!= 0)
552 switch (header
.response
.status
)
554 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
555 rc
= MEMCACHED_NOTFOUND
;
557 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
558 rc
= MEMCACHED_DATA_EXISTS
;
560 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
561 rc
= MEMCACHED_NOTSTORED
;
563 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
566 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
567 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
569 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
570 rc
= MEMCACHED_AUTH_CONTINUE
;
572 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
573 rc
= MEMCACHED_AUTH_FAILURE
;
575 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
576 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
578 /* @todo fix the error mappings */
579 rc
= MEMCACHED_PROTOCOL_ERROR
;