e9f82b0af3653064e9cec4fa4a8906d1b6128b31
[awesomized/libmemcached] / libmemcached / memcached_response.c
1 /*
2 Memcached library
3
4 memcached_response() is used to determine the return result
5 from an issued command.
6 */
7
8 #include "common.h"
9 #include "memcached_io.h"
10
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);
17
18 memcached_return memcached_read_one_response(memcached_server_st *ptr,
19 char *buffer, size_t buffer_length,
20 memcached_result_st *result)
21 {
22 memcached_server_response_decrement(ptr);
23
24 memcached_return rc;
25 if (ptr->root->flags & MEM_BINARY_PROTOCOL)
26 rc= binary_read_one_response(ptr, buffer, buffer_length, result);
27 else
28 rc= textual_read_one_response(ptr, buffer, buffer_length, result);
29
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);
35
36 return rc;
37 }
38
39 memcached_return memcached_response(memcached_server_st *ptr,
40 char *buffer, size_t buffer_length,
41 memcached_result_st *result)
42 {
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);
46
47 /*
48 * The previous implementation purged all pending requests and just
49 * returned the last one. Purge all pending messages to ensure backwards
50 * compatibility.
51 */
52 if ((ptr->root->flags & MEM_BINARY_PROTOCOL) == 0)
53 while (memcached_server_response_count(ptr) > 1)
54 {
55 memcached_return rc= memcached_read_one_response(ptr, buffer, buffer_length, result);
56
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)
65 return rc;
66 }
67
68 return memcached_read_one_response(ptr, buffer, buffer_length, result);
69 }
70
71 static memcached_return textual_read_one_response(memcached_server_st *ptr,
72 char *buffer, size_t buffer_length,
73 memcached_result_st *result)
74 {
75 memcached_return rc= memcached_io_readline(ptr, buffer, buffer_length);
76 if (rc != MEMCACHED_SUCCESS)
77 return rc;
78
79 switch(buffer[0])
80 {
81 case 'V': /* VALUE || VERSION */
82 if (buffer[1] == 'A') /* VALUE */
83 {
84 memcached_return rc;
85
86 /* We add back in one because we will need to search for END */
87 memcached_server_response_increment(ptr);
88 if (result)
89 rc= value_fetch(ptr, buffer, result);
90 else
91 rc= value_fetch(ptr, buffer, &ptr->root->result);
92
93 return rc;
94 }
95 else if (buffer[1] == 'E') /* VERSION */
96 {
97 return MEMCACHED_SUCCESS;
98 }
99 else
100 {
101 WATCHPOINT_STRING(buffer);
102 WATCHPOINT_ASSERT(0);
103 return MEMCACHED_UNKNOWN_READ_FAILURE;
104 }
105 case 'O': /* OK */
106 return MEMCACHED_SUCCESS;
107 case 'S': /* STORED STATS SERVER_ERROR */
108 {
109 if (buffer[2] == 'A') /* STORED STATS */
110 {
111 memcached_server_response_increment(ptr);
112 return MEMCACHED_STAT;
113 }
114 else if (buffer[1] == 'E')
115 return MEMCACHED_SERVER_ERROR;
116 else if (buffer[1] == 'T')
117 return MEMCACHED_STORED;
118 else
119 {
120 WATCHPOINT_STRING(buffer);
121 WATCHPOINT_ASSERT(0);
122 return MEMCACHED_UNKNOWN_READ_FAILURE;
123 }
124 }
125 case 'D': /* DELETED */
126 return MEMCACHED_DELETED;
127 case 'N': /* NOT_FOUND */
128 {
129 if (buffer[4] == 'F')
130 return MEMCACHED_NOTFOUND;
131 else if (buffer[4] == 'S')
132 return MEMCACHED_NOTSTORED;
133 else
134 return MEMCACHED_UNKNOWN_READ_FAILURE;
135 }
136 case 'E': /* PROTOCOL ERROR or END */
137 {
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;
144 else
145 return MEMCACHED_UNKNOWN_READ_FAILURE;
146 }
147 case 'C': /* CLIENT ERROR */
148 return MEMCACHED_CLIENT_ERROR;
149 default:
150 {
151 unsigned long long auto_return_value;
152
153 if (sscanf(buffer, "%llu", &auto_return_value) == 1)
154 return MEMCACHED_SUCCESS;
155
156 return MEMCACHED_UNKNOWN_READ_FAILURE;
157 }
158 }
159
160 /* NOTREACHED */
161 }
162
163 char *memcached_result_value(memcached_result_st *ptr)
164 {
165 memcached_string_st *sptr= &ptr->value;
166 return memcached_string_value(sptr);
167 }
168
169 size_t memcached_result_length(memcached_result_st *ptr)
170 {
171 memcached_string_st *sptr= &ptr->value;
172 return memcached_string_length(sptr);
173 }
174
175 static memcached_return binary_read_one_response(memcached_server_st *ptr,
176 char *buffer, size_t buffer_length,
177 memcached_result_st *result)
178 {
179 protocol_binary_response_header header;
180
181 unlikely (memcached_safe_read(ptr, &header.bytes,
182 sizeof(header.bytes)) != MEMCACHED_SUCCESS)
183 return MEMCACHED_UNKNOWN_READ_FAILURE;
184
185 unlikely (header.response.magic != PROTOCOL_BINARY_RES)
186 return MEMCACHED_PROTOCOL_ERROR;
187
188 /*
189 ** Convert the header to host local endian!
190 */
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;
196
197 if (header.response.status == 0)
198 {
199 switch (header.response.opcode)
200 {
201 case PROTOCOL_BINARY_CMD_GETK:
202 case PROTOCOL_BINARY_CMD_GETKQ:
203 {
204 uint16_t keylen= header.response.keylen;
205 memcached_result_reset(result);
206 result->cas= header.response.cas;
207
208 if (memcached_safe_read(ptr, &result->flags,
209 sizeof (result->flags)) != MEMCACHED_SUCCESS)
210 return MEMCACHED_UNKNOWN_READ_FAILURE;
211
212 result->flags= ntohl(result->flags);
213 bodylen -= header.response.extlen;
214
215 result->key_length= keylen;
216 if (memcached_safe_read(ptr, result->key, keylen) != MEMCACHED_SUCCESS)
217 return MEMCACHED_UNKNOWN_READ_FAILURE;
218
219 bodylen -= keylen;
220 if (memcached_string_check(&result->value,
221 bodylen) != MEMCACHED_SUCCESS)
222 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
223
224 char *vptr= memcached_string_value(&result->value);
225 if (memcached_safe_read(ptr, vptr, bodylen) != MEMCACHED_SUCCESS)
226 return MEMCACHED_UNKNOWN_READ_FAILURE;
227
228 memcached_string_set_length(&result->value, bodylen);
229 }
230 break;
231 case PROTOCOL_BINARY_CMD_INCREMENT:
232 case PROTOCOL_BINARY_CMD_DECREMENT:
233 {
234 if (bodylen != sizeof(uint64_t) || buffer_length != sizeof(uint64_t))
235 return MEMCACHED_PROTOCOL_ERROR;
236
237 WATCHPOINT_ASSERT(bodylen == buffer_length);
238 uint64_t val;
239 if (memcached_safe_read(ptr, &val, sizeof(val)) != MEMCACHED_SUCCESS)
240 return MEMCACHED_UNKNOWN_READ_FAILURE;
241
242 val= ntohll(val);
243 memcpy(buffer, &val, sizeof(val));
244 }
245 break;
246 case PROTOCOL_BINARY_CMD_VERSION:
247 {
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;
254 }
255 break;
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:
264 {
265 WATCHPOINT_ASSERT(bodylen == 0);
266 return MEMCACHED_SUCCESS;
267 }
268 break;
269 case PROTOCOL_BINARY_CMD_NOOP:
270 {
271 WATCHPOINT_ASSERT(bodylen == 0);
272 return MEMCACHED_END;
273 }
274 break;
275 case PROTOCOL_BINARY_CMD_STAT:
276 {
277 if (bodylen == 0)
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;
282 else
283 {
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;
290 }
291 }
292 break;
293 default:
294 {
295 /* Command not implemented yet! */
296 WATCHPOINT_ASSERT(0);
297 return MEMCACHED_PROTOCOL_ERROR;
298 }
299 }
300 }
301 else if (header.response.bodylen)
302 {
303 /* What should I do with the error message??? just discard it for now */
304 char hole[SMALL_STRING_LEN];
305 while (bodylen > 0)
306 {
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;
310 bodylen -= nr;
311 }
312
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?
316 */
317 switch (header.response.opcode)
318 {
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);
325 default:
326 break;
327 }
328 }
329
330 memcached_return rc= MEMCACHED_SUCCESS;
331 unlikely(header.response.status != 0)
332 switch (header.response.status)
333 {
334 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT:
335 rc= MEMCACHED_NOTFOUND;
336 break;
337 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS:
338 rc= MEMCACHED_DATA_EXISTS;
339 break;
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:
345 default:
346 /* @todo fix the error mappings */
347 rc= MEMCACHED_PROTOCOL_ERROR;
348 break;
349 }
350
351 return rc;
352 }