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 WATCHPOINT_ASSERT(0);
238 return MEMCACHED_UNKNOWN_READ_FAILURE
;
241 return MEMCACHED_SUCCESS
;
242 case 'S': /* STORED STATS SERVER_ERROR */
244 if (buffer
[2] == 'A') /* STORED STATS */
246 memcached_server_response_increment(ptr
);
247 return MEMCACHED_STAT
;
249 else if (buffer
[1] == 'E') /* SERVER_ERROR */
252 char *startptr
= buffer
+ 13, *endptr
= startptr
;
254 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
257 Yes, we could make this "efficent" but to do that we would need
258 to maintain more state for the size of the buffer. Why waste
259 memory in the struct, which is important, for something that
260 rarely should happen?
262 rel_ptr
= (char *)libmemcached_realloc(ptr
->root
,
263 ptr
->cached_server_error
,
264 (size_t) (endptr
- startptr
+ 1));
268 /* If we happened to have some memory, we just null it since we don't know the size */
269 if (ptr
->cached_server_error
)
270 ptr
->cached_server_error
[0]= 0;
271 return MEMCACHED_SERVER_ERROR
;
273 ptr
->cached_server_error
= rel_ptr
;
275 memcpy(ptr
->cached_server_error
, startptr
, (size_t) (endptr
- startptr
));
276 ptr
->cached_server_error
[endptr
- startptr
]= 0;
277 return MEMCACHED_SERVER_ERROR
;
279 else if (buffer
[1] == 'T')
280 return MEMCACHED_STORED
;
283 WATCHPOINT_STRING(buffer
);
284 WATCHPOINT_ASSERT(0);
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
;
297 return MEMCACHED_UNKNOWN_READ_FAILURE
;
299 case 'E': /* PROTOCOL ERROR or END */
301 if (buffer
[1] == 'N')
302 return MEMCACHED_END
;
303 else if (buffer
[1] == 'R')
304 return MEMCACHED_PROTOCOL_ERROR
;
305 else if (buffer
[1] == 'X')
306 return MEMCACHED_DATA_EXISTS
;
308 return MEMCACHED_UNKNOWN_READ_FAILURE
;
310 case 'I': /* CLIENT ERROR */
311 /* We add back in one because we will need to search for END */
312 memcached_server_response_increment(ptr
);
313 return MEMCACHED_ITEM
;
314 case 'C': /* CLIENT ERROR */
315 return MEMCACHED_CLIENT_ERROR
;
318 unsigned long long auto_return_value
;
320 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
321 return MEMCACHED_SUCCESS
;
323 return MEMCACHED_UNKNOWN_READ_FAILURE
;
330 static memcached_return_t
binary_read_one_response(memcached_server_write_instance_st ptr
,
331 char *buffer
, size_t buffer_length
,
332 memcached_result_st
*result
)
334 protocol_binary_response_header header
;
336 unlikely (memcached_safe_read(ptr
, &header
.bytes
,
337 sizeof(header
.bytes
)) != MEMCACHED_SUCCESS
)
338 return MEMCACHED_UNKNOWN_READ_FAILURE
;
340 unlikely (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
341 return MEMCACHED_PROTOCOL_ERROR
;
344 ** Convert the header to host local endian!
346 header
.response
.keylen
= ntohs(header
.response
.keylen
);
347 header
.response
.status
= ntohs(header
.response
.status
);
348 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
349 header
.response
.cas
= ntohll(header
.response
.cas
);
350 uint32_t bodylen
= header
.response
.bodylen
;
352 if (header
.response
.status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
||
353 header
.response
.status
== PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
)
355 switch (header
.response
.opcode
)
357 case PROTOCOL_BINARY_CMD_GETKQ
:
359 * We didn't increment the response counter for the GETKQ packet
360 * (only the final NOOP), so we need to increment the counter again.
362 memcached_server_response_increment(ptr
);
364 case PROTOCOL_BINARY_CMD_GETK
:
366 uint16_t keylen
= header
.response
.keylen
;
367 memcached_result_reset(result
);
368 result
->item_cas
= header
.response
.cas
;
370 if (memcached_safe_read(ptr
, &result
->item_flags
,
371 sizeof (result
->item_flags
)) != MEMCACHED_SUCCESS
)
372 return MEMCACHED_UNKNOWN_READ_FAILURE
;
374 result
->item_flags
= ntohl(result
->item_flags
);
375 bodylen
-= header
.response
.extlen
;
377 result
->key_length
= keylen
;
378 if (memcached_safe_read(ptr
, result
->item_key
, keylen
) != MEMCACHED_SUCCESS
)
379 return MEMCACHED_UNKNOWN_READ_FAILURE
;
382 if (memcached_string_check(&result
->value
,
383 bodylen
) != MEMCACHED_SUCCESS
)
384 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
386 char *vptr
= memcached_string_value_mutable(&result
->value
);
387 if (memcached_safe_read(ptr
, vptr
, bodylen
) != MEMCACHED_SUCCESS
)
388 return MEMCACHED_UNKNOWN_READ_FAILURE
;
390 memcached_string_set_length(&result
->value
, bodylen
);
393 case PROTOCOL_BINARY_CMD_INCREMENT
:
394 case PROTOCOL_BINARY_CMD_DECREMENT
:
396 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
397 return MEMCACHED_PROTOCOL_ERROR
;
399 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
401 if (memcached_safe_read(ptr
, &val
, sizeof(val
)) != MEMCACHED_SUCCESS
)
402 return MEMCACHED_UNKNOWN_READ_FAILURE
;
405 memcpy(buffer
, &val
, sizeof(val
));
408 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS
:
409 case PROTOCOL_BINARY_CMD_VERSION
:
411 memset(buffer
, 0, buffer_length
);
412 if (bodylen
>= buffer_length
)
413 /* not enough space in buffer.. should not happen... */
414 return MEMCACHED_UNKNOWN_READ_FAILURE
;
415 else if (memcached_safe_read(ptr
, buffer
, bodylen
) != MEMCACHED_SUCCESS
)
416 return MEMCACHED_UNKNOWN_READ_FAILURE
;
419 case PROTOCOL_BINARY_CMD_FLUSH
:
420 case PROTOCOL_BINARY_CMD_QUIT
:
421 case PROTOCOL_BINARY_CMD_SET
:
422 case PROTOCOL_BINARY_CMD_ADD
:
423 case PROTOCOL_BINARY_CMD_REPLACE
:
424 case PROTOCOL_BINARY_CMD_APPEND
:
425 case PROTOCOL_BINARY_CMD_PREPEND
:
426 case PROTOCOL_BINARY_CMD_DELETE
:
428 WATCHPOINT_ASSERT(bodylen
== 0);
429 return MEMCACHED_SUCCESS
;
431 case PROTOCOL_BINARY_CMD_NOOP
:
433 WATCHPOINT_ASSERT(bodylen
== 0);
434 return MEMCACHED_END
;
436 case PROTOCOL_BINARY_CMD_STAT
:
439 return MEMCACHED_END
;
440 else if (bodylen
+ 1 > buffer_length
)
441 /* not enough space in buffer.. should not happen... */
442 return MEMCACHED_UNKNOWN_READ_FAILURE
;
445 size_t keylen
= header
.response
.keylen
;
446 memset(buffer
, 0, buffer_length
);
447 if (memcached_safe_read(ptr
, buffer
, keylen
) != MEMCACHED_SUCCESS
||
448 memcached_safe_read(ptr
, buffer
+ keylen
+ 1,
449 bodylen
- keylen
) != MEMCACHED_SUCCESS
)
450 return MEMCACHED_UNKNOWN_READ_FAILURE
;
455 case PROTOCOL_BINARY_CMD_SASL_AUTH
:
456 case PROTOCOL_BINARY_CMD_SASL_STEP
:
458 memcached_result_reset(result
);
459 result
->item_cas
= header
.response
.cas
;
461 if (memcached_string_check(&result
->value
,
462 bodylen
) != MEMCACHED_SUCCESS
)
463 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
465 char *vptr
= memcached_string_value_mutable(&result
->value
);
466 if (memcached_safe_read(ptr
, vptr
, bodylen
) != MEMCACHED_SUCCESS
)
467 return MEMCACHED_UNKNOWN_READ_FAILURE
;
469 memcached_string_set_length(&result
->value
, bodylen
);
474 /* Command not implemented yet! */
475 WATCHPOINT_ASSERT(0);
476 return MEMCACHED_PROTOCOL_ERROR
;
480 else if (header
.response
.bodylen
)
482 /* What should I do with the error message??? just discard it for now */
483 char hole
[SMALL_STRING_LEN
];
486 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
487 if (memcached_safe_read(ptr
, hole
, nr
) != MEMCACHED_SUCCESS
)
488 return MEMCACHED_UNKNOWN_READ_FAILURE
;
489 bodylen
-= (uint32_t) nr
;
492 /* This might be an error from one of the quiet commands.. if
493 * so, just throw it away and get the next one. What about creating
494 * a callback to the user with the error information?
496 switch (header
.response
.opcode
)
498 case PROTOCOL_BINARY_CMD_SETQ
:
499 case PROTOCOL_BINARY_CMD_ADDQ
:
500 case PROTOCOL_BINARY_CMD_REPLACEQ
:
501 case PROTOCOL_BINARY_CMD_APPENDQ
:
502 case PROTOCOL_BINARY_CMD_PREPENDQ
:
503 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
509 memcached_return_t rc
= MEMCACHED_SUCCESS
;
510 unlikely(header
.response
.status
!= 0)
511 switch (header
.response
.status
)
513 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
514 rc
= MEMCACHED_NOTFOUND
;
516 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
517 rc
= MEMCACHED_DATA_EXISTS
;
519 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
520 rc
= MEMCACHED_NOTSTORED
;
522 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
525 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
526 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
528 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE
:
529 rc
= MEMCACHED_AUTH_CONTINUE
;
531 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR
:
532 rc
= MEMCACHED_AUTH_FAILURE
;
534 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
535 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
537 /* @todo fix the error mappings */
538 rc
= MEMCACHED_PROTOCOL_ERROR
;