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 static memcached_return_t
binary_read_one_response(memcached_server_st
*ptr
,
321 char *buffer
, size_t buffer_length
,
322 memcached_result_st
*result
)
324 protocol_binary_response_header header
;
326 unlikely (memcached_safe_read(ptr
, &header
.bytes
,
327 sizeof(header
.bytes
)) != MEMCACHED_SUCCESS
)
328 return MEMCACHED_UNKNOWN_READ_FAILURE
;
330 unlikely (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
331 return MEMCACHED_PROTOCOL_ERROR
;
334 ** Convert the header to host local endian!
336 header
.response
.keylen
= ntohs(header
.response
.keylen
);
337 header
.response
.status
= ntohs(header
.response
.status
);
338 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
339 header
.response
.cas
= ntohll(header
.response
.cas
);
340 uint32_t bodylen
= header
.response
.bodylen
;
342 if (header
.response
.status
== 0)
344 switch (header
.response
.opcode
)
346 case PROTOCOL_BINARY_CMD_GETKQ
:
348 * We didn't increment the response counter for the GETKQ packet
349 * (only the final NOOP), so we need to increment the counter again.
351 memcached_server_response_increment(ptr
);
353 case PROTOCOL_BINARY_CMD_GETK
:
355 uint16_t keylen
= header
.response
.keylen
;
356 memcached_result_reset(result
);
357 result
->cas
= header
.response
.cas
;
359 if (memcached_safe_read(ptr
, &result
->flags
,
360 sizeof (result
->flags
)) != MEMCACHED_SUCCESS
)
361 return MEMCACHED_UNKNOWN_READ_FAILURE
;
363 result
->flags
= ntohl(result
->flags
);
364 bodylen
-= header
.response
.extlen
;
366 result
->key_length
= keylen
;
367 if (memcached_safe_read(ptr
, result
->key
, keylen
) != MEMCACHED_SUCCESS
)
368 return MEMCACHED_UNKNOWN_READ_FAILURE
;
371 if (memcached_string_check(&result
->value
,
372 bodylen
) != MEMCACHED_SUCCESS
)
373 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
375 char *vptr
= memcached_string_value(&result
->value
);
376 if (memcached_safe_read(ptr
, vptr
, bodylen
) != MEMCACHED_SUCCESS
)
377 return MEMCACHED_UNKNOWN_READ_FAILURE
;
379 memcached_string_set_length(&result
->value
, bodylen
);
382 case PROTOCOL_BINARY_CMD_INCREMENT
:
383 case PROTOCOL_BINARY_CMD_DECREMENT
:
385 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
386 return MEMCACHED_PROTOCOL_ERROR
;
388 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
390 if (memcached_safe_read(ptr
, &val
, sizeof(val
)) != MEMCACHED_SUCCESS
)
391 return MEMCACHED_UNKNOWN_READ_FAILURE
;
394 memcpy(buffer
, &val
, sizeof(val
));
397 case PROTOCOL_BINARY_CMD_VERSION
:
399 memset(buffer
, 0, buffer_length
);
400 if (bodylen
>= buffer_length
)
401 /* not enough space in buffer.. should not happen... */
402 return MEMCACHED_UNKNOWN_READ_FAILURE
;
403 else if (memcached_safe_read(ptr
, buffer
, bodylen
) != MEMCACHED_SUCCESS
)
404 return MEMCACHED_UNKNOWN_READ_FAILURE
;
407 case PROTOCOL_BINARY_CMD_FLUSH
:
408 case PROTOCOL_BINARY_CMD_QUIT
:
409 case PROTOCOL_BINARY_CMD_SET
:
410 case PROTOCOL_BINARY_CMD_ADD
:
411 case PROTOCOL_BINARY_CMD_REPLACE
:
412 case PROTOCOL_BINARY_CMD_APPEND
:
413 case PROTOCOL_BINARY_CMD_PREPEND
:
414 case PROTOCOL_BINARY_CMD_DELETE
:
416 WATCHPOINT_ASSERT(bodylen
== 0);
417 return MEMCACHED_SUCCESS
;
419 case PROTOCOL_BINARY_CMD_NOOP
:
421 WATCHPOINT_ASSERT(bodylen
== 0);
422 return MEMCACHED_END
;
424 case PROTOCOL_BINARY_CMD_STAT
:
427 return MEMCACHED_END
;
428 else if (bodylen
+ 1 > buffer_length
)
429 /* not enough space in buffer.. should not happen... */
430 return MEMCACHED_UNKNOWN_READ_FAILURE
;
433 size_t keylen
= header
.response
.keylen
;
434 memset(buffer
, 0, buffer_length
);
435 if (memcached_safe_read(ptr
, buffer
, keylen
) != MEMCACHED_SUCCESS
||
436 memcached_safe_read(ptr
, buffer
+ keylen
+ 1,
437 bodylen
- keylen
) != MEMCACHED_SUCCESS
)
438 return MEMCACHED_UNKNOWN_READ_FAILURE
;
444 /* Command not implemented yet! */
445 WATCHPOINT_ASSERT(0);
446 return MEMCACHED_PROTOCOL_ERROR
;
450 else if (header
.response
.bodylen
)
452 /* What should I do with the error message??? just discard it for now */
453 char hole
[SMALL_STRING_LEN
];
456 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
457 if (memcached_safe_read(ptr
, hole
, nr
) != MEMCACHED_SUCCESS
)
458 return MEMCACHED_UNKNOWN_READ_FAILURE
;
459 bodylen
-= (uint32_t) nr
;
462 /* This might be an error from one of the quiet commands.. if
463 * so, just throw it away and get the next one. What about creating
464 * a callback to the user with the error information?
466 switch (header
.response
.opcode
)
468 case PROTOCOL_BINARY_CMD_SETQ
:
469 case PROTOCOL_BINARY_CMD_ADDQ
:
470 case PROTOCOL_BINARY_CMD_REPLACEQ
:
471 case PROTOCOL_BINARY_CMD_APPENDQ
:
472 case PROTOCOL_BINARY_CMD_PREPENDQ
:
473 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
479 memcached_return_t rc
= MEMCACHED_SUCCESS
;
480 unlikely(header
.response
.status
!= 0)
481 switch (header
.response
.status
)
483 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
484 rc
= MEMCACHED_NOTFOUND
;
486 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
487 rc
= MEMCACHED_DATA_EXISTS
;
489 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
490 rc
= MEMCACHED_NOTSTORED
;
492 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
495 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
496 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
498 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
499 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
501 /* @todo fix the error mappings */
502 rc
= MEMCACHED_PROTOCOL_ERROR
;