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 if (ptr
->root
->flags
& MEM_BINARY_PROTOCOL
)
26 rc
= binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
28 rc
= textual_read_one_response(ptr
, buffer
, buffer_length
, result
);
30 unlikely(rc
== MEMCACHED_UNKNOWN_READ_FAILURE
||
31 rc
== MEMCACHED_PROTOCOL_ERROR
||
32 rc
== MEMCACHED_CLIENT_ERROR
||
33 rc
== MEMCACHED_MEMORY_ALLOCATION_FAILURE
)
34 memcached_io_reset(ptr
);
39 memcached_return
memcached_response(memcached_server_st
*ptr
,
40 char *buffer
, size_t buffer_length
,
41 memcached_result_st
*result
)
43 /* We may have old commands in the buffer not set, first purge */
44 if (ptr
->root
->flags
& MEM_NO_BLOCK
)
45 (void)memcached_io_write(ptr
, NULL
, 0, 1);
48 * The previous implementation purged all pending requests and just
49 * returned the last one. Purge all pending messages to ensure backwards
52 if ((ptr
->root
->flags
& MEM_BINARY_PROTOCOL
) == 0)
53 while (memcached_server_response_count(ptr
) > 1)
55 memcached_return rc
= memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
57 unlikely (rc
!= MEMCACHED_END
&&
58 rc
!= MEMCACHED_STORED
&&
59 rc
!= MEMCACHED_SUCCESS
&&
60 rc
!= MEMCACHED_STAT
&&
61 rc
!= MEMCACHED_DELETED
&&
62 rc
!= MEMCACHED_NOTFOUND
&&
63 rc
!= MEMCACHED_NOTSTORED
&&
64 rc
!= MEMCACHED_DATA_EXISTS
)
68 return memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
71 static memcached_return
textual_read_one_response(memcached_server_st
*ptr
,
72 char *buffer
, size_t buffer_length
,
73 memcached_result_st
*result
)
75 memcached_return rc
= memcached_io_readline(ptr
, buffer
, buffer_length
);
76 if (rc
!= MEMCACHED_SUCCESS
)
81 case 'V': /* VALUE || VERSION */
82 if (buffer
[1] == 'A') /* VALUE */
86 /* We add back in one because we will need to search for END */
87 memcached_server_response_increment(ptr
);
89 rc
= value_fetch(ptr
, buffer
, result
);
91 rc
= value_fetch(ptr
, buffer
, &ptr
->root
->result
);
95 else if (buffer
[1] == 'E') /* VERSION */
97 return MEMCACHED_SUCCESS
;
101 WATCHPOINT_STRING(buffer
);
102 WATCHPOINT_ASSERT(0);
103 return MEMCACHED_UNKNOWN_READ_FAILURE
;
106 return MEMCACHED_SUCCESS
;
107 case 'S': /* STORED STATS SERVER_ERROR */
109 if (buffer
[2] == 'A') /* STORED STATS */
111 memcached_server_response_increment(ptr
);
112 return MEMCACHED_STAT
;
114 else if (buffer
[1] == 'E')
115 return MEMCACHED_SERVER_ERROR
;
116 else if (buffer
[1] == 'T')
117 return MEMCACHED_STORED
;
120 WATCHPOINT_STRING(buffer
);
121 WATCHPOINT_ASSERT(0);
122 return MEMCACHED_UNKNOWN_READ_FAILURE
;
125 case 'D': /* DELETED */
126 return MEMCACHED_DELETED
;
127 case 'N': /* NOT_FOUND */
129 if (buffer
[4] == 'F')
130 return MEMCACHED_NOTFOUND
;
131 else if (buffer
[4] == 'S')
132 return MEMCACHED_NOTSTORED
;
134 return MEMCACHED_UNKNOWN_READ_FAILURE
;
136 case 'E': /* PROTOCOL ERROR or END */
138 if (buffer
[1] == 'N')
139 return MEMCACHED_END
;
140 else if (buffer
[1] == 'R')
141 return MEMCACHED_PROTOCOL_ERROR
;
142 else if (buffer
[1] == 'X')
143 return MEMCACHED_DATA_EXISTS
;
145 return MEMCACHED_UNKNOWN_READ_FAILURE
;
147 case 'C': /* CLIENT ERROR */
148 return MEMCACHED_CLIENT_ERROR
;
151 unsigned long long auto_return_value
;
153 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
154 return MEMCACHED_SUCCESS
;
156 return MEMCACHED_UNKNOWN_READ_FAILURE
;
163 char *memcached_result_value(memcached_result_st
*ptr
)
165 memcached_string_st
*sptr
= &ptr
->value
;
166 return memcached_string_value(sptr
);
169 size_t memcached_result_length(memcached_result_st
*ptr
)
171 memcached_string_st
*sptr
= &ptr
->value
;
172 return memcached_string_length(sptr
);
175 static memcached_return
binary_read_one_response(memcached_server_st
*ptr
,
176 char *buffer
, size_t buffer_length
,
177 memcached_result_st
*result
)
179 protocol_binary_response_header header
;
181 unlikely (memcached_safe_read(ptr
, &header
.bytes
,
182 sizeof(header
.bytes
)) != MEMCACHED_SUCCESS
)
183 return MEMCACHED_UNKNOWN_READ_FAILURE
;
185 unlikely (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
186 return MEMCACHED_PROTOCOL_ERROR
;
189 ** Convert the header to host local endian!
191 header
.response
.keylen
= ntohs(header
.response
.keylen
);
192 header
.response
.status
= ntohs(header
.response
.status
);
193 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
194 header
.response
.cas
= ntohll(header
.response
.cas
);
195 uint32_t bodylen
= header
.response
.bodylen
;
197 if (header
.response
.status
== 0)
199 switch (header
.response
.opcode
)
201 case PROTOCOL_BINARY_CMD_GETK
:
202 case PROTOCOL_BINARY_CMD_GETKQ
:
204 uint16_t keylen
= header
.response
.keylen
;
205 memcached_result_reset(result
);
206 result
->cas
= header
.response
.cas
;
208 if (memcached_safe_read(ptr
, &result
->flags
,
209 sizeof (result
->flags
)) != MEMCACHED_SUCCESS
)
210 return MEMCACHED_UNKNOWN_READ_FAILURE
;
212 result
->flags
= ntohl(result
->flags
);
213 bodylen
-= header
.response
.extlen
;
215 result
->key_length
= keylen
;
216 if (memcached_safe_read(ptr
, result
->key
, keylen
) != MEMCACHED_SUCCESS
)
217 return MEMCACHED_UNKNOWN_READ_FAILURE
;
220 if (memcached_string_check(&result
->value
,
221 bodylen
) != MEMCACHED_SUCCESS
)
222 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
224 char *vptr
= memcached_string_value(&result
->value
);
225 if (memcached_safe_read(ptr
, vptr
, bodylen
) != MEMCACHED_SUCCESS
)
226 return MEMCACHED_UNKNOWN_READ_FAILURE
;
228 memcached_string_set_length(&result
->value
, bodylen
);
231 case PROTOCOL_BINARY_CMD_INCREMENT
:
232 case PROTOCOL_BINARY_CMD_DECREMENT
:
234 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
235 return MEMCACHED_PROTOCOL_ERROR
;
237 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
239 if (memcached_safe_read(ptr
, &val
, sizeof(val
)) != MEMCACHED_SUCCESS
)
240 return MEMCACHED_UNKNOWN_READ_FAILURE
;
243 memcpy(buffer
, &val
, sizeof(val
));
246 case PROTOCOL_BINARY_CMD_VERSION
:
248 memset(buffer
, 0, buffer_length
);
249 if (bodylen
>= buffer_length
)
250 /* not enough space in buffer.. should not happen... */
251 return MEMCACHED_UNKNOWN_READ_FAILURE
;
252 else if (memcached_safe_read(ptr
, buffer
, bodylen
) != MEMCACHED_SUCCESS
)
253 return MEMCACHED_UNKNOWN_READ_FAILURE
;
256 case PROTOCOL_BINARY_CMD_FLUSH
:
257 case PROTOCOL_BINARY_CMD_QUIT
:
258 case PROTOCOL_BINARY_CMD_SET
:
259 case PROTOCOL_BINARY_CMD_ADD
:
260 case PROTOCOL_BINARY_CMD_REPLACE
:
261 case PROTOCOL_BINARY_CMD_APPEND
:
262 case PROTOCOL_BINARY_CMD_PREPEND
:
263 case PROTOCOL_BINARY_CMD_DELETE
:
265 WATCHPOINT_ASSERT(bodylen
== 0);
266 return MEMCACHED_SUCCESS
;
269 case PROTOCOL_BINARY_CMD_NOOP
:
271 WATCHPOINT_ASSERT(bodylen
== 0);
272 return MEMCACHED_END
;
275 case PROTOCOL_BINARY_CMD_STAT
:
278 return MEMCACHED_END
;
279 else if (bodylen
+ 1 > buffer_length
)
280 /* not enough space in buffer.. should not happen... */
281 return MEMCACHED_UNKNOWN_READ_FAILURE
;
284 size_t keylen
= header
.response
.keylen
;
285 memset(buffer
, 0, buffer_length
);
286 if (memcached_safe_read(ptr
, buffer
, keylen
) != MEMCACHED_SUCCESS
||
287 memcached_safe_read(ptr
, buffer
+ keylen
+ 1,
288 bodylen
- keylen
) != MEMCACHED_SUCCESS
)
289 return MEMCACHED_UNKNOWN_READ_FAILURE
;
295 /* Command not implemented yet! */
296 WATCHPOINT_ASSERT(0);
297 return MEMCACHED_PROTOCOL_ERROR
;
301 else if (header
.response
.bodylen
)
303 /* What should I do with the error message??? just discard it for now */
304 char hole
[SMALL_STRING_LEN
];
307 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
308 if (memcached_safe_read(ptr
, hole
, nr
) != MEMCACHED_SUCCESS
)
309 return MEMCACHED_UNKNOWN_READ_FAILURE
;
313 /* This might be an error from one of the quiet commands.. if
314 * so, just throw it away and get the next one. What about creating
315 * a callback to the user with the error information?
317 switch (header
.response
.opcode
)
319 case PROTOCOL_BINARY_CMD_SETQ
:
320 case PROTOCOL_BINARY_CMD_ADDQ
:
321 case PROTOCOL_BINARY_CMD_REPLACEQ
:
322 case PROTOCOL_BINARY_CMD_APPENDQ
:
323 case PROTOCOL_BINARY_CMD_PREPENDQ
:
324 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
330 memcached_return rc
= MEMCACHED_SUCCESS
;
331 unlikely(header
.response
.status
!= 0)
332 switch (header
.response
.status
)
334 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
335 rc
= MEMCACHED_NOTFOUND
;
337 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
338 rc
= MEMCACHED_DATA_EXISTS
;
340 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
341 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
342 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
343 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
344 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
346 /* @todo fix the error mappings */
347 rc
= MEMCACHED_PROTOCOL_ERROR
;