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
;
87 if (ptr
->root
->flags
& MEM_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
= 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
);
172 We read the \r\n into the string since not doing so is more
173 cycles then the waster of memory to do so.
175 We are null terminating through, which will most likely make
176 some people lazy about using the return length.
178 to_read
= (value_length
) + 2;
179 read_length
= memcached_io_read(ptr
, value_ptr
, to_read
);
180 if (read_length
!= (size_t)(value_length
+ 2))
185 /* This next bit blows the API, but this is internal....*/
188 char_ptr
= memcached_string_value(&result
->value
);;
189 char_ptr
[value_length
]= 0;
190 char_ptr
[value_length
+ 1]= 0;
191 memcached_string_set_length(&result
->value
, value_length
);
194 return MEMCACHED_SUCCESS
;
197 memcached_io_reset(ptr
);
199 return MEMCACHED_PARTIAL_READ
;
202 static memcached_return
textual_read_one_response(memcached_server_st
*ptr
,
203 char *buffer
, size_t buffer_length
,
204 memcached_result_st
*result
)
206 memcached_return rc
= memcached_io_readline(ptr
, buffer
, buffer_length
);
207 if (rc
!= MEMCACHED_SUCCESS
)
212 case 'V': /* VALUE || VERSION */
213 if (buffer
[1] == 'A') /* VALUE */
215 /* We add back in one because we will need to search for END */
216 memcached_server_response_increment(ptr
);
217 return textual_value_fetch(ptr
, buffer
, result
);
219 else if (buffer
[1] == 'E') /* VERSION */
221 return MEMCACHED_SUCCESS
;
225 WATCHPOINT_STRING(buffer
);
226 WATCHPOINT_ASSERT(0);
227 return MEMCACHED_UNKNOWN_READ_FAILURE
;
230 return MEMCACHED_SUCCESS
;
231 case 'S': /* STORED STATS SERVER_ERROR */
233 if (buffer
[2] == 'A') /* STORED STATS */
235 memcached_server_response_increment(ptr
);
236 return MEMCACHED_STAT
;
238 else if (buffer
[1] == 'E')
239 return MEMCACHED_SERVER_ERROR
;
240 else if (buffer
[1] == 'T')
241 return MEMCACHED_STORED
;
244 WATCHPOINT_STRING(buffer
);
245 WATCHPOINT_ASSERT(0);
246 return MEMCACHED_UNKNOWN_READ_FAILURE
;
249 case 'D': /* DELETED */
250 return MEMCACHED_DELETED
;
251 case 'N': /* NOT_FOUND */
253 if (buffer
[4] == 'F')
254 return MEMCACHED_NOTFOUND
;
255 else if (buffer
[4] == 'S')
256 return MEMCACHED_NOTSTORED
;
258 return MEMCACHED_UNKNOWN_READ_FAILURE
;
260 case 'E': /* PROTOCOL ERROR or END */
262 if (buffer
[1] == 'N')
263 return MEMCACHED_END
;
264 else if (buffer
[1] == 'R')
265 return MEMCACHED_PROTOCOL_ERROR
;
266 else if (buffer
[1] == 'X')
267 return MEMCACHED_DATA_EXISTS
;
269 return MEMCACHED_UNKNOWN_READ_FAILURE
;
271 case 'C': /* CLIENT ERROR */
272 return MEMCACHED_CLIENT_ERROR
;
275 unsigned long long auto_return_value
;
277 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
278 return MEMCACHED_SUCCESS
;
280 return MEMCACHED_UNKNOWN_READ_FAILURE
;
287 char *memcached_result_value(memcached_result_st
*ptr
)
289 memcached_string_st
*sptr
= &ptr
->value
;
290 return memcached_string_value(sptr
);
293 size_t memcached_result_length(memcached_result_st
*ptr
)
295 memcached_string_st
*sptr
= &ptr
->value
;
296 return memcached_string_length(sptr
);
299 static memcached_return
binary_read_one_response(memcached_server_st
*ptr
,
300 char *buffer
, size_t buffer_length
,
301 memcached_result_st
*result
)
303 protocol_binary_response_header header
;
305 unlikely (memcached_safe_read(ptr
, &header
.bytes
,
306 sizeof(header
.bytes
)) != MEMCACHED_SUCCESS
)
307 return MEMCACHED_UNKNOWN_READ_FAILURE
;
309 unlikely (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
310 return MEMCACHED_PROTOCOL_ERROR
;
313 ** Convert the header to host local endian!
315 header
.response
.keylen
= ntohs(header
.response
.keylen
);
316 header
.response
.status
= ntohs(header
.response
.status
);
317 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
318 header
.response
.cas
= ntohll(header
.response
.cas
);
319 uint32_t bodylen
= header
.response
.bodylen
;
321 if (header
.response
.status
== 0)
323 switch (header
.response
.opcode
)
325 case PROTOCOL_BINARY_CMD_GETK
:
326 case PROTOCOL_BINARY_CMD_GETKQ
:
328 uint16_t keylen
= header
.response
.keylen
;
329 memcached_result_reset(result
);
330 result
->cas
= header
.response
.cas
;
332 if (memcached_safe_read(ptr
, &result
->flags
,
333 sizeof (result
->flags
)) != MEMCACHED_SUCCESS
)
334 return MEMCACHED_UNKNOWN_READ_FAILURE
;
336 result
->flags
= ntohl(result
->flags
);
337 bodylen
-= header
.response
.extlen
;
339 result
->key_length
= keylen
;
340 if (memcached_safe_read(ptr
, result
->key
, keylen
) != MEMCACHED_SUCCESS
)
341 return MEMCACHED_UNKNOWN_READ_FAILURE
;
344 if (memcached_string_check(&result
->value
,
345 bodylen
) != MEMCACHED_SUCCESS
)
346 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
348 char *vptr
= memcached_string_value(&result
->value
);
349 if (memcached_safe_read(ptr
, vptr
, bodylen
) != MEMCACHED_SUCCESS
)
350 return MEMCACHED_UNKNOWN_READ_FAILURE
;
352 memcached_string_set_length(&result
->value
, bodylen
);
355 case PROTOCOL_BINARY_CMD_INCREMENT
:
356 case PROTOCOL_BINARY_CMD_DECREMENT
:
358 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
359 return MEMCACHED_PROTOCOL_ERROR
;
361 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
363 if (memcached_safe_read(ptr
, &val
, sizeof(val
)) != MEMCACHED_SUCCESS
)
364 return MEMCACHED_UNKNOWN_READ_FAILURE
;
367 memcpy(buffer
, &val
, sizeof(val
));
370 case PROTOCOL_BINARY_CMD_VERSION
:
372 memset(buffer
, 0, buffer_length
);
373 if (bodylen
>= buffer_length
)
374 /* not enough space in buffer.. should not happen... */
375 return MEMCACHED_UNKNOWN_READ_FAILURE
;
376 else if (memcached_safe_read(ptr
, buffer
, bodylen
) != MEMCACHED_SUCCESS
)
377 return MEMCACHED_UNKNOWN_READ_FAILURE
;
380 case PROTOCOL_BINARY_CMD_FLUSH
:
381 case PROTOCOL_BINARY_CMD_QUIT
:
382 case PROTOCOL_BINARY_CMD_SET
:
383 case PROTOCOL_BINARY_CMD_ADD
:
384 case PROTOCOL_BINARY_CMD_REPLACE
:
385 case PROTOCOL_BINARY_CMD_APPEND
:
386 case PROTOCOL_BINARY_CMD_PREPEND
:
387 case PROTOCOL_BINARY_CMD_DELETE
:
389 WATCHPOINT_ASSERT(bodylen
== 0);
390 return MEMCACHED_SUCCESS
;
393 case PROTOCOL_BINARY_CMD_NOOP
:
395 WATCHPOINT_ASSERT(bodylen
== 0);
396 return MEMCACHED_END
;
399 case PROTOCOL_BINARY_CMD_STAT
:
402 return MEMCACHED_END
;
403 else if (bodylen
+ 1 > buffer_length
)
404 /* not enough space in buffer.. should not happen... */
405 return MEMCACHED_UNKNOWN_READ_FAILURE
;
408 size_t keylen
= header
.response
.keylen
;
409 memset(buffer
, 0, buffer_length
);
410 if (memcached_safe_read(ptr
, buffer
, keylen
) != MEMCACHED_SUCCESS
||
411 memcached_safe_read(ptr
, buffer
+ keylen
+ 1,
412 bodylen
- keylen
) != MEMCACHED_SUCCESS
)
413 return MEMCACHED_UNKNOWN_READ_FAILURE
;
419 /* Command not implemented yet! */
420 WATCHPOINT_ASSERT(0);
421 return MEMCACHED_PROTOCOL_ERROR
;
425 else if (header
.response
.bodylen
)
427 /* What should I do with the error message??? just discard it for now */
428 char hole
[SMALL_STRING_LEN
];
431 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
432 if (memcached_safe_read(ptr
, hole
, nr
) != MEMCACHED_SUCCESS
)
433 return MEMCACHED_UNKNOWN_READ_FAILURE
;
437 /* This might be an error from one of the quiet commands.. if
438 * so, just throw it away and get the next one. What about creating
439 * a callback to the user with the error information?
441 switch (header
.response
.opcode
)
443 case PROTOCOL_BINARY_CMD_SETQ
:
444 case PROTOCOL_BINARY_CMD_ADDQ
:
445 case PROTOCOL_BINARY_CMD_REPLACEQ
:
446 case PROTOCOL_BINARY_CMD_APPENDQ
:
447 case PROTOCOL_BINARY_CMD_PREPENDQ
:
448 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
454 memcached_return rc
= MEMCACHED_SUCCESS
;
455 unlikely(header
.response
.status
!= 0)
456 switch (header
.response
.status
)
458 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
459 rc
= MEMCACHED_NOTFOUND
;
461 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
462 rc
= MEMCACHED_DATA_EXISTS
;
464 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
465 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
466 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
467 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
468 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
470 /* @todo fix the error mappings */
471 rc
= MEMCACHED_PROTOCOL_ERROR
;