4 memcached_response() is used to determine the return result
5 from an issued command.
9 #include "memcached_io.h"
11 static memcached_return
textual_read_one_response(memcached_server_st
*ptr
,
12 char *buffer
, size_t buffer_length
,
13 memcached_result_st
*result
);
14 static memcached_return
binary_read_one_response(memcached_server_st
*ptr
,
15 char *buffer
, size_t buffer_length
,
16 memcached_result_st
*result
);
18 memcached_return
memcached_read_one_response(memcached_server_st
*ptr
,
19 char *buffer
, size_t buffer_length
,
20 memcached_result_st
*result
)
22 memcached_server_response_decrement(ptr
);
25 result
= &ptr
->root
->result
;
28 if (ptr
->root
->flags
& MEM_BINARY_PROTOCOL
)
29 rc
= binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
31 rc
= textual_read_one_response(ptr
, buffer
, buffer_length
, result
);
33 unlikely(rc
== MEMCACHED_UNKNOWN_READ_FAILURE
||
34 rc
== MEMCACHED_PROTOCOL_ERROR
||
35 rc
== MEMCACHED_CLIENT_ERROR
||
36 rc
== MEMCACHED_MEMORY_ALLOCATION_FAILURE
)
37 memcached_io_reset(ptr
);
42 memcached_return
memcached_response(memcached_server_st
*ptr
,
43 char *buffer
, size_t buffer_length
,
44 memcached_result_st
*result
)
46 /* We may have old commands in the buffer not set, first purge */
47 if (ptr
->root
->flags
& MEM_NO_BLOCK
)
48 (void)memcached_io_write(ptr
, NULL
, 0, 1);
51 * The previous implementation purged all pending requests and just
52 * returned the last one. Purge all pending messages to ensure backwards
55 if ((ptr
->root
->flags
& MEM_BINARY_PROTOCOL
) == 0)
56 while (memcached_server_response_count(ptr
) > 1)
58 memcached_return rc
= memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
60 unlikely (rc
!= MEMCACHED_END
&&
61 rc
!= MEMCACHED_STORED
&&
62 rc
!= MEMCACHED_SUCCESS
&&
63 rc
!= MEMCACHED_STAT
&&
64 rc
!= MEMCACHED_DELETED
&&
65 rc
!= MEMCACHED_NOTFOUND
&&
66 rc
!= MEMCACHED_NOTSTORED
&&
67 rc
!= MEMCACHED_DATA_EXISTS
)
71 return memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
74 static memcached_return
textual_value_fetch(memcached_server_st
*ptr
,
76 memcached_result_st
*result
)
78 memcached_return rc
= MEMCACHED_SUCCESS
;
86 if (ptr
->root
->flags
& MEM_USE_UDP
)
87 return MEMCACHED_NOT_SUPPORTED
;
89 WATCHPOINT_ASSERT(ptr
->root
);
90 end_ptr
= buffer
+ MEMCACHED_DEFAULT_COMMAND_SIZE
;
92 memcached_result_reset(result
);
95 string_ptr
+= 6; /* "VALUE " */
101 size_t prefix_length
;
104 result
->key_length
= 0;
106 for (prefix_length
= ptr
->root
->prefix_key_length
; !(iscntrl(*string_ptr
) || isspace(*string_ptr
)) ; string_ptr
++)
108 if (prefix_length
== 0)
112 result
->key_length
++;
117 result
->key
[result
->key_length
]= 0;
120 if (end_ptr
== string_ptr
)
123 /* Flags fetch move past space */
125 if (end_ptr
== string_ptr
)
127 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++);
128 result
->flags
= (uint32_t) strtoul(next_ptr
, &string_ptr
, 10);
130 if (end_ptr
== string_ptr
)
133 /* Length fetch move past space*/
135 if (end_ptr
== string_ptr
)
138 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++);
139 value_length
= (size_t)strtoull(next_ptr
, &string_ptr
, 10);
141 if (end_ptr
== string_ptr
)
145 if (*string_ptr
== '\r')
147 /* Skip past the \r\n */
153 for (next_ptr
= string_ptr
; isdigit(*string_ptr
); string_ptr
++);
154 result
->cas
= strtoull(next_ptr
, &string_ptr
, 10);
157 if (end_ptr
< string_ptr
)
160 /* We add two bytes so that we can walk the \r\n */
161 rc
= memcached_string_check(&result
->value
, value_length
+2);
162 if (rc
!= MEMCACHED_SUCCESS
)
165 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
168 value_ptr
= memcached_string_value(&result
->value
);
170 We read the \r\n into the string since not doing so is more
171 cycles then the waster of memory to do so.
173 We are null terminating through, which will most likely make
174 some people lazy about using the return length.
176 to_read
= (value_length
) + 2;
177 ssize_t read_length
= 0;
178 memcached_return 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
textual_read_one_response(memcached_server_st
*ptr
,
205 char *buffer
, size_t buffer_length
,
206 memcached_result_st
*result
)
208 memcached_return 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 char *memcached_result_value(memcached_result_st
*ptr
)
323 memcached_string_st
*sptr
= &ptr
->value
;
324 return memcached_string_value(sptr
);
327 size_t memcached_result_length(memcached_result_st
*ptr
)
329 memcached_string_st
*sptr
= &ptr
->value
;
330 return memcached_string_length(sptr
);
333 static memcached_return
binary_read_one_response(memcached_server_st
*ptr
,
334 char *buffer
, size_t buffer_length
,
335 memcached_result_st
*result
)
337 protocol_binary_response_header header
;
339 unlikely (memcached_safe_read(ptr
, &header
.bytes
,
340 sizeof(header
.bytes
)) != MEMCACHED_SUCCESS
)
341 return MEMCACHED_UNKNOWN_READ_FAILURE
;
343 unlikely (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
344 return MEMCACHED_PROTOCOL_ERROR
;
347 ** Convert the header to host local endian!
349 header
.response
.keylen
= ntohs(header
.response
.keylen
);
350 header
.response
.status
= ntohs(header
.response
.status
);
351 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
352 header
.response
.cas
= ntohll(header
.response
.cas
);
353 uint32_t bodylen
= header
.response
.bodylen
;
355 if (header
.response
.status
== 0)
357 switch (header
.response
.opcode
)
359 case PROTOCOL_BINARY_CMD_GETK
:
360 case PROTOCOL_BINARY_CMD_GETKQ
:
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 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_E2BIG
:
497 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
498 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
499 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
500 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
502 /* @todo fix the error mappings */
503 rc
= MEMCACHED_PROTOCOL_ERROR
;