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) {
54 memcached_return rc
= memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
56 unlikely (rc
!= MEMCACHED_END
&&
57 rc
!= MEMCACHED_STORED
&&
58 rc
!= MEMCACHED_SUCCESS
&&
59 rc
!= MEMCACHED_STAT
&&
60 rc
!= MEMCACHED_DELETED
&&
61 rc
!= MEMCACHED_NOTFOUND
&&
62 rc
!= MEMCACHED_NOTSTORED
&&
63 rc
!= MEMCACHED_DATA_EXISTS
)
67 return memcached_read_one_response(ptr
, buffer
, buffer_length
, result
);
70 static memcached_return
textual_read_one_response(memcached_server_st
*ptr
,
71 char *buffer
, size_t buffer_length
,
72 memcached_result_st
*result
)
74 memcached_return rc
= memcached_io_readline(ptr
, buffer
, buffer_length
);
75 if (rc
!= MEMCACHED_SUCCESS
)
80 case 'V': /* VALUE || VERSION */
81 if (buffer
[1] == 'A') /* VALUE */
85 /* We add back in one because we will need to search for END */
86 memcached_server_response_increment(ptr
);
88 rc
= value_fetch(ptr
, buffer
, result
);
90 rc
= value_fetch(ptr
, buffer
, &ptr
->root
->result
);
94 else if (buffer
[1] == 'E') /* VERSION */
96 return MEMCACHED_SUCCESS
;
100 WATCHPOINT_STRING(buffer
);
101 WATCHPOINT_ASSERT(0);
102 return MEMCACHED_UNKNOWN_READ_FAILURE
;
105 return MEMCACHED_SUCCESS
;
106 case 'S': /* STORED STATS SERVER_ERROR */
108 if (buffer
[2] == 'A') /* STORED STATS */
110 memcached_server_response_increment(ptr
);
111 return MEMCACHED_STAT
;
113 else if (buffer
[1] == 'E')
114 return MEMCACHED_SERVER_ERROR
;
115 else if (buffer
[1] == 'T')
116 return MEMCACHED_STORED
;
119 WATCHPOINT_STRING(buffer
);
120 WATCHPOINT_ASSERT(0);
121 return MEMCACHED_UNKNOWN_READ_FAILURE
;
124 case 'D': /* DELETED */
125 return MEMCACHED_DELETED
;
126 case 'N': /* NOT_FOUND */
128 if (buffer
[4] == 'F')
129 return MEMCACHED_NOTFOUND
;
130 else if (buffer
[4] == 'S')
131 return MEMCACHED_NOTSTORED
;
133 return MEMCACHED_UNKNOWN_READ_FAILURE
;
135 case 'E': /* PROTOCOL ERROR or END */
137 if (buffer
[1] == 'N')
138 return MEMCACHED_END
;
139 else if (buffer
[1] == 'R')
140 return MEMCACHED_PROTOCOL_ERROR
;
141 else if (buffer
[1] == 'X')
142 return MEMCACHED_DATA_EXISTS
;
144 return MEMCACHED_UNKNOWN_READ_FAILURE
;
146 case 'C': /* CLIENT ERROR */
147 return MEMCACHED_CLIENT_ERROR
;
150 unsigned long long auto_return_value
;
152 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
153 return MEMCACHED_SUCCESS
;
155 return MEMCACHED_UNKNOWN_READ_FAILURE
;
162 char *memcached_result_value(memcached_result_st
*ptr
)
164 memcached_string_st
*sptr
= &ptr
->value
;
165 return memcached_string_value(sptr
);
168 size_t memcached_result_length(memcached_result_st
*ptr
)
170 memcached_string_st
*sptr
= &ptr
->value
;
171 return memcached_string_length(sptr
);
174 static memcached_return
binary_read_one_response(memcached_server_st
*ptr
,
175 char *buffer
, size_t buffer_length
,
176 memcached_result_st
*result
)
178 protocol_binary_response_header header
;
180 unlikely (memcached_safe_read(ptr
, &header
.bytes
,
181 sizeof(header
.bytes
)) != MEMCACHED_SUCCESS
)
182 return MEMCACHED_UNKNOWN_READ_FAILURE
;
184 unlikely (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
185 return MEMCACHED_PROTOCOL_ERROR
;
188 ** Convert the header to host local endian!
190 header
.response
.keylen
= ntohs(header
.response
.keylen
);
191 header
.response
.status
= ntohs(header
.response
.status
);
192 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
193 header
.response
.cas
= ntohll(header
.response
.cas
);
194 uint32_t bodylen
= header
.response
.bodylen
;
196 if (header
.response
.status
== 0)
198 switch (header
.response
.opcode
)
200 case PROTOCOL_BINARY_CMD_GETK
:
201 case PROTOCOL_BINARY_CMD_GETKQ
:
203 uint16_t keylen
= header
.response
.keylen
;
204 memcached_result_reset(result
);
205 result
->cas
= header
.response
.cas
;
207 if (memcached_safe_read(ptr
, &result
->flags
,
208 sizeof (result
->flags
)) != MEMCACHED_SUCCESS
)
209 return MEMCACHED_UNKNOWN_READ_FAILURE
;
211 result
->flags
= ntohl(result
->flags
);
212 bodylen
-= header
.response
.extlen
;
214 result
->key_length
= keylen
;
215 if (memcached_safe_read(ptr
, result
->key
, keylen
) != MEMCACHED_SUCCESS
)
216 return MEMCACHED_UNKNOWN_READ_FAILURE
;
219 if (memcached_string_check(&result
->value
,
220 bodylen
) != MEMCACHED_SUCCESS
)
221 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
223 char *vptr
= memcached_string_value(&result
->value
);
224 if (memcached_safe_read(ptr
, vptr
, bodylen
) != MEMCACHED_SUCCESS
)
225 return MEMCACHED_UNKNOWN_READ_FAILURE
;
227 memcached_string_set_length(&result
->value
, bodylen
);
230 case PROTOCOL_BINARY_CMD_INCREMENT
:
231 case PROTOCOL_BINARY_CMD_DECREMENT
:
233 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
234 return MEMCACHED_PROTOCOL_ERROR
;
236 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
238 if (memcached_safe_read(ptr
, &val
, sizeof(val
)) != MEMCACHED_SUCCESS
)
239 return MEMCACHED_UNKNOWN_READ_FAILURE
;
242 memcpy(buffer
, &val
, sizeof(val
));
245 case PROTOCOL_BINARY_CMD_VERSION
:
247 memset(buffer
, 0, buffer_length
);
248 if (bodylen
>= buffer_length
)
249 /* not enough space in buffer.. should not happen... */
250 return MEMCACHED_UNKNOWN_READ_FAILURE
;
251 else if (memcached_safe_read(ptr
, buffer
, bodylen
) != MEMCACHED_SUCCESS
)
252 return MEMCACHED_UNKNOWN_READ_FAILURE
;
255 case PROTOCOL_BINARY_CMD_FLUSH
:
256 case PROTOCOL_BINARY_CMD_QUIT
:
257 case PROTOCOL_BINARY_CMD_SET
:
258 case PROTOCOL_BINARY_CMD_ADD
:
259 case PROTOCOL_BINARY_CMD_REPLACE
:
260 case PROTOCOL_BINARY_CMD_APPEND
:
261 case PROTOCOL_BINARY_CMD_PREPEND
:
262 case PROTOCOL_BINARY_CMD_DELETE
:
264 WATCHPOINT_ASSERT(bodylen
== 0);
265 return MEMCACHED_SUCCESS
;
268 case PROTOCOL_BINARY_CMD_NOOP
:
270 WATCHPOINT_ASSERT(bodylen
== 0);
271 return MEMCACHED_END
;
274 case PROTOCOL_BINARY_CMD_STAT
:
277 return MEMCACHED_END
;
278 else if (bodylen
+ 1 > buffer_length
)
279 /* not enough space in buffer.. should not happen... */
280 return MEMCACHED_UNKNOWN_READ_FAILURE
;
283 size_t keylen
= header
.response
.keylen
;
284 memset(buffer
, 0, buffer_length
);
285 if (memcached_safe_read(ptr
, buffer
, keylen
) != MEMCACHED_SUCCESS
||
286 memcached_safe_read(ptr
, buffer
+ keylen
+ 1,
287 bodylen
- keylen
) != MEMCACHED_SUCCESS
)
288 return MEMCACHED_UNKNOWN_READ_FAILURE
;
294 /* Command not implemented yet! */
295 WATCHPOINT_ASSERT(0);
296 return MEMCACHED_PROTOCOL_ERROR
;
300 else if (header
.response
.bodylen
)
302 /* What should I do with the error message??? just discard it for now */
303 char hole
[SMALL_STRING_LEN
];
306 size_t nr
= (bodylen
> SMALL_STRING_LEN
) ? SMALL_STRING_LEN
: bodylen
;
307 if (memcached_safe_read(ptr
, hole
, nr
) != MEMCACHED_SUCCESS
)
308 return MEMCACHED_UNKNOWN_READ_FAILURE
;
312 /* This might be an error from one of the quiet commands.. if
313 * so, just throw it away and get the next one. What about creating
314 * a callback to the user with the error information?
316 switch (header
.response
.opcode
)
318 case PROTOCOL_BINARY_CMD_SETQ
:
319 case PROTOCOL_BINARY_CMD_ADDQ
:
320 case PROTOCOL_BINARY_CMD_REPLACEQ
:
321 case PROTOCOL_BINARY_CMD_APPENDQ
:
322 case PROTOCOL_BINARY_CMD_PREPENDQ
:
323 return binary_read_one_response(ptr
, buffer
, buffer_length
, result
);
329 memcached_return rc
= MEMCACHED_SUCCESS
;
330 unlikely(header
.response
.status
!= 0)
331 switch (header
.response
.status
)
333 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
334 rc
= MEMCACHED_NOTFOUND
;
336 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
337 rc
= MEMCACHED_DATA_EXISTS
;
339 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
340 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
341 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
342 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
343 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
345 /* @todo fix the error mappings */
346 rc
= MEMCACHED_PROTOCOL_ERROR
;