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
;
84 ssize_t read_length
= 0;
85 memcached_return_t rrc
;
87 if (ptr
->root
->flags
.use_udp
)
88 return MEMCACHED_NOT_SUPPORTED
;
90 WATCHPOINT_ASSERT(ptr
->root
);
91 end_ptr
= buffer
+ MEMCACHED_DEFAULT_COMMAND_SIZE
;
93 memcached_result_reset(result
);
96 string_ptr
+= 6; /* "VALUE " */
102 size_t prefix_length
;
105 result
->key_length
= 0;
107 for (prefix_length
= ptr
->root
->prefix_key_length
; !(iscntrl(*string_ptr
) || isspace(*string_ptr
)) ; string_ptr
++)
109 if (prefix_length
== 0)
113 result
->key_length
++;
118 result
->key
[result
->key_length
]= 0;
121 if (end_ptr
== string_ptr
)
124 /* Flags fetch move past space */
126 if (end_ptr
== string_ptr
)
128 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++);
129 result
->flags
= (uint32_t) strtoul(next_ptr
, &string_ptr
, 10);
131 if (end_ptr
== string_ptr
)
134 /* Length fetch move past space*/
136 if (end_ptr
== string_ptr
)
139 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++);
140 value_length
= (size_t)strtoull(next_ptr
, &string_ptr
, 10);
142 if (end_ptr
== string_ptr
)
146 if (*string_ptr
== '\r')
148 /* Skip past the \r\n */
154 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++);
155 result
->cas
= strtoull(next_ptr
, &string_ptr
, 10);
158 if (end_ptr
< string_ptr
)
161 /* We add two bytes so that we can walk the \r\n */
162 rc
= memcached_string_check(&result
->value
, value_length
+2);
163 if (rc
!= MEMCACHED_SUCCESS
)
166 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
169 value_ptr
= memcached_string_value(&result
->value
);
171 We read the \r\n into the string since not doing so is more
172 cycles then the waster of memory to do so.
174 We are null terminating through, which will most likely make
175 some people lazy about using the return length.
177 to_read
= (value_length
) + 2;
178 rrc
= memcached_io_read(ptr
, value_ptr
, to_read
, &read_length
);
179 if (rrc
!= MEMCACHED_SUCCESS
)
182 if (read_length
!= (ssize_t
)(value_length
+ 2))
187 /* This next bit blows the API, but this is internal....*/
190 char_ptr
= memcached_string_value(&result
->value
);;
191 char_ptr
[value_length
]= 0;
192 char_ptr
[value_length
+ 1]= 0;
193 memcached_string_set_length(&result
->value
, value_length
);
196 return MEMCACHED_SUCCESS
;
199 memcached_io_reset(ptr
);
201 return MEMCACHED_PARTIAL_READ
;
204 static memcached_return_t
textual_read_one_response(memcached_server_st
*ptr
,
205 char *buffer
, size_t buffer_length
,
206 memcached_result_st
*result
)
208 memcached_return_t rc
= memcached_io_readline(ptr
, buffer
, buffer_length
);
209 if (rc
!= MEMCACHED_SUCCESS
)
214 case 'V': /* VALUE || VERSION */
215 if (buffer
[1] == 'A') /* VALUE */
217 /* We add back in one because we will need to search for END */
218 memcached_server_response_increment(ptr
);
219 return textual_value_fetch(ptr
, buffer
, result
);
221 else if (buffer
[1] == 'E') /* VERSION */
223 return MEMCACHED_SUCCESS
;
227 WATCHPOINT_STRING(buffer
);
228 WATCHPOINT_ASSERT(0);
229 return MEMCACHED_UNKNOWN_READ_FAILURE
;
232 return MEMCACHED_SUCCESS
;
233 case 'S': /* STORED STATS SERVER_ERROR */
235 if (buffer
[2] == 'A') /* STORED STATS */
237 memcached_server_response_increment(ptr
);
238 return MEMCACHED_STAT
;
240 else if (buffer
[1] == 'E') /* SERVER_ERROR */
243 char *startptr
= buffer
+ 13, *endptr
= startptr
;
245 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
248 Yes, we could make this "efficent" but to do that we would need
249 to maintain more state for the size of the buffer. Why waste
250 memory in the struct, which is important, for something that
251 rarely should happen?
253 rel_ptr
= (char *)ptr
->root
->call_realloc(ptr
->root
,
254 ptr
->cached_server_error
,
255 (size_t) (endptr
- startptr
+ 1));
259 /* If we happened to have some memory, we just null it since we don't know the size */
260 if (ptr
->cached_server_error
)
261 ptr
->cached_server_error
[0]= 0;
262 return MEMCACHED_SERVER_ERROR
;
264 ptr
->cached_server_error
= rel_ptr
;
266 memcpy(ptr
->cached_server_error
, startptr
, (size_t) (endptr
- startptr
));
267 ptr
->cached_server_error
[endptr
- startptr
]= 0;
268 return MEMCACHED_SERVER_ERROR
;
270 else if (buffer
[1] == 'T')
271 return MEMCACHED_STORED
;
274 WATCHPOINT_STRING(buffer
);
275 WATCHPOINT_ASSERT(0);
276 return MEMCACHED_UNKNOWN_READ_FAILURE
;
279 case 'D': /* DELETED */
280 return MEMCACHED_DELETED
;
281 case 'N': /* NOT_FOUND */
283 if (buffer
[4] == 'F')
284 return MEMCACHED_NOTFOUND
;
285 else if (buffer
[4] == 'S')
286 return MEMCACHED_NOTSTORED
;
288 return MEMCACHED_UNKNOWN_READ_FAILURE
;
290 case 'E': /* PROTOCOL ERROR or END */
292 if (buffer
[1] == 'N')
293 return MEMCACHED_END
;
294 else if (buffer
[1] == 'R')
295 return MEMCACHED_PROTOCOL_ERROR
;
296 else if (buffer
[1] == 'X')
297 return MEMCACHED_DATA_EXISTS
;
299 return MEMCACHED_UNKNOWN_READ_FAILURE
;
301 case 'I': /* CLIENT ERROR */
302 /* We add back in one because we will need to search for END */
303 memcached_server_response_increment(ptr
);
304 return MEMCACHED_ITEM
;
305 case 'C': /* CLIENT ERROR */
306 return MEMCACHED_CLIENT_ERROR
;
309 unsigned long long auto_return_value
;
311 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
312 return MEMCACHED_SUCCESS
;
314 return MEMCACHED_UNKNOWN_READ_FAILURE
;
321 static memcached_return_t
binary_read_one_response(memcached_server_st
*ptr
,
322 char *buffer
, size_t buffer_length
,
323 memcached_result_st
*result
)
325 protocol_binary_response_header header
;
327 unlikely (memcached_safe_read(ptr
, &header
.bytes
,
328 sizeof(header
.bytes
)) != MEMCACHED_SUCCESS
)
329 return MEMCACHED_UNKNOWN_READ_FAILURE
;
331 unlikely (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
332 return MEMCACHED_PROTOCOL_ERROR
;
335 ** Convert the header to host local endian!
337 header
.response
.keylen
= ntohs(header
.response
.keylen
);
338 header
.response
.status
= ntohs(header
.response
.status
);
339 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
340 header
.response
.cas
= ntohll(header
.response
.cas
);
341 uint32_t bodylen
= header
.response
.bodylen
;
343 if (header
.response
.status
== 0)
345 switch (header
.response
.opcode
)
347 case PROTOCOL_BINARY_CMD_GETKQ
:
349 * We didn't increment the response counter for the GETKQ packet
350 * (only the final NOOP), so we need to increment the counter again.
352 memcached_server_response_increment(ptr
);
354 case PROTOCOL_BINARY_CMD_GETK
:
356 uint16_t keylen
= header
.response
.keylen
;
357 memcached_result_reset(result
);
358 result
->cas
= header
.response
.cas
;
360 if (memcached_safe_read(ptr
, &result
->flags
,
361 sizeof (result
->flags
)) != MEMCACHED_SUCCESS
)
362 return MEMCACHED_UNKNOWN_READ_FAILURE
;
364 result
->flags
= ntohl(result
->flags
);
365 bodylen
-= header
.response
.extlen
;
367 result
->key_length
= keylen
;
368 if (memcached_safe_read(ptr
, result
->key
, keylen
) != MEMCACHED_SUCCESS
)
369 return MEMCACHED_UNKNOWN_READ_FAILURE
;
372 if (memcached_string_check(&result
->value
,
373 bodylen
) != MEMCACHED_SUCCESS
)
374 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
376 char *vptr
= memcached_string_value(&result
->value
);
377 if (memcached_safe_read(ptr
, vptr
, bodylen
) != MEMCACHED_SUCCESS
)
378 return MEMCACHED_UNKNOWN_READ_FAILURE
;
380 memcached_string_set_length(&result
->value
, bodylen
);
383 case PROTOCOL_BINARY_CMD_INCREMENT
:
384 case PROTOCOL_BINARY_CMD_DECREMENT
:
386 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
387 return MEMCACHED_PROTOCOL_ERROR
;
389 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
391 if (memcached_safe_read(ptr
, &val
, sizeof(val
)) != MEMCACHED_SUCCESS
)
392 return MEMCACHED_UNKNOWN_READ_FAILURE
;
395 memcpy(buffer
, &val
, sizeof(val
));
398 case PROTOCOL_BINARY_CMD_VERSION
:
400 memset(buffer
, 0, buffer_length
);
401 if (bodylen
>= buffer_length
)
402 /* not enough space in buffer.. should not happen... */
403 return MEMCACHED_UNKNOWN_READ_FAILURE
;
404 else if (memcached_safe_read(ptr
, buffer
, bodylen
) != MEMCACHED_SUCCESS
)
405 return MEMCACHED_UNKNOWN_READ_FAILURE
;
408 case PROTOCOL_BINARY_CMD_FLUSH
:
409 case PROTOCOL_BINARY_CMD_QUIT
:
410 case PROTOCOL_BINARY_CMD_SET
:
411 case PROTOCOL_BINARY_CMD_ADD
:
412 case PROTOCOL_BINARY_CMD_REPLACE
:
413 case PROTOCOL_BINARY_CMD_APPEND
:
414 case PROTOCOL_BINARY_CMD_PREPEND
:
415 case PROTOCOL_BINARY_CMD_DELETE
:
417 WATCHPOINT_ASSERT(bodylen
== 0);
418 return MEMCACHED_SUCCESS
;
420 case PROTOCOL_BINARY_CMD_NOOP
:
422 WATCHPOINT_ASSERT(bodylen
== 0);
423 return MEMCACHED_END
;
425 case PROTOCOL_BINARY_CMD_STAT
:
428 return MEMCACHED_END
;
429 else if (bodylen
+ 1 > buffer_length
)
430 /* not enough space in buffer.. should not happen... */
431 return MEMCACHED_UNKNOWN_READ_FAILURE
;
434 size_t keylen
= header
.response
.keylen
;
435 memset(buffer
, 0, buffer_length
);
436 if (memcached_safe_read(ptr
, buffer
, keylen
) != MEMCACHED_SUCCESS
||
437 memcached_safe_read(ptr
, buffer
+ keylen
+ 1,
438 bodylen
- keylen
) != MEMCACHED_SUCCESS
)
439 return MEMCACHED_UNKNOWN_READ_FAILURE
;
445 /* Command not implemented yet! */
446 WATCHPOINT_ASSERT(0);
447 return MEMCACHED_PROTOCOL_ERROR
;
451 else if (header
.response
.bodylen
)
453 /* What should I do with the error message??? just discard it for now */
454 char hole
[SMALL_STRING_LEN
];
457 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
458 if (memcached_safe_read(ptr
, hole
, nr
) != MEMCACHED_SUCCESS
)
459 return MEMCACHED_UNKNOWN_READ_FAILURE
;
460 bodylen
-= (uint32_t) nr
;
463 /* This might be an error from one of the quiet commands.. if
464 * so, just throw it away and get the next one. What about creating
465 * a callback to the user with the error information?
467 switch (header
.response
.opcode
)
469 case PROTOCOL_BINARY_CMD_SETQ
:
470 case PROTOCOL_BINARY_CMD_ADDQ
:
471 case PROTOCOL_BINARY_CMD_REPLACEQ
:
472 case PROTOCOL_BINARY_CMD_APPENDQ
:
473 case PROTOCOL_BINARY_CMD_PREPENDQ
:
474 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
480 memcached_return_t rc
= MEMCACHED_SUCCESS
;
481 unlikely(header
.response
.status
!= 0)
482 switch (header
.response
.status
)
484 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
485 rc
= MEMCACHED_NOTFOUND
;
487 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
488 rc
= MEMCACHED_DATA_EXISTS
;
490 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
491 rc
= MEMCACHED_NOTSTORED
;
493 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
496 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
497 rc
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
499 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
500 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
502 /* @todo fix the error mappings */
503 rc
= MEMCACHED_PROTOCOL_ERROR
;