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')
241 return MEMCACHED_SERVER_ERROR
;
242 else if (buffer
[1] == 'T')
243 return MEMCACHED_STORED
;
246 WATCHPOINT_STRING(buffer
);
247 WATCHPOINT_ASSERT(0);
248 return MEMCACHED_UNKNOWN_READ_FAILURE
;
251 case 'D': /* DELETED */
252 return MEMCACHED_DELETED
;
253 case 'N': /* NOT_FOUND */
255 if (buffer
[4] == 'F')
256 return MEMCACHED_NOTFOUND
;
257 else if (buffer
[4] == 'S')
258 return MEMCACHED_NOTSTORED
;
260 return MEMCACHED_UNKNOWN_READ_FAILURE
;
262 case 'E': /* PROTOCOL ERROR or END */
264 if (buffer
[1] == 'N')
265 return MEMCACHED_END
;
266 else if (buffer
[1] == 'R')
267 return MEMCACHED_PROTOCOL_ERROR
;
268 else if (buffer
[1] == 'X')
269 return MEMCACHED_DATA_EXISTS
;
271 return MEMCACHED_UNKNOWN_READ_FAILURE
;
273 case 'C': /* CLIENT ERROR */
274 return MEMCACHED_CLIENT_ERROR
;
277 unsigned long long auto_return_value
;
279 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
280 return MEMCACHED_SUCCESS
;
282 return MEMCACHED_UNKNOWN_READ_FAILURE
;
289 char *memcached_result_value(memcached_result_st
*ptr
)
291 memcached_string_st
*sptr
= &ptr
->value
;
292 return memcached_string_value(sptr
);
295 size_t memcached_result_length(memcached_result_st
*ptr
)
297 memcached_string_st
*sptr
= &ptr
->value
;
298 return memcached_string_length(sptr
);
301 static memcached_return
binary_read_one_response(memcached_server_st
*ptr
,
302 char *buffer
, size_t buffer_length
,
303 memcached_result_st
*result
)
305 protocol_binary_response_header header
;
307 unlikely (memcached_safe_read(ptr
, &header
.bytes
,
308 sizeof(header
.bytes
)) != MEMCACHED_SUCCESS
)
309 return MEMCACHED_UNKNOWN_READ_FAILURE
;
311 unlikely (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
312 return MEMCACHED_PROTOCOL_ERROR
;
315 ** Convert the header to host local endian!
317 header
.response
.keylen
= ntohs(header
.response
.keylen
);
318 header
.response
.status
= ntohs(header
.response
.status
);
319 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
320 header
.response
.cas
= ntohll(header
.response
.cas
);
321 uint32_t bodylen
= header
.response
.bodylen
;
323 if (header
.response
.status
== 0)
325 switch (header
.response
.opcode
)
327 case PROTOCOL_BINARY_CMD_GETK
:
328 case PROTOCOL_BINARY_CMD_GETKQ
:
330 uint16_t keylen
= header
.response
.keylen
;
331 memcached_result_reset(result
);
332 result
->cas
= header
.response
.cas
;
334 if (memcached_safe_read(ptr
, &result
->flags
,
335 sizeof (result
->flags
)) != MEMCACHED_SUCCESS
)
336 return MEMCACHED_UNKNOWN_READ_FAILURE
;
338 result
->flags
= ntohl(result
->flags
);
339 bodylen
-= header
.response
.extlen
;
341 result
->key_length
= keylen
;
342 if (memcached_safe_read(ptr
, result
->key
, keylen
) != MEMCACHED_SUCCESS
)
343 return MEMCACHED_UNKNOWN_READ_FAILURE
;
346 if (memcached_string_check(&result
->value
,
347 bodylen
) != MEMCACHED_SUCCESS
)
348 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
350 char *vptr
= memcached_string_value(&result
->value
);
351 if (memcached_safe_read(ptr
, vptr
, bodylen
) != MEMCACHED_SUCCESS
)
352 return MEMCACHED_UNKNOWN_READ_FAILURE
;
354 memcached_string_set_length(&result
->value
, bodylen
);
357 case PROTOCOL_BINARY_CMD_INCREMENT
:
358 case PROTOCOL_BINARY_CMD_DECREMENT
:
360 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
361 return MEMCACHED_PROTOCOL_ERROR
;
363 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
365 if (memcached_safe_read(ptr
, &val
, sizeof(val
)) != MEMCACHED_SUCCESS
)
366 return MEMCACHED_UNKNOWN_READ_FAILURE
;
369 memcpy(buffer
, &val
, sizeof(val
));
372 case PROTOCOL_BINARY_CMD_VERSION
:
374 memset(buffer
, 0, buffer_length
);
375 if (bodylen
>= buffer_length
)
376 /* not enough space in buffer.. should not happen... */
377 return MEMCACHED_UNKNOWN_READ_FAILURE
;
378 else if (memcached_safe_read(ptr
, buffer
, bodylen
) != MEMCACHED_SUCCESS
)
379 return MEMCACHED_UNKNOWN_READ_FAILURE
;
382 case PROTOCOL_BINARY_CMD_FLUSH
:
383 case PROTOCOL_BINARY_CMD_QUIT
:
384 case PROTOCOL_BINARY_CMD_SET
:
385 case PROTOCOL_BINARY_CMD_ADD
:
386 case PROTOCOL_BINARY_CMD_REPLACE
:
387 case PROTOCOL_BINARY_CMD_APPEND
:
388 case PROTOCOL_BINARY_CMD_PREPEND
:
389 case PROTOCOL_BINARY_CMD_DELETE
:
391 WATCHPOINT_ASSERT(bodylen
== 0);
392 return MEMCACHED_SUCCESS
;
395 case PROTOCOL_BINARY_CMD_NOOP
:
397 WATCHPOINT_ASSERT(bodylen
== 0);
398 return MEMCACHED_END
;
401 case PROTOCOL_BINARY_CMD_STAT
:
404 return MEMCACHED_END
;
405 else if (bodylen
+ 1 > buffer_length
)
406 /* not enough space in buffer.. should not happen... */
407 return MEMCACHED_UNKNOWN_READ_FAILURE
;
410 size_t keylen
= header
.response
.keylen
;
411 memset(buffer
, 0, buffer_length
);
412 if (memcached_safe_read(ptr
, buffer
, keylen
) != MEMCACHED_SUCCESS
||
413 memcached_safe_read(ptr
, buffer
+ keylen
+ 1,
414 bodylen
- keylen
) != MEMCACHED_SUCCESS
)
415 return MEMCACHED_UNKNOWN_READ_FAILURE
;
421 /* Command not implemented yet! */
422 WATCHPOINT_ASSERT(0);
423 return MEMCACHED_PROTOCOL_ERROR
;
427 else if (header
.response
.bodylen
)
429 /* What should I do with the error message??? just discard it for now */
430 char hole
[SMALL_STRING_LEN
];
433 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
434 if (memcached_safe_read(ptr
, hole
, nr
) != MEMCACHED_SUCCESS
)
435 return MEMCACHED_UNKNOWN_READ_FAILURE
;
439 /* This might be an error from one of the quiet commands.. if
440 * so, just throw it away and get the next one. What about creating
441 * a callback to the user with the error information?
443 switch (header
.response
.opcode
)
445 case PROTOCOL_BINARY_CMD_SETQ
:
446 case PROTOCOL_BINARY_CMD_ADDQ
:
447 case PROTOCOL_BINARY_CMD_REPLACEQ
:
448 case PROTOCOL_BINARY_CMD_APPENDQ
:
449 case PROTOCOL_BINARY_CMD_PREPENDQ
:
450 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
456 memcached_return rc
= MEMCACHED_SUCCESS
;
457 unlikely(header
.response
.status
!= 0)
458 switch (header
.response
.status
)
460 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
461 rc
= MEMCACHED_NOTFOUND
;
463 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
464 rc
= MEMCACHED_DATA_EXISTS
;
466 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
467 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
468 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
469 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
470 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
472 /* @todo fix the error mappings */
473 rc
= MEMCACHED_PROTOCOL_ERROR
;