replace memcached_readline with memcached_io_readline
[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 memcached_return rc= memcached_read_one_response(ptr, buffer, buffer_length, result);
55
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)
64 return rc;
65 }
66
67 return memcached_read_one_response(ptr, buffer, buffer_length, result);
68 }
69
70 static memcached_return textual_read_one_response(memcached_server_st *ptr,
71 char *buffer, size_t buffer_length,
72 memcached_result_st *result)
73 {
74 memcached_return rc= memcached_io_readline(ptr, buffer, buffer_length);
75 if (rc != MEMCACHED_SUCCESS)
76 return rc;
77
78 switch(buffer[0])
79 {
80 case 'V': /* VALUE || VERSION */
81 if (buffer[1] == 'A') /* VALUE */
82 {
83 memcached_return rc;
84
85 /* We add back in one because we will need to search for END */
86 memcached_server_response_increment(ptr);
87 if (result)
88 rc= value_fetch(ptr, buffer, result);
89 else
90 rc= value_fetch(ptr, buffer, &ptr->root->result);
91
92 return rc;
93 }
94 else if (buffer[1] == 'E') /* VERSION */
95 {
96 return MEMCACHED_SUCCESS;
97 }
98 else
99 {
100 WATCHPOINT_STRING(buffer);
101 WATCHPOINT_ASSERT(0);
102 return MEMCACHED_UNKNOWN_READ_FAILURE;
103 }
104 case 'O': /* OK */
105 return MEMCACHED_SUCCESS;
106 case 'S': /* STORED STATS SERVER_ERROR */
107 {
108 if (buffer[2] == 'A') /* STORED STATS */
109 {
110 memcached_server_response_increment(ptr);
111 return MEMCACHED_STAT;
112 }
113 else if (buffer[1] == 'E')
114 return MEMCACHED_SERVER_ERROR;
115 else if (buffer[1] == 'T')
116 return MEMCACHED_STORED;
117 else
118 {
119 WATCHPOINT_STRING(buffer);
120 WATCHPOINT_ASSERT(0);
121 return MEMCACHED_UNKNOWN_READ_FAILURE;
122 }
123 }
124 case 'D': /* DELETED */
125 return MEMCACHED_DELETED;
126 case 'N': /* NOT_FOUND */
127 {
128 if (buffer[4] == 'F')
129 return MEMCACHED_NOTFOUND;
130 else if (buffer[4] == 'S')
131 return MEMCACHED_NOTSTORED;
132 else
133 return MEMCACHED_UNKNOWN_READ_FAILURE;
134 }
135 case 'E': /* PROTOCOL ERROR or END */
136 {
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;
143 else
144 return MEMCACHED_UNKNOWN_READ_FAILURE;
145 }
146 case 'C': /* CLIENT ERROR */
147 return MEMCACHED_CLIENT_ERROR;
148 default:
149 {
150 unsigned long long auto_return_value;
151
152 if (sscanf(buffer, "%llu", &auto_return_value) == 1)
153 return MEMCACHED_SUCCESS;
154
155 return MEMCACHED_UNKNOWN_READ_FAILURE;
156 }
157 }
158
159 return MEMCACHED_SUCCESS;
160 }
161
162 char *memcached_result_value(memcached_result_st *ptr)
163 {
164 memcached_string_st *sptr= &ptr->value;
165 return memcached_string_value(sptr);
166 }
167
168 size_t memcached_result_length(memcached_result_st *ptr)
169 {
170 memcached_string_st *sptr= &ptr->value;
171 return memcached_string_length(sptr);
172 }
173
174 static memcached_return binary_read_one_response(memcached_server_st *ptr,
175 char *buffer, size_t buffer_length,
176 memcached_result_st *result)
177 {
178 protocol_binary_response_header header;
179
180 unlikely (memcached_safe_read(ptr, &header.bytes,
181 sizeof(header.bytes)) != MEMCACHED_SUCCESS)
182 return MEMCACHED_UNKNOWN_READ_FAILURE;
183
184 unlikely (header.response.magic != PROTOCOL_BINARY_RES)
185 return MEMCACHED_PROTOCOL_ERROR;
186
187 /*
188 ** Convert the header to host local endian!
189 */
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;
195
196 if (header.response.status == 0)
197 {
198 switch (header.response.opcode)
199 {
200 case PROTOCOL_BINARY_CMD_GETK:
201 case PROTOCOL_BINARY_CMD_GETKQ:
202 {
203 uint16_t keylen= header.response.keylen;
204 memcached_result_reset(result);
205 result->cas= header.response.cas;
206
207 if (memcached_safe_read(ptr, &result->flags,
208 sizeof (result->flags)) != MEMCACHED_SUCCESS)
209 return MEMCACHED_UNKNOWN_READ_FAILURE;
210
211 result->flags= ntohl(result->flags);
212 bodylen -= header.response.extlen;
213
214 result->key_length= keylen;
215 if (memcached_safe_read(ptr, result->key, keylen) != MEMCACHED_SUCCESS)
216 return MEMCACHED_UNKNOWN_READ_FAILURE;
217
218 bodylen -= keylen;
219 if (memcached_string_check(&result->value,
220 bodylen) != MEMCACHED_SUCCESS)
221 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
222
223 char *vptr= memcached_string_value(&result->value);
224 if (memcached_safe_read(ptr, vptr, bodylen) != MEMCACHED_SUCCESS)
225 return MEMCACHED_UNKNOWN_READ_FAILURE;
226
227 memcached_string_set_length(&result->value, bodylen);
228 }
229 break;
230 case PROTOCOL_BINARY_CMD_INCREMENT:
231 case PROTOCOL_BINARY_CMD_DECREMENT:
232 {
233 if (bodylen != sizeof(uint64_t) || buffer_length != sizeof(uint64_t))
234 return MEMCACHED_PROTOCOL_ERROR;
235
236 WATCHPOINT_ASSERT(bodylen == buffer_length);
237 uint64_t val;
238 if (memcached_safe_read(ptr, &val, sizeof(val)) != MEMCACHED_SUCCESS)
239 return MEMCACHED_UNKNOWN_READ_FAILURE;
240
241 val= ntohll(val);
242 memcpy(buffer, &val, sizeof(val));
243 }
244 break;
245 case PROTOCOL_BINARY_CMD_VERSION:
246 {
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;
253 }
254 break;
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:
263 {
264 WATCHPOINT_ASSERT(bodylen == 0);
265 return MEMCACHED_SUCCESS;
266 }
267 break;
268 case PROTOCOL_BINARY_CMD_NOOP:
269 {
270 WATCHPOINT_ASSERT(bodylen == 0);
271 return MEMCACHED_END;
272 }
273 break;
274 case PROTOCOL_BINARY_CMD_STAT:
275 {
276 if (bodylen == 0)
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;
281 else
282 {
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;
289 }
290 }
291 break;
292 default:
293 {
294 /* Command not implemented yet! */
295 WATCHPOINT_ASSERT(0);
296 return MEMCACHED_PROTOCOL_ERROR;
297 }
298 }
299 }
300 else if (header.response.bodylen)
301 {
302 /* What should I do with the error message??? just discard it for now */
303 char buffer[SMALL_STRING_LEN];
304 while (bodylen > 0)
305 {
306 size_t nr= (bodylen > SMALL_STRING_LEN) ? SMALL_STRING_LEN : bodylen;
307 if (memcached_safe_read(ptr, buffer, nr) != MEMCACHED_SUCCESS)
308 return MEMCACHED_UNKNOWN_READ_FAILURE;
309 bodylen -= nr;
310 }
311 }
312
313 memcached_return rc= MEMCACHED_SUCCESS;
314 unlikely(header.response.status != 0)
315 switch (header.response.status)
316 {
317 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT:
318 rc= MEMCACHED_NOTFOUND;
319 break;
320 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS:
321 rc= MEMCACHED_DATA_EXISTS;
322 break;
323 case PROTOCOL_BINARY_RESPONSE_E2BIG:
324 case PROTOCOL_BINARY_RESPONSE_EINVAL:
325 case PROTOCOL_BINARY_RESPONSE_NOT_STORED:
326 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
327 case PROTOCOL_BINARY_RESPONSE_ENOMEM:
328 default:
329 /* @todo fix the error mappings */
330 rc= MEMCACHED_PROTOCOL_ERROR;
331 break;
332 }
333
334 return rc;
335 }