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
= 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')
243 char *startptr
= buffer
+ 13, *endptr
= startptr
;
244 while (*endptr
!= '\r' && *endptr
!= '\n') endptr
++;
245 if (ptr
->cached_server_error
) free(ptr
->cached_server_error
);
246 ptr
->cached_server_error
= malloc(endptr
- startptr
+ 1);
247 memcpy(ptr
->cached_server_error
, startptr
, endptr
- startptr
);
248 ptr
->cached_server_error
[endptr
- startptr
]= 0;
249 return MEMCACHED_SERVER_ERROR
;
251 else if (buffer
[1] == 'T')
252 return MEMCACHED_STORED
;
255 WATCHPOINT_STRING(buffer
);
256 WATCHPOINT_ASSERT(0);
257 return MEMCACHED_UNKNOWN_READ_FAILURE
;
260 case 'D': /* DELETED */
261 return MEMCACHED_DELETED
;
262 case 'N': /* NOT_FOUND */
264 if (buffer
[4] == 'F')
265 return MEMCACHED_NOTFOUND
;
266 else if (buffer
[4] == 'S')
267 return MEMCACHED_NOTSTORED
;
269 return MEMCACHED_UNKNOWN_READ_FAILURE
;
271 case 'E': /* PROTOCOL ERROR or END */
273 if (buffer
[1] == 'N')
274 return MEMCACHED_END
;
275 else if (buffer
[1] == 'R')
276 return MEMCACHED_PROTOCOL_ERROR
;
277 else if (buffer
[1] == 'X')
278 return MEMCACHED_DATA_EXISTS
;
280 return MEMCACHED_UNKNOWN_READ_FAILURE
;
282 case 'I': /* CLIENT ERROR */
283 /* We add back in one because we will need to search for END */
284 memcached_server_response_increment(ptr
);
285 return MEMCACHED_ITEM
;
286 case 'C': /* CLIENT ERROR */
287 return MEMCACHED_CLIENT_ERROR
;
290 unsigned long long auto_return_value
;
292 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
293 return MEMCACHED_SUCCESS
;
295 return MEMCACHED_UNKNOWN_READ_FAILURE
;
302 char *memcached_result_value(memcached_result_st
*ptr
)
304 memcached_string_st
*sptr
= &ptr
->value
;
305 return memcached_string_value(sptr
);
308 size_t memcached_result_length(memcached_result_st
*ptr
)
310 memcached_string_st
*sptr
= &ptr
->value
;
311 return memcached_string_length(sptr
);
314 static memcached_return
binary_read_one_response(memcached_server_st
*ptr
,
315 char *buffer
, size_t buffer_length
,
316 memcached_result_st
*result
)
318 protocol_binary_response_header header
;
320 unlikely (memcached_safe_read(ptr
, &header
.bytes
,
321 sizeof(header
.bytes
)) != MEMCACHED_SUCCESS
)
322 return MEMCACHED_UNKNOWN_READ_FAILURE
;
324 unlikely (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
325 return MEMCACHED_PROTOCOL_ERROR
;
328 ** Convert the header to host local endian!
330 header
.response
.keylen
= ntohs(header
.response
.keylen
);
331 header
.response
.status
= ntohs(header
.response
.status
);
332 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
333 header
.response
.cas
= ntohll(header
.response
.cas
);
334 uint32_t bodylen
= header
.response
.bodylen
;
336 if (header
.response
.status
== 0)
338 switch (header
.response
.opcode
)
340 case PROTOCOL_BINARY_CMD_GETK
:
341 case PROTOCOL_BINARY_CMD_GETKQ
:
343 uint16_t keylen
= header
.response
.keylen
;
344 memcached_result_reset(result
);
345 result
->cas
= header
.response
.cas
;
347 if (memcached_safe_read(ptr
, &result
->flags
,
348 sizeof (result
->flags
)) != MEMCACHED_SUCCESS
)
349 return MEMCACHED_UNKNOWN_READ_FAILURE
;
351 result
->flags
= ntohl(result
->flags
);
352 bodylen
-= header
.response
.extlen
;
354 result
->key_length
= keylen
;
355 if (memcached_safe_read(ptr
, result
->key
, keylen
) != MEMCACHED_SUCCESS
)
356 return MEMCACHED_UNKNOWN_READ_FAILURE
;
359 if (memcached_string_check(&result
->value
,
360 bodylen
) != MEMCACHED_SUCCESS
)
361 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
363 char *vptr
= memcached_string_value(&result
->value
);
364 if (memcached_safe_read(ptr
, vptr
, bodylen
) != MEMCACHED_SUCCESS
)
365 return MEMCACHED_UNKNOWN_READ_FAILURE
;
367 memcached_string_set_length(&result
->value
, bodylen
);
370 case PROTOCOL_BINARY_CMD_INCREMENT
:
371 case PROTOCOL_BINARY_CMD_DECREMENT
:
373 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
374 return MEMCACHED_PROTOCOL_ERROR
;
376 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
378 if (memcached_safe_read(ptr
, &val
, sizeof(val
)) != MEMCACHED_SUCCESS
)
379 return MEMCACHED_UNKNOWN_READ_FAILURE
;
382 memcpy(buffer
, &val
, sizeof(val
));
385 case PROTOCOL_BINARY_CMD_VERSION
:
387 memset(buffer
, 0, buffer_length
);
388 if (bodylen
>= buffer_length
)
389 /* not enough space in buffer.. should not happen... */
390 return MEMCACHED_UNKNOWN_READ_FAILURE
;
391 else if (memcached_safe_read(ptr
, buffer
, bodylen
) != MEMCACHED_SUCCESS
)
392 return MEMCACHED_UNKNOWN_READ_FAILURE
;
395 case PROTOCOL_BINARY_CMD_FLUSH
:
396 case PROTOCOL_BINARY_CMD_QUIT
:
397 case PROTOCOL_BINARY_CMD_SET
:
398 case PROTOCOL_BINARY_CMD_ADD
:
399 case PROTOCOL_BINARY_CMD_REPLACE
:
400 case PROTOCOL_BINARY_CMD_APPEND
:
401 case PROTOCOL_BINARY_CMD_PREPEND
:
402 case PROTOCOL_BINARY_CMD_DELETE
:
404 WATCHPOINT_ASSERT(bodylen
== 0);
405 return MEMCACHED_SUCCESS
;
407 case PROTOCOL_BINARY_CMD_NOOP
:
409 WATCHPOINT_ASSERT(bodylen
== 0);
410 return MEMCACHED_END
;
412 case PROTOCOL_BINARY_CMD_STAT
:
415 return MEMCACHED_END
;
416 else if (bodylen
+ 1 > buffer_length
)
417 /* not enough space in buffer.. should not happen... */
418 return MEMCACHED_UNKNOWN_READ_FAILURE
;
421 size_t keylen
= header
.response
.keylen
;
422 memset(buffer
, 0, buffer_length
);
423 if (memcached_safe_read(ptr
, buffer
, keylen
) != MEMCACHED_SUCCESS
||
424 memcached_safe_read(ptr
, buffer
+ keylen
+ 1,
425 bodylen
- keylen
) != MEMCACHED_SUCCESS
)
426 return MEMCACHED_UNKNOWN_READ_FAILURE
;
432 /* Command not implemented yet! */
433 WATCHPOINT_ASSERT(0);
434 return MEMCACHED_PROTOCOL_ERROR
;
438 else if (header
.response
.bodylen
)
440 /* What should I do with the error message??? just discard it for now */
441 char hole
[SMALL_STRING_LEN
];
444 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
445 if (memcached_safe_read(ptr
, hole
, nr
) != MEMCACHED_SUCCESS
)
446 return MEMCACHED_UNKNOWN_READ_FAILURE
;
450 /* This might be an error from one of the quiet commands.. if
451 * so, just throw it away and get the next one. What about creating
452 * a callback to the user with the error information?
454 switch (header
.response
.opcode
)
456 case PROTOCOL_BINARY_CMD_SETQ
:
457 case PROTOCOL_BINARY_CMD_ADDQ
:
458 case PROTOCOL_BINARY_CMD_REPLACEQ
:
459 case PROTOCOL_BINARY_CMD_APPENDQ
:
460 case PROTOCOL_BINARY_CMD_PREPENDQ
:
461 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
467 memcached_return rc
= MEMCACHED_SUCCESS
;
468 unlikely(header
.response
.status
!= 0)
469 switch (header
.response
.status
)
471 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
472 rc
= MEMCACHED_NOTFOUND
;
474 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
475 rc
= MEMCACHED_DATA_EXISTS
;
477 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
478 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
479 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
480 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
481 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
483 /* @todo fix the error mappings */
484 rc
= MEMCACHED_PROTOCOL_ERROR
;