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_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_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_instance_st
*ptr
,
22 char *buffer
, size_t buffer_length
,
23 memcached_result_st
*result
)
25 memcached_server_response_decrement(ptr
);
28 result
= &ptr
->root
->result
;
30 memcached_return_t rc
;
31 if (ptr
->root
->flags
.binary_protocol
)
32 rc
= binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
34 rc
= textual_read_one_response(ptr
, buffer
, buffer_length
, result
);
36 unlikely(rc
== MEMCACHED_UNKNOWN_READ_FAILURE
||
37 rc
== MEMCACHED_PROTOCOL_ERROR
||
38 rc
== MEMCACHED_CLIENT_ERROR
||
39 rc
== MEMCACHED_MEMORY_ALLOCATION_FAILURE
)
40 memcached_io_reset(ptr
);
45 memcached_return_t
memcached_response(memcached_server_instance_st
*ptr
,
46 char *buffer
, size_t buffer_length
,
47 memcached_result_st
*result
)
49 /* We may have old commands in the buffer not set, first purge */
50 if ((ptr
->root
->flags
.no_block
) && (ptr
->root
->options
.is_processing_input
== false))
52 (void)memcached_io_write(ptr
, NULL
, 0, 1);
56 * The previous implementation purged all pending requests and just
57 * returned the last one. Purge all pending messages to ensure backwards
60 if (ptr
->root
->flags
.binary_protocol
== false)
61 while (memcached_server_response_count(ptr
) > 1)
63 memcached_return_t rc
= memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
65 unlikely (rc
!= MEMCACHED_END
&&
66 rc
!= MEMCACHED_STORED
&&
67 rc
!= MEMCACHED_SUCCESS
&&
68 rc
!= MEMCACHED_STAT
&&
69 rc
!= MEMCACHED_DELETED
&&
70 rc
!= MEMCACHED_NOTFOUND
&&
71 rc
!= MEMCACHED_NOTSTORED
&&
72 rc
!= MEMCACHED_DATA_EXISTS
)
76 return memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
79 static memcached_return_t
textual_value_fetch(memcached_server_instance_st
*ptr
,
81 memcached_result_st
*result
)
83 memcached_return_t rc
= MEMCACHED_SUCCESS
;
90 ssize_t read_length
= 0;
91 memcached_return_t rrc
;
93 if (ptr
->root
->flags
.use_udp
)
94 return MEMCACHED_NOT_SUPPORTED
;
96 WATCHPOINT_ASSERT(ptr
->root
);
97 end_ptr
= buffer
+ MEMCACHED_DEFAULT_COMMAND_SIZE
;
99 memcached_result_reset(result
);
102 string_ptr
+= 6; /* "VALUE " */
105 /* We load the key */
108 size_t prefix_length
;
111 result
->key_length
= 0;
113 for (prefix_length
= ptr
->root
->prefix_key_length
; !(iscntrl(*string_ptr
) || isspace(*string_ptr
)) ; string_ptr
++)
115 if (prefix_length
== 0)
119 result
->key_length
++;
124 result
->key
[result
->key_length
]= 0;
127 if (end_ptr
== string_ptr
)
130 /* Flags fetch move past space */
132 if (end_ptr
== string_ptr
)
134 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++);
135 result
->flags
= (uint32_t) strtoul(next_ptr
, &string_ptr
, 10);
137 if (end_ptr
== string_ptr
)
140 /* Length fetch move past space*/
142 if (end_ptr
== string_ptr
)
145 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++);
146 value_length
= (size_t)strtoull(next_ptr
, &string_ptr
, 10);
148 if (end_ptr
== string_ptr
)
152 if (*string_ptr
== '\r')
154 /* Skip past the \r\n */
160 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++);
161 result
->cas
= strtoull(next_ptr
, &string_ptr
, 10);
164 if (end_ptr
< string_ptr
)
167 /* We add two bytes so that we can walk the \r\n */
168 rc
= memcached_string_check(&result
->value
, value_length
+2);
169 if (rc
!= MEMCACHED_SUCCESS
)
172 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
175 value_ptr
= memcached_string_value(&result
->value
);
177 We read the \r\n into the string since not doing so is more
178 cycles then the waster of memory to do so.
180 We are null terminating through, which will most likely make
181 some people lazy about using the return length.
183 to_read
= (value_length
) + 2;
184 rrc
= memcached_io_read(ptr
, value_ptr
, to_read
, &read_length
);
185 if (rrc
!= MEMCACHED_SUCCESS
)
188 if (read_length
!= (ssize_t
)(value_length
+ 2))
193 /* This next bit blows the API, but this is internal....*/
196 char_ptr
= memcached_string_value(&result
->value
);;
197 char_ptr
[value_length
]= 0;
198 char_ptr
[value_length
+ 1]= 0;
199 memcached_string_set_length(&result
->value
, value_length
);
202 return MEMCACHED_SUCCESS
;
205 memcached_io_reset(ptr
);
207 return MEMCACHED_PARTIAL_READ
;
210 static memcached_return_t
textual_read_one_response(memcached_server_instance_st
*ptr
,
211 char *buffer
, size_t buffer_length
,
212 memcached_result_st
*result
)
214 memcached_return_t rc
= memcached_io_readline(ptr
, buffer
, buffer_length
);
215 if (rc
!= MEMCACHED_SUCCESS
)
220 case 'V': /* VALUE || VERSION */
221 if (buffer
[1] == 'A') /* VALUE */
223 /* We add back in one because we will need to search for END */
224 memcached_server_response_increment(ptr
);
225 return textual_value_fetch(ptr
, buffer
, result
);
227 else if (buffer
[1] == 'E') /* VERSION */
229 return MEMCACHED_SUCCESS
;
233 WATCHPOINT_STRING(buffer
);
234 WATCHPOINT_ASSERT(0);
235 return MEMCACHED_UNKNOWN_READ_FAILURE
;
238 return MEMCACHED_SUCCESS
;
239 case 'S': /* STORED STATS SERVER_ERROR */
241 if (buffer
[2] == 'A') /* STORED STATS */
243 memcached_server_response_increment(ptr
);
244 return MEMCACHED_STAT
;
246 else if (buffer
[1] == 'E') /* SERVER_ERROR */
249 char *startptr
= buffer
+ 13, *endptr
= startptr
;
251 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
254 Yes, we could make this "efficent" but to do that we would need
255 to maintain more state for the size of the buffer. Why waste
256 memory in the struct, which is important, for something that
257 rarely should happen?
259 rel_ptr
= (char *)ptr
->root
->call_realloc(ptr
->root
,
260 ptr
->cached_server_error
,
261 (size_t) (endptr
- startptr
+ 1));
265 /* If we happened to have some memory, we just null it since we don't know the size */
266 if (ptr
->cached_server_error
)
267 ptr
->cached_server_error
[0]= 0;
268 return MEMCACHED_SERVER_ERROR
;
270 ptr
->cached_server_error
= rel_ptr
;
272 memcpy(ptr
->cached_server_error
, startptr
, (size_t) (endptr
- startptr
));
273 ptr
->cached_server_error
[endptr
- startptr
]= 0;
274 return MEMCACHED_SERVER_ERROR
;
276 else if (buffer
[1] == 'T')
277 return MEMCACHED_STORED
;
280 WATCHPOINT_STRING(buffer
);
281 WATCHPOINT_ASSERT(0);
282 return MEMCACHED_UNKNOWN_READ_FAILURE
;
285 case 'D': /* DELETED */
286 return MEMCACHED_DELETED
;
287 case 'N': /* NOT_FOUND */
289 if (buffer
[4] == 'F')
290 return MEMCACHED_NOTFOUND
;
291 else if (buffer
[4] == 'S')
292 return MEMCACHED_NOTSTORED
;
294 return MEMCACHED_UNKNOWN_READ_FAILURE
;
296 case 'E': /* PROTOCOL ERROR or END */
298 if (buffer
[1] == 'N')
299 return MEMCACHED_END
;
300 else if (buffer
[1] == 'R')
301 return MEMCACHED_PROTOCOL_ERROR
;
302 else if (buffer
[1] == 'X')
303 return MEMCACHED_DATA_EXISTS
;
305 return MEMCACHED_UNKNOWN_READ_FAILURE
;
307 case 'I': /* CLIENT ERROR */
308 /* We add back in one because we will need to search for END */
309 memcached_server_response_increment(ptr
);
310 return MEMCACHED_ITEM
;
311 case 'C': /* CLIENT ERROR */
312 return MEMCACHED_CLIENT_ERROR
;
315 unsigned long long auto_return_value
;
317 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
318 return MEMCACHED_SUCCESS
;
320 return MEMCACHED_UNKNOWN_READ_FAILURE
;
327 static memcached_return_t
binary_read_one_response(memcached_server_instance_st
*ptr
,
328 char *buffer
, size_t buffer_length
,
329 memcached_result_st
*result
)
331 protocol_binary_response_header header
;
333 unlikely (memcached_safe_read(ptr
, &header
.bytes
,
334 sizeof(header
.bytes
)) != MEMCACHED_SUCCESS
)
335 return MEMCACHED_UNKNOWN_READ_FAILURE
;
337 unlikely (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
338 return MEMCACHED_PROTOCOL_ERROR
;
341 ** Convert the header to host local endian!
343 header
.response
.keylen
= ntohs(header
.response
.keylen
);
344 header
.response
.status
= ntohs(header
.response
.status
);
345 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
346 header
.response
.cas
= ntohll(header
.response
.cas
);
347 uint32_t bodylen
= header
.response
.bodylen
;
349 if (header
.response
.status
== 0)
351 switch (header
.response
.opcode
)
353 case PROTOCOL_BINARY_CMD_GETKQ
:
355 * We didn't increment the response counter for the GETKQ packet
356 * (only the final NOOP), so we need to increment the counter again.
358 memcached_server_response_increment(ptr
);
360 case PROTOCOL_BINARY_CMD_GETK
:
362 uint16_t keylen
= header
.response
.keylen
;
363 memcached_result_reset(result
);
364 result
->cas
= header
.response
.cas
;
366 if (memcached_safe_read(ptr
, &result
->flags
,
367 sizeof (result
->flags
)) != MEMCACHED_SUCCESS
)
368 return MEMCACHED_UNKNOWN_READ_FAILURE
;
370 result
->flags
= ntohl(result
->flags
);
371 bodylen
-= header
.response
.extlen
;
373 result
->key_length
= keylen
;
374 if (memcached_safe_read(ptr
, result
->key
, keylen
) != MEMCACHED_SUCCESS
)
375 return MEMCACHED_UNKNOWN_READ_FAILURE
;
378 if (memcached_string_check(&result
->value
,
379 bodylen
) != MEMCACHED_SUCCESS
)
380 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
382 char *vptr
= memcached_string_value(&result
->value
);
383 if (memcached_safe_read(ptr
, vptr
, bodylen
) != MEMCACHED_SUCCESS
)
384 return MEMCACHED_UNKNOWN_READ_FAILURE
;
386 memcached_string_set_length(&result
->value
, bodylen
);
389 case PROTOCOL_BINARY_CMD_INCREMENT
:
390 case PROTOCOL_BINARY_CMD_DECREMENT
:
392 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
393 return MEMCACHED_PROTOCOL_ERROR
;
395 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
397 if (memcached_safe_read(ptr
, &val
, sizeof(val
)) != MEMCACHED_SUCCESS
)
398 return MEMCACHED_UNKNOWN_READ_FAILURE
;
401 memcpy(buffer
, &val
, sizeof(val
));
404 case PROTOCOL_BINARY_CMD_VERSION
:
406 memset(buffer
, 0, buffer_length
);
407 if (bodylen
>= buffer_length
)
408 /* not enough space in buffer.. should not happen... */
409 return MEMCACHED_UNKNOWN_READ_FAILURE
;
410 else if (memcached_safe_read(ptr
, buffer
, bodylen
) != MEMCACHED_SUCCESS
)
411 return MEMCACHED_UNKNOWN_READ_FAILURE
;
414 case PROTOCOL_BINARY_CMD_FLUSH
:
415 case PROTOCOL_BINARY_CMD_QUIT
:
416 case PROTOCOL_BINARY_CMD_SET
:
417 case PROTOCOL_BINARY_CMD_ADD
:
418 case PROTOCOL_BINARY_CMD_REPLACE
:
419 case PROTOCOL_BINARY_CMD_APPEND
:
420 case PROTOCOL_BINARY_CMD_PREPEND
:
421 case PROTOCOL_BINARY_CMD_DELETE
:
423 WATCHPOINT_ASSERT(bodylen
== 0);
424 return MEMCACHED_SUCCESS
;
426 case PROTOCOL_BINARY_CMD_NOOP
:
428 WATCHPOINT_ASSERT(bodylen
== 0);
429 return MEMCACHED_END
;
431 case PROTOCOL_BINARY_CMD_STAT
:
434 return MEMCACHED_END
;
435 else if (bodylen
+ 1 > buffer_length
)
436 /* not enough space in buffer.. should not happen... */
437 return MEMCACHED_UNKNOWN_READ_FAILURE
;
440 size_t keylen
= header
.response
.keylen
;
441 memset(buffer
, 0, buffer_length
);
442 if (memcached_safe_read(ptr
, buffer
, keylen
) != MEMCACHED_SUCCESS
||
443 memcached_safe_read(ptr
, buffer
+ keylen
+ 1,
444 bodylen
- keylen
) != MEMCACHED_SUCCESS
)
445 return MEMCACHED_UNKNOWN_READ_FAILURE
;
451 /* Command not implemented yet! */
452 WATCHPOINT_ASSERT(0);
453 return MEMCACHED_PROTOCOL_ERROR
;
457 else if (header
.response
.bodylen
)
459 /* What should I do with the error message??? just discard it for now */
460 char hole
[SMALL_STRING_LEN
];
463 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
464 if (memcached_safe_read(ptr
, hole
, nr
) != MEMCACHED_SUCCESS
)
465 return MEMCACHED_UNKNOWN_READ_FAILURE
;
466 bodylen
-= (uint32_t) nr
;
469 /* This might be an error from one of the quiet commands.. if
470 * so, just throw it away and get the next one. What about creating
471 * a callback to the user with the error information?
473 switch (header
.response
.opcode
)
475 case PROTOCOL_BINARY_CMD_SETQ
:
476 case PROTOCOL_BINARY_CMD_ADDQ
:
477 case PROTOCOL_BINARY_CMD_REPLACEQ
:
478 case PROTOCOL_BINARY_CMD_APPENDQ
:
479 case PROTOCOL_BINARY_CMD_PREPENDQ
:
480 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
486 memcached_return_t rc
= MEMCACHED_SUCCESS
;
487 unlikely(header
.response
.status
!= 0)
488 switch (header
.response
.status
)
490 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
491 rc
= MEMCACHED_NOTFOUND
;
493 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
494 rc
= MEMCACHED_DATA_EXISTS
;
496 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
497 rc
= MEMCACHED_NOTSTORED
;
499 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
502 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
503 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
505 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
506 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
508 /* @todo fix the error mappings */
509 rc
= MEMCACHED_PROTOCOL_ERROR
;