4 memcached_response() is used to determine the return result
5 from an issued command.
10 static memcached_return_t
textual_read_one_response(memcached_server_st
*ptr
,
11 char *buffer
, size_t buffer_length
,
12 memcached_result_st
*result
);
13 static memcached_return_t
binary_read_one_response(memcached_server_st
*ptr
,
14 char *buffer
, size_t buffer_length
,
15 memcached_result_st
*result
);
17 memcached_return_t
memcached_read_one_response(memcached_server_st
*ptr
,
18 char *buffer
, size_t buffer_length
,
19 memcached_result_st
*result
)
21 memcached_server_response_decrement(ptr
);
24 result
= &ptr
->root
->result
;
26 memcached_return_t rc
;
27 if (ptr
->root
->flags
.binary_protocol
)
28 rc
= binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
30 rc
= textual_read_one_response(ptr
, buffer
, buffer_length
, result
);
32 unlikely(rc
== MEMCACHED_UNKNOWN_READ_FAILURE
||
33 rc
== MEMCACHED_PROTOCOL_ERROR
||
34 rc
== MEMCACHED_CLIENT_ERROR
||
35 rc
== MEMCACHED_MEMORY_ALLOCATION_FAILURE
)
36 memcached_io_reset(ptr
);
41 memcached_return_t
memcached_response(memcached_server_st
*ptr
,
42 char *buffer
, size_t buffer_length
,
43 memcached_result_st
*result
)
45 /* We may have old commands in the buffer not set, first purge */
46 if (ptr
->root
->flags
.no_block
)
47 (void)memcached_io_write(ptr
, NULL
, 0, 1);
50 * The previous implementation purged all pending requests and just
51 * returned the last one. Purge all pending messages to ensure backwards
54 if (ptr
->root
->flags
.binary_protocol
== false)
55 while (memcached_server_response_count(ptr
) > 1)
57 memcached_return_t rc
= memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
59 unlikely (rc
!= MEMCACHED_END
&&
60 rc
!= MEMCACHED_STORED
&&
61 rc
!= MEMCACHED_SUCCESS
&&
62 rc
!= MEMCACHED_STAT
&&
63 rc
!= MEMCACHED_DELETED
&&
64 rc
!= MEMCACHED_NOTFOUND
&&
65 rc
!= MEMCACHED_NOTSTORED
&&
66 rc
!= MEMCACHED_DATA_EXISTS
)
70 return memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
73 static memcached_return_t
textual_value_fetch(memcached_server_st
*ptr
,
75 memcached_result_st
*result
)
77 memcached_return_t rc
= MEMCACHED_SUCCESS
;
85 if (ptr
->root
->flags
.use_udp
)
86 return MEMCACHED_NOT_SUPPORTED
;
88 WATCHPOINT_ASSERT(ptr
->root
);
89 end_ptr
= buffer
+ MEMCACHED_DEFAULT_COMMAND_SIZE
;
91 memcached_result_reset(result
);
94 string_ptr
+= 6; /* "VALUE " */
100 size_t prefix_length
;
103 result
->key_length
= 0;
105 for (prefix_length
= ptr
->root
->prefix_key_length
; !(iscntrl(*string_ptr
) || isspace(*string_ptr
)) ; string_ptr
++)
107 if (prefix_length
== 0)
111 result
->key_length
++;
116 result
->key
[result
->key_length
]= 0;
119 if (end_ptr
== string_ptr
)
122 /* Flags fetch move past space */
124 if (end_ptr
== string_ptr
)
126 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++);
127 result
->flags
= (uint32_t) strtoul(next_ptr
, &string_ptr
, 10);
129 if (end_ptr
== string_ptr
)
132 /* Length fetch move past space*/
134 if (end_ptr
== string_ptr
)
137 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++);
138 value_length
= (size_t)strtoull(next_ptr
, &string_ptr
, 10);
140 if (end_ptr
== string_ptr
)
144 if (*string_ptr
== '\r')
146 /* Skip past the \r\n */
152 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++);
153 result
->cas
= strtoull(next_ptr
, &string_ptr
, 10);
156 if (end_ptr
< string_ptr
)
159 /* We add two bytes so that we can walk the \r\n */
160 rc
= memcached_string_check(&result
->value
, value_length
+2);
161 if (rc
!= MEMCACHED_SUCCESS
)
164 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
167 value_ptr
= memcached_string_value(&result
->value
);
169 We read the \r\n into the string since not doing so is more
170 cycles then the waster of memory to do so.
172 We are null terminating through, which will most likely make
173 some people lazy about using the return length.
175 to_read
= (value_length
) + 2;
176 ssize_t read_length
= 0;
177 memcached_return_t rrc
= memcached_io_read(ptr
, value_ptr
, to_read
, &read_length
);
178 if (rrc
!= MEMCACHED_SUCCESS
)
181 if (read_length
!= (ssize_t
)(value_length
+ 2))
186 /* This next bit blows the API, but this is internal....*/
189 char_ptr
= memcached_string_value(&result
->value
);;
190 char_ptr
[value_length
]= 0;
191 char_ptr
[value_length
+ 1]= 0;
192 memcached_string_set_length(&result
->value
, value_length
);
195 return MEMCACHED_SUCCESS
;
198 memcached_io_reset(ptr
);
200 return MEMCACHED_PARTIAL_READ
;
203 static memcached_return_t
textual_read_one_response(memcached_server_st
*ptr
,
204 char *buffer
, size_t buffer_length
,
205 memcached_result_st
*result
)
207 memcached_return_t rc
= memcached_io_readline(ptr
, buffer
, buffer_length
);
208 if (rc
!= MEMCACHED_SUCCESS
)
213 case 'V': /* VALUE || VERSION */
214 if (buffer
[1] == 'A') /* VALUE */
216 /* We add back in one because we will need to search for END */
217 memcached_server_response_increment(ptr
);
218 return textual_value_fetch(ptr
, buffer
, result
);
220 else if (buffer
[1] == 'E') /* VERSION */
222 return MEMCACHED_SUCCESS
;
226 WATCHPOINT_STRING(buffer
);
227 WATCHPOINT_ASSERT(0);
228 return MEMCACHED_UNKNOWN_READ_FAILURE
;
231 return MEMCACHED_SUCCESS
;
232 case 'S': /* STORED STATS SERVER_ERROR */
234 if (buffer
[2] == 'A') /* STORED STATS */
236 memcached_server_response_increment(ptr
);
237 return MEMCACHED_STAT
;
239 else if (buffer
[1] == 'E') /* SERVER_ERROR */
242 char *startptr
= buffer
+ 13, *endptr
= startptr
;
244 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
247 Yes, we could make this "efficent" but to do that we would need
248 to maintain more state for the size of the buffer. Why waste
249 memory in the struct, which is important, for something that
250 rarely should happen?
252 rel_ptr
= (char *)ptr
->root
->call_realloc(ptr
->root
,
253 ptr
->cached_server_error
,
254 (size_t) (endptr
- startptr
+ 1));
258 /* If we happened to have some memory, we just null it since we don't know the size */
259 if (ptr
->cached_server_error
)
260 ptr
->cached_server_error
[0]= 0;
261 return MEMCACHED_SERVER_ERROR
;
263 ptr
->cached_server_error
= rel_ptr
;
265 memcpy(ptr
->cached_server_error
, startptr
, (size_t) (endptr
- startptr
));
266 ptr
->cached_server_error
[endptr
- startptr
]= 0;
267 return MEMCACHED_SERVER_ERROR
;
269 else if (buffer
[1] == 'T')
270 return MEMCACHED_STORED
;
273 WATCHPOINT_STRING(buffer
);
274 WATCHPOINT_ASSERT(0);
275 return MEMCACHED_UNKNOWN_READ_FAILURE
;
278 case 'D': /* DELETED */
279 return MEMCACHED_DELETED
;
280 case 'N': /* NOT_FOUND */
282 if (buffer
[4] == 'F')
283 return MEMCACHED_NOTFOUND
;
284 else if (buffer
[4] == 'S')
285 return MEMCACHED_NOTSTORED
;
287 return MEMCACHED_UNKNOWN_READ_FAILURE
;
289 case 'E': /* PROTOCOL ERROR or END */
291 if (buffer
[1] == 'N')
292 return MEMCACHED_END
;
293 else if (buffer
[1] == 'R')
294 return MEMCACHED_PROTOCOL_ERROR
;
295 else if (buffer
[1] == 'X')
296 return MEMCACHED_DATA_EXISTS
;
298 return MEMCACHED_UNKNOWN_READ_FAILURE
;
300 case 'I': /* CLIENT ERROR */
301 /* We add back in one because we will need to search for END */
302 memcached_server_response_increment(ptr
);
303 return MEMCACHED_ITEM
;
304 case 'C': /* CLIENT ERROR */
305 return MEMCACHED_CLIENT_ERROR
;
308 unsigned long long auto_return_value
;
310 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
311 return MEMCACHED_SUCCESS
;
313 return MEMCACHED_UNKNOWN_READ_FAILURE
;
320 char *memcached_result_value(memcached_result_st
*ptr
)
322 memcached_string_st
*sptr
= &ptr
->value
;
323 return memcached_string_value(sptr
);
326 size_t memcached_result_length(memcached_result_st
*ptr
)
328 memcached_string_st
*sptr
= &ptr
->value
;
329 return memcached_string_length(sptr
);
332 static memcached_return_t
binary_read_one_response(memcached_server_st
*ptr
,
333 char *buffer
, size_t buffer_length
,
334 memcached_result_st
*result
)
336 protocol_binary_response_header header
;
338 unlikely (memcached_safe_read(ptr
, &header
.bytes
,
339 sizeof(header
.bytes
)) != MEMCACHED_SUCCESS
)
340 return MEMCACHED_UNKNOWN_READ_FAILURE
;
342 unlikely (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
343 return MEMCACHED_PROTOCOL_ERROR
;
346 ** Convert the header to host local endian!
348 header
.response
.keylen
= ntohs(header
.response
.keylen
);
349 header
.response
.status
= ntohs(header
.response
.status
);
350 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
351 header
.response
.cas
= ntohll(header
.response
.cas
);
352 uint32_t bodylen
= header
.response
.bodylen
;
354 if (header
.response
.status
== 0)
356 switch (header
.response
.opcode
)
358 case PROTOCOL_BINARY_CMD_GETKQ
:
360 * We didn't increment the response counter for the GETKQ packet
361 * (only the final NOOP), so we need to increment the counter again.
363 memcached_server_response_increment(ptr
);
365 case PROTOCOL_BINARY_CMD_GETK
:
367 uint16_t keylen
= header
.response
.keylen
;
368 memcached_result_reset(result
);
369 result
->cas
= header
.response
.cas
;
371 if (memcached_safe_read(ptr
, &result
->flags
,
372 sizeof (result
->flags
)) != MEMCACHED_SUCCESS
)
373 return MEMCACHED_UNKNOWN_READ_FAILURE
;
375 result
->flags
= ntohl(result
->flags
);
376 bodylen
-= header
.response
.extlen
;
378 result
->key_length
= keylen
;
379 if (memcached_safe_read(ptr
, result
->key
, keylen
) != MEMCACHED_SUCCESS
)
380 return MEMCACHED_UNKNOWN_READ_FAILURE
;
383 if (memcached_string_check(&result
->value
,
384 bodylen
) != MEMCACHED_SUCCESS
)
385 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
387 char *vptr
= memcached_string_value(&result
->value
);
388 if (memcached_safe_read(ptr
, vptr
, bodylen
) != MEMCACHED_SUCCESS
)
389 return MEMCACHED_UNKNOWN_READ_FAILURE
;
391 memcached_string_set_length(&result
->value
, bodylen
);
394 case PROTOCOL_BINARY_CMD_INCREMENT
:
395 case PROTOCOL_BINARY_CMD_DECREMENT
:
397 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
398 return MEMCACHED_PROTOCOL_ERROR
;
400 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
402 if (memcached_safe_read(ptr
, &val
, sizeof(val
)) != MEMCACHED_SUCCESS
)
403 return MEMCACHED_UNKNOWN_READ_FAILURE
;
406 memcpy(buffer
, &val
, sizeof(val
));
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
;
456 /* Command not implemented yet! */
457 WATCHPOINT_ASSERT(0);
458 return MEMCACHED_PROTOCOL_ERROR
;
462 else if (header
.response
.bodylen
)
464 /* What should I do with the error message??? just discard it for now */
465 char hole
[SMALL_STRING_LEN
];
468 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
469 if (memcached_safe_read(ptr
, hole
, nr
) != MEMCACHED_SUCCESS
)
470 return MEMCACHED_UNKNOWN_READ_FAILURE
;
471 bodylen
-= (uint32_t) nr
;
474 /* This might be an error from one of the quiet commands.. if
475 * so, just throw it away and get the next one. What about creating
476 * a callback to the user with the error information?
478 switch (header
.response
.opcode
)
480 case PROTOCOL_BINARY_CMD_SETQ
:
481 case PROTOCOL_BINARY_CMD_ADDQ
:
482 case PROTOCOL_BINARY_CMD_REPLACEQ
:
483 case PROTOCOL_BINARY_CMD_APPENDQ
:
484 case PROTOCOL_BINARY_CMD_PREPENDQ
:
485 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
491 memcached_return_t rc
= MEMCACHED_SUCCESS
;
492 unlikely(header
.response
.status
!= 0)
493 switch (header
.response
.status
)
495 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
496 rc
= MEMCACHED_NOTFOUND
;
498 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
499 rc
= MEMCACHED_DATA_EXISTS
;
501 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
502 rc
= MEMCACHED_NOTSTORED
;
504 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
507 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
508 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
510 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
511 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
513 /* @todo fix the error mappings */
514 rc
= MEMCACHED_PROTOCOL_ERROR
;