4 memcached_response() is used to determine the return result
5 from an issued command.
9 #include "memcached_io.h"
11 static memcached_return
binary_response(memcached_server_st
*ptr
,
12 char *buffer
, size_t buffer_length
,
13 memcached_result_st
*result
);
15 memcached_return
memcached_response(memcached_server_st
*ptr
,
16 char *buffer
, size_t buffer_length
,
17 memcached_result_st
*result
)
22 unsigned int max_messages
;
26 /* UDP at the moment is odd...*/
27 if (ptr
->type
== MEMCACHED_CONNECTION_UDP
)
32 return MEMCACHED_SUCCESS
;
34 read_length
= memcached_io_read(ptr
, buffer
, 8);
37 /* We may have old commands in the buffer not set, first purge */
38 if (ptr
->root
->flags
& MEM_NO_BLOCK
)
39 (void)memcached_io_write(ptr
, NULL
, 0, 1);
41 if (ptr
->root
->flags
& MEM_BINARY_PROTOCOL
)
42 return binary_response(ptr
, buffer
, buffer_length
, result
);
44 max_messages
= memcached_server_response_count(ptr
);
45 for (x
= 0; x
< max_messages
; x
++)
47 size_t total_length
= 0;
55 read_length
= memcached_io_read(ptr
, buffer_ptr
, 1);
56 WATCHPOINT_ASSERT(isgraph(*buffer_ptr
) || isspace(*buffer_ptr
));
60 memcached_io_reset(ptr
);
61 return MEMCACHED_UNKNOWN_READ_FAILURE
;
64 if (*buffer_ptr
== '\n')
70 WATCHPOINT_ASSERT(total_length
<= buffer_length
);
72 if (total_length
>= buffer_length
)
74 memcached_io_reset(ptr
);
75 return MEMCACHED_PROTOCOL_ERROR
;
81 memcached_server_response_decrement(ptr
);
86 case 'V': /* VALUE || VERSION */
87 if (buffer
[1] == 'A') /* VALUE */
91 /* We add back in one because we will need to search for END */
92 memcached_server_response_increment(ptr
);
94 rc
= value_fetch(ptr
, buffer
, result
);
96 rc
= value_fetch(ptr
, buffer
, &ptr
->root
->result
);
100 else if (buffer
[1] == 'E') /* VERSION */
102 return MEMCACHED_SUCCESS
;
106 WATCHPOINT_STRING(buffer
);
107 WATCHPOINT_ASSERT(0);
108 memcached_io_reset(ptr
);
109 return MEMCACHED_UNKNOWN_READ_FAILURE
;
112 return MEMCACHED_SUCCESS
;
113 case 'S': /* STORED STATS SERVER_ERROR */
115 if (buffer
[2] == 'A') /* STORED STATS */
117 memcached_server_response_increment(ptr
);
118 return MEMCACHED_STAT
;
120 else if (buffer
[1] == 'E')
121 return MEMCACHED_SERVER_ERROR
;
122 else if (buffer
[1] == 'T')
123 return MEMCACHED_STORED
;
126 WATCHPOINT_STRING(buffer
);
127 WATCHPOINT_ASSERT(0);
128 memcached_io_reset(ptr
);
129 return MEMCACHED_UNKNOWN_READ_FAILURE
;
132 case 'D': /* DELETED */
133 return MEMCACHED_DELETED
;
134 case 'N': /* NOT_FOUND */
136 if (buffer
[4] == 'F')
137 return MEMCACHED_NOTFOUND
;
138 else if (buffer
[4] == 'S')
139 return MEMCACHED_NOTSTORED
;
142 memcached_io_reset(ptr
);
143 return MEMCACHED_UNKNOWN_READ_FAILURE
;
146 case 'E': /* PROTOCOL ERROR or END */
148 if (buffer
[1] == 'N')
149 return MEMCACHED_END
;
150 else if (buffer
[1] == 'R')
152 memcached_io_reset(ptr
);
153 return MEMCACHED_PROTOCOL_ERROR
;
155 else if (buffer
[1] == 'X')
157 memcached_io_reset(ptr
);
158 return MEMCACHED_DATA_EXISTS
;
162 memcached_io_reset(ptr
);
163 return MEMCACHED_UNKNOWN_READ_FAILURE
;
166 case 'C': /* CLIENT ERROR */
167 memcached_io_reset(ptr
);
168 return MEMCACHED_CLIENT_ERROR
;
171 unsigned long long auto_return_value
;
173 if (sscanf(buffer
, "%llu", &auto_return_value
) == 1)
174 return MEMCACHED_SUCCESS
;
176 memcached_io_reset(ptr
);
178 return MEMCACHED_UNKNOWN_READ_FAILURE
;
183 return MEMCACHED_SUCCESS
;
186 char *memcached_result_value(memcached_result_st
*ptr
)
188 memcached_string_st
*sptr
= &ptr
->value
;
189 return memcached_string_value(sptr
);
192 size_t memcached_result_length(memcached_result_st
*ptr
)
194 memcached_string_st
*sptr
= &ptr
->value
;
195 return memcached_string_length(sptr
);
199 * Read a given number of bytes from the server and place it into a specific
200 * buffer. Reset the IO channel or this server if an error occurs.
202 static memcached_return
safe_read(memcached_server_st
*ptr
, void *dta
,
208 while (offset
< size
)
210 ssize_t nread
= memcached_io_read(ptr
, data
+ offset
, size
- offset
);
213 memcached_io_reset(ptr
);
214 return MEMCACHED_UNKNOWN_READ_FAILURE
;
219 return MEMCACHED_SUCCESS
;
222 static memcached_return
binary_response(memcached_server_st
*ptr
,
224 size_t buffer_length
,
225 memcached_result_st
*result
)
227 protocol_binary_response_header header
;
228 memcached_server_response_decrement(ptr
);
230 unlikely (safe_read(ptr
, &header
.bytes
,
231 sizeof(header
.bytes
)) != MEMCACHED_SUCCESS
)
232 return MEMCACHED_UNKNOWN_READ_FAILURE
;
234 unlikely (header
.response
.magic
!= PROTOCOL_BINARY_RES
)
236 memcached_io_reset(ptr
);
237 return MEMCACHED_PROTOCOL_ERROR
;
241 ** Convert the header to host local endian!
243 header
.response
.keylen
= ntohs(header
.response
.keylen
);
244 header
.response
.status
= ntohs(header
.response
.status
);
245 header
.response
.bodylen
= ntohl(header
.response
.bodylen
);
246 header
.response
.cas
= ntohll(header
.response
.cas
);
247 uint32_t bodylen
= header
.response
.bodylen
;
249 if (header
.response
.status
== 0)
251 if ((header
.response
.opcode
== PROTOCOL_BINARY_CMD_GETK
) ||
252 (header
.response
.opcode
== PROTOCOL_BINARY_CMD_GETKQ
))
254 uint16_t keylen
= header
.response
.keylen
;
255 memcached_result_reset(result
);
256 result
->cas
= header
.response
.cas
;
258 if (safe_read(ptr
, &result
->flags
,
259 sizeof(result
->flags
)) != MEMCACHED_SUCCESS
)
261 return MEMCACHED_UNKNOWN_READ_FAILURE
;
263 result
->flags
= ntohl(result
->flags
);
264 bodylen
-= header
.response
.extlen
;
266 result
->key_length
= keylen
;
267 if (safe_read(ptr
, result
->key
, keylen
) != MEMCACHED_SUCCESS
)
269 return MEMCACHED_UNKNOWN_READ_FAILURE
;
273 if (memcached_string_check(&result
->value
,
274 bodylen
) != MEMCACHED_SUCCESS
)
276 memcached_io_reset(ptr
);
277 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
280 char *vptr
= memcached_string_value(&result
->value
);
281 if (safe_read(ptr
, vptr
, bodylen
) != MEMCACHED_SUCCESS
)
283 return MEMCACHED_UNKNOWN_READ_FAILURE
;
286 memcached_string_set_length(&result
->value
, bodylen
);
288 else if ((header
.response
.opcode
== PROTOCOL_BINARY_CMD_INCREMENT
) ||
289 (header
.response
.opcode
== PROTOCOL_BINARY_CMD_DECREMENT
))
291 if (bodylen
!= sizeof(uint64_t) || buffer_length
!= sizeof(uint64_t))
293 return MEMCACHED_PROTOCOL_ERROR
;
296 WATCHPOINT_ASSERT(bodylen
== buffer_length
);
298 if (safe_read(ptr
, &val
, sizeof(val
)) != MEMCACHED_SUCCESS
)
300 return MEMCACHED_UNKNOWN_READ_FAILURE
;
304 memcpy(buffer
, &val
, sizeof(val
));
306 else if (header
.response
.opcode
== PROTOCOL_BINARY_CMD_VERSION
)
308 memset(buffer
, 0, buffer_length
);
309 if (bodylen
>= buffer_length
)
310 /* not enough space in buffer.. should not happen... */
311 return MEMCACHED_UNKNOWN_READ_FAILURE
;
313 safe_read(ptr
, buffer
, bodylen
);
315 else if ((header
.response
.opcode
== PROTOCOL_BINARY_CMD_FLUSH
) ||
316 (header
.response
.opcode
== PROTOCOL_BINARY_CMD_QUIT
) ||
317 (header
.response
.opcode
== PROTOCOL_BINARY_CMD_SET
) ||
318 (header
.response
.opcode
== PROTOCOL_BINARY_CMD_ADD
) ||
319 (header
.response
.opcode
== PROTOCOL_BINARY_CMD_REPLACE
) ||
320 (header
.response
.opcode
== PROTOCOL_BINARY_CMD_APPEND
) ||
321 (header
.response
.opcode
== PROTOCOL_BINARY_CMD_PREPEND
) ||
322 (header
.response
.opcode
== PROTOCOL_BINARY_CMD_DELETE
))
324 WATCHPOINT_ASSERT(bodylen
== 0);
325 return MEMCACHED_SUCCESS
;
327 else if (header
.response
.opcode
== PROTOCOL_BINARY_CMD_NOOP
)
329 WATCHPOINT_ASSERT(bodylen
== 0);
330 return MEMCACHED_END
;
332 else if (header
.response
.opcode
== PROTOCOL_BINARY_CMD_STAT
)
335 return MEMCACHED_END
;
336 else if (bodylen
+ 1 > buffer_length
)
337 /* not enough space in buffer.. should not happen... */
338 return MEMCACHED_UNKNOWN_READ_FAILURE
;
341 size_t keylen
= header
.response
.keylen
;
342 memset(buffer
, 0, buffer_length
);
343 safe_read(ptr
, buffer
, keylen
);
344 safe_read(ptr
, buffer
+ keylen
+ 1, bodylen
- keylen
);
349 /* Command not implemented yet! */
350 WATCHPOINT_ASSERT(0);
351 memcached_io_reset(ptr
);
352 return MEMCACHED_PROTOCOL_ERROR
;
355 else if (header
.response
.bodylen
)
357 /* What should I do with the error message??? just discard it for now */
361 size_t nr
= (bodylen
> sizeof(hole
)) ? sizeof(hole
) : bodylen
;
362 safe_read(ptr
, hole
, nr
);
367 memcached_return rc
= MEMCACHED_SUCCESS
;
368 unlikely(header
.response
.status
!= 0)
369 switch (header
.response
.status
)
371 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT
:
372 rc
= MEMCACHED_NOTFOUND
;
374 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS
:
375 rc
= MEMCACHED_DATA_EXISTS
;
377 case PROTOCOL_BINARY_RESPONSE_E2BIG
:
378 case PROTOCOL_BINARY_RESPONSE_EINVAL
:
379 case PROTOCOL_BINARY_RESPONSE_NOT_STORED
:
380 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND
:
381 case PROTOCOL_BINARY_RESPONSE_ENOMEM
:
383 /* @todo fix the error mappings */
384 rc
= MEMCACHED_PROTOCOL_ERROR
;