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_read_one_response(memcached_server_st
*ptr
,
75 char *buffer
, size_t buffer_length
,
76 memcached_result_st
*result
)
78 memcached_return rc
= memcached_io_readline(ptr
, buffer
, buffer_length
);
79 if (rc
!= MEMCACHED_SUCCESS
)
84 case 'V': /* VALUE || VERSION */
85 if (buffer
[1] == 'A') /* VALUE */
87 /* We add back in one because we will need to search for END */
88 memcached_server_response_increment(ptr
);
89 return value_fetch(ptr
, buffer
, result
);
91 else if (buffer
[1] == 'E') /* VERSION */
93 return MEMCACHED_SUCCESS
;
97 WATCHPOINT_STRING(buffer
);
99 return MEMCACHED_UNKNOWN_READ_FAILURE
;
102 return MEMCACHED_SUCCESS
;
103 case 'S': /* STORED STATS SERVER_ERROR */
105 if (buffer
[2] == 'A') /* STORED STATS */
107 memcached_server_response_increment(ptr
);
108 return MEMCACHED_STAT
;
110 else if (buffer
[1] == 'E')
111 return MEMCACHED_SERVER_ERROR
;
112 else if (buffer
[1] == 'T')
113 return MEMCACHED_STORED
;
116 WATCHPOINT_STRING(buffer
);
117 WATCHPOINT_ASSERT(0);
118 return MEMCACHED_UNKNOWN_READ_FAILURE
;
121 case 'D': /* DELETED */
122 return MEMCACHED_DELETED
;
123 case 'N': /* NOT_FOUND */
125 if (buffer
[4] == 'F')
126 return MEMCACHED_NOTFOUND
;
127 else if (buffer
[4] == 'S')
128 return MEMCACHED_NOTSTORED
;
130 return MEMCACHED_UNKNOWN_READ_FAILURE
;
132 case 'E': /* PROTOCOL ERROR or END */
134 if (buffer
[1] == 'N')
135 return MEMCACHED_END
;
136 else if (buffer
[1] == 'R')
137 return MEMCACHED_PROTOCOL_ERROR
;
138 else if (buffer
[1] == 'X')
139 return MEMCACHED_DATA_EXISTS
;
141 return MEMCACHED_UNKNOWN_READ_FAILURE
;
143 case 'C': /* CLIENT ERROR */
144 return MEMCACHED_CLIENT_ERROR
;
147 unsigned long long auto_return_value
;
149 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
150 return MEMCACHED_SUCCESS
;
152 return MEMCACHED_UNKNOWN_READ_FAILURE
;
159 char *memcached_result_value(memcached_result_st
*ptr
)
161 memcached_string_st
*sptr
= &ptr
->value
;
162 return memcached_string_value(sptr
);
165 size_t memcached_result_length(memcached_result_st
*ptr
)
167 memcached_string_st
*sptr
= &ptr
->value
;
168 return memcached_string_length(sptr
);
171 static memcached_return
binary_read_one_response(memcached_server_st
*ptr
,
172 char *buffer
, size_t buffer_length
,
173 memcached_result_st
*result
)
175 protocol_binary_response_header header
;
177 unlikely (memcached_safe_read(ptr
, &header
.bytes
,
178 sizeof(header
.bytes
)) != MEMCACHED_SUCCESS
)
179 return MEMCACHED_UNKNOWN_READ_FAILURE
;
181 unlikely (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
182 return MEMCACHED_PROTOCOL_ERROR
;
185 ** Convert the header to host local endian!
187 header
.response
.keylen
= ntohs(header
.response
.keylen
);
188 header
.response
.status
= ntohs(header
.response
.status
);
189 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
190 header
.response
.cas
= ntohll(header
.response
.cas
);
191 uint32_t bodylen
= header
.response
.bodylen
;
193 if (header
.response
.status
== 0)
195 switch (header
.response
.opcode
)
197 case PROTOCOL_BINARY_CMD_GETK
:
198 case PROTOCOL_BINARY_CMD_GETKQ
:
200 uint16_t keylen
= header
.response
.keylen
;
201 memcached_result_reset(result
);
202 result
->cas
= header
.response
.cas
;
204 if (memcached_safe_read(ptr
, &result
->flags
,
205 sizeof (result
->flags
)) != MEMCACHED_SUCCESS
)
206 return MEMCACHED_UNKNOWN_READ_FAILURE
;
208 result
->flags
= ntohl(result
->flags
);
209 bodylen
-= header
.response
.extlen
;
211 result
->key_length
= keylen
;
212 if (memcached_safe_read(ptr
, result
->key
, keylen
) != MEMCACHED_SUCCESS
)
213 return MEMCACHED_UNKNOWN_READ_FAILURE
;
216 if (memcached_string_check(&result
->value
,
217 bodylen
) != MEMCACHED_SUCCESS
)
218 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
220 char *vptr
= memcached_string_value(&result
->value
);
221 if (memcached_safe_read(ptr
, vptr
, bodylen
) != MEMCACHED_SUCCESS
)
222 return MEMCACHED_UNKNOWN_READ_FAILURE
;
224 memcached_string_set_length(&result
->value
, bodylen
);
227 case PROTOCOL_BINARY_CMD_INCREMENT
:
228 case PROTOCOL_BINARY_CMD_DECREMENT
:
230 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
231 return MEMCACHED_PROTOCOL_ERROR
;
233 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
235 if (memcached_safe_read(ptr
, &val
, sizeof(val
)) != MEMCACHED_SUCCESS
)
236 return MEMCACHED_UNKNOWN_READ_FAILURE
;
239 memcpy(buffer
, &val
, sizeof(val
));
242 case PROTOCOL_BINARY_CMD_VERSION
:
244 memset(buffer
, 0, buffer_length
);
245 if (bodylen
>= buffer_length
)
246 /* not enough space in buffer.. should not happen... */
247 return MEMCACHED_UNKNOWN_READ_FAILURE
;
248 else if (memcached_safe_read(ptr
, buffer
, bodylen
) != MEMCACHED_SUCCESS
)
249 return MEMCACHED_UNKNOWN_READ_FAILURE
;
252 case PROTOCOL_BINARY_CMD_FLUSH
:
253 case PROTOCOL_BINARY_CMD_QUIT
:
254 case PROTOCOL_BINARY_CMD_SET
:
255 case PROTOCOL_BINARY_CMD_ADD
:
256 case PROTOCOL_BINARY_CMD_REPLACE
:
257 case PROTOCOL_BINARY_CMD_APPEND
:
258 case PROTOCOL_BINARY_CMD_PREPEND
:
259 case PROTOCOL_BINARY_CMD_DELETE
:
261 WATCHPOINT_ASSERT(bodylen
== 0);
262 return MEMCACHED_SUCCESS
;
265 case PROTOCOL_BINARY_CMD_NOOP
:
267 WATCHPOINT_ASSERT(bodylen
== 0);
268 return MEMCACHED_END
;
271 case PROTOCOL_BINARY_CMD_STAT
:
274 return MEMCACHED_END
;
275 else if (bodylen
+ 1 > buffer_length
)
276 /* not enough space in buffer.. should not happen... */
277 return MEMCACHED_UNKNOWN_READ_FAILURE
;
280 size_t keylen
= header
.response
.keylen
;
281 memset(buffer
, 0, buffer_length
);
282 if (memcached_safe_read(ptr
, buffer
, keylen
) != MEMCACHED_SUCCESS
||
283 memcached_safe_read(ptr
, buffer
+ keylen
+ 1,
284 bodylen
- keylen
) != MEMCACHED_SUCCESS
)
285 return MEMCACHED_UNKNOWN_READ_FAILURE
;
291 /* Command not implemented yet! */
292 WATCHPOINT_ASSERT(0);
293 return MEMCACHED_PROTOCOL_ERROR
;
297 else if (header
.response
.bodylen
)
299 /* What should I do with the error message??? just discard it for now */
300 char hole
[SMALL_STRING_LEN
];
303 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
304 if (memcached_safe_read(ptr
, hole
, nr
) != MEMCACHED_SUCCESS
)
305 return MEMCACHED_UNKNOWN_READ_FAILURE
;
309 /* This might be an error from one of the quiet commands.. if
310 * so, just throw it away and get the next one. What about creating
311 * a callback to the user with the error information?
313 switch (header
.response
.opcode
)
315 case PROTOCOL_BINARY_CMD_SETQ
:
316 case PROTOCOL_BINARY_CMD_ADDQ
:
317 case PROTOCOL_BINARY_CMD_REPLACEQ
:
318 case PROTOCOL_BINARY_CMD_APPENDQ
:
319 case PROTOCOL_BINARY_CMD_PREPENDQ
:
320 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
326 memcached_return rc
= MEMCACHED_SUCCESS
;
327 unlikely(header
.response
.status
!= 0)
328 switch (header
.response
.status
)
330 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
331 rc
= MEMCACHED_NOTFOUND
;
333 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
334 rc
= MEMCACHED_DATA_EXISTS
;
336 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
337 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
338 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
339 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
340 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
342 /* @todo fix the error mappings */
343 rc
= MEMCACHED_PROTOCOL_ERROR
;