Mass rename to simplify names.
[m6w6/libmemcached] / libmemcached / 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
10 static memcached_return_t textual_read_one_response(memcached_server_st *ptr,
11 char *buffer, size_t buffer_length,
12 memcached_result_st *result);
13 static memcached_return_t binary_read_one_response(memcached_server_st *ptr,
14 char *buffer, size_t buffer_length,
15 memcached_result_st *result);
16
17 memcached_return_t memcached_read_one_response(memcached_server_st *ptr,
18 char *buffer, size_t buffer_length,
19 memcached_result_st *result)
20 {
21 memcached_server_response_decrement(ptr);
22
23 if (result == NULL)
24 result = &ptr->root->result;
25
26 memcached_return_t rc;
27 if (ptr->root->flags.binary_protocol)
28 rc= binary_read_one_response(ptr, buffer, buffer_length, result);
29 else
30 rc= textual_read_one_response(ptr, buffer, buffer_length, result);
31
32 unlikely(rc == MEMCACHED_UNKNOWN_READ_FAILURE ||
33 rc == MEMCACHED_PROTOCOL_ERROR ||
34 rc == MEMCACHED_CLIENT_ERROR ||
35 rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
36 memcached_io_reset(ptr);
37
38 return rc;
39 }
40
41 memcached_return_t memcached_response(memcached_server_st *ptr,
42 char *buffer, size_t buffer_length,
43 memcached_result_st *result)
44 {
45 /* We may have old commands in the buffer not set, first purge */
46 if (ptr->root->flags.no_block)
47 (void)memcached_io_write(ptr, NULL, 0, 1);
48
49 /*
50 * The previous implementation purged all pending requests and just
51 * returned the last one. Purge all pending messages to ensure backwards
52 * compatibility.
53 */
54 if (ptr->root->flags.binary_protocol == false)
55 while (memcached_server_response_count(ptr) > 1)
56 {
57 memcached_return_t rc= memcached_read_one_response(ptr, buffer, buffer_length, result);
58
59 unlikely (rc != MEMCACHED_END &&
60 rc != MEMCACHED_STORED &&
61 rc != MEMCACHED_SUCCESS &&
62 rc != MEMCACHED_STAT &&
63 rc != MEMCACHED_DELETED &&
64 rc != MEMCACHED_NOTFOUND &&
65 rc != MEMCACHED_NOTSTORED &&
66 rc != MEMCACHED_DATA_EXISTS)
67 return rc;
68 }
69
70 return memcached_read_one_response(ptr, buffer, buffer_length, result);
71 }
72
73 static memcached_return_t textual_value_fetch(memcached_server_st *ptr,
74 char *buffer,
75 memcached_result_st *result)
76 {
77 memcached_return_t rc= MEMCACHED_SUCCESS;
78 char *string_ptr;
79 char *end_ptr;
80 char *next_ptr;
81 size_t value_length;
82 size_t to_read;
83 char *value_ptr;
84
85 if (ptr->root->flags.use_udp)
86 return MEMCACHED_NOT_SUPPORTED;
87
88 WATCHPOINT_ASSERT(ptr->root);
89 end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
90
91 memcached_result_reset(result);
92
93 string_ptr= buffer;
94 string_ptr+= 6; /* "VALUE " */
95
96
97 /* We load the key */
98 {
99 char *key;
100 size_t prefix_length;
101
102 key= result->key;
103 result->key_length= 0;
104
105 for (prefix_length= ptr->root->prefix_key_length; !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++)
106 {
107 if (prefix_length == 0)
108 {
109 *key= *string_ptr;
110 key++;
111 result->key_length++;
112 }
113 else
114 prefix_length--;
115 }
116 result->key[result->key_length]= 0;
117 }
118
119 if (end_ptr == string_ptr)
120 goto read_error;
121
122 /* Flags fetch move past space */
123 string_ptr++;
124 if (end_ptr == string_ptr)
125 goto read_error;
126 for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
127 result->flags= (uint32_t) strtoul(next_ptr, &string_ptr, 10);
128
129 if (end_ptr == string_ptr)
130 goto read_error;
131
132 /* Length fetch move past space*/
133 string_ptr++;
134 if (end_ptr == string_ptr)
135 goto read_error;
136
137 for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
138 value_length= (size_t)strtoull(next_ptr, &string_ptr, 10);
139
140 if (end_ptr == string_ptr)
141 goto read_error;
142
143 /* Skip spaces */
144 if (*string_ptr == '\r')
145 {
146 /* Skip past the \r\n */
147 string_ptr+= 2;
148 }
149 else
150 {
151 string_ptr++;
152 for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
153 result->cas= strtoull(next_ptr, &string_ptr, 10);
154 }
155
156 if (end_ptr < string_ptr)
157 goto read_error;
158
159 /* We add two bytes so that we can walk the \r\n */
160 rc= memcached_string_check(&result->value, value_length+2);
161 if (rc != MEMCACHED_SUCCESS)
162 {
163 value_length= 0;
164 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
165 }
166
167 value_ptr= memcached_string_value(&result->value);
168 /*
169 We read the \r\n into the string since not doing so is more
170 cycles then the waster of memory to do so.
171
172 We are null terminating through, which will most likely make
173 some people lazy about using the return length.
174 */
175 to_read= (value_length) + 2;
176 ssize_t read_length= 0;
177 memcached_return_t rrc= memcached_io_read(ptr, value_ptr, to_read, &read_length);
178 if (rrc != MEMCACHED_SUCCESS)
179 return rrc;
180
181 if (read_length != (ssize_t)(value_length + 2))
182 {
183 goto read_error;
184 }
185
186 /* This next bit blows the API, but this is internal....*/
187 {
188 char *char_ptr;
189 char_ptr= memcached_string_value(&result->value);;
190 char_ptr[value_length]= 0;
191 char_ptr[value_length + 1]= 0;
192 memcached_string_set_length(&result->value, value_length);
193 }
194
195 return MEMCACHED_SUCCESS;
196
197 read_error:
198 memcached_io_reset(ptr);
199
200 return MEMCACHED_PARTIAL_READ;
201 }
202
203 static memcached_return_t textual_read_one_response(memcached_server_st *ptr,
204 char *buffer, size_t buffer_length,
205 memcached_result_st *result)
206 {
207 memcached_return_t rc= memcached_io_readline(ptr, buffer, buffer_length);
208 if (rc != MEMCACHED_SUCCESS)
209 return rc;
210
211 switch(buffer[0])
212 {
213 case 'V': /* VALUE || VERSION */
214 if (buffer[1] == 'A') /* VALUE */
215 {
216 /* We add back in one because we will need to search for END */
217 memcached_server_response_increment(ptr);
218 return textual_value_fetch(ptr, buffer, result);
219 }
220 else if (buffer[1] == 'E') /* VERSION */
221 {
222 return MEMCACHED_SUCCESS;
223 }
224 else
225 {
226 WATCHPOINT_STRING(buffer);
227 WATCHPOINT_ASSERT(0);
228 return MEMCACHED_UNKNOWN_READ_FAILURE;
229 }
230 case 'O': /* OK */
231 return MEMCACHED_SUCCESS;
232 case 'S': /* STORED STATS SERVER_ERROR */
233 {
234 if (buffer[2] == 'A') /* STORED STATS */
235 {
236 memcached_server_response_increment(ptr);
237 return MEMCACHED_STAT;
238 }
239 else if (buffer[1] == 'E') /* SERVER_ERROR */
240 {
241 char *rel_ptr;
242 char *startptr= buffer + 13, *endptr= startptr;
243
244 while (*endptr != '\r' && *endptr != '\n') endptr++;
245
246 /*
247 Yes, we could make this "efficent" but to do that we would need
248 to maintain more state for the size of the buffer. Why waste
249 memory in the struct, which is important, for something that
250 rarely should happen?
251 */
252 rel_ptr= (char *)ptr->root->call_realloc(ptr->root,
253 ptr->cached_server_error,
254 (size_t) (endptr - startptr + 1));
255
256 if (rel_ptr == NULL)
257 {
258 /* If we happened to have some memory, we just null it since we don't know the size */
259 if (ptr->cached_server_error)
260 ptr->cached_server_error[0]= 0;
261 return MEMCACHED_SERVER_ERROR;
262 }
263 ptr->cached_server_error= rel_ptr;
264
265 memcpy(ptr->cached_server_error, startptr, (size_t) (endptr - startptr));
266 ptr->cached_server_error[endptr - startptr]= 0;
267 return MEMCACHED_SERVER_ERROR;
268 }
269 else if (buffer[1] == 'T')
270 return MEMCACHED_STORED;
271 else
272 {
273 WATCHPOINT_STRING(buffer);
274 WATCHPOINT_ASSERT(0);
275 return MEMCACHED_UNKNOWN_READ_FAILURE;
276 }
277 }
278 case 'D': /* DELETED */
279 return MEMCACHED_DELETED;
280 case 'N': /* NOT_FOUND */
281 {
282 if (buffer[4] == 'F')
283 return MEMCACHED_NOTFOUND;
284 else if (buffer[4] == 'S')
285 return MEMCACHED_NOTSTORED;
286 else
287 return MEMCACHED_UNKNOWN_READ_FAILURE;
288 }
289 case 'E': /* PROTOCOL ERROR or END */
290 {
291 if (buffer[1] == 'N')
292 return MEMCACHED_END;
293 else if (buffer[1] == 'R')
294 return MEMCACHED_PROTOCOL_ERROR;
295 else if (buffer[1] == 'X')
296 return MEMCACHED_DATA_EXISTS;
297 else
298 return MEMCACHED_UNKNOWN_READ_FAILURE;
299 }
300 case 'I': /* CLIENT ERROR */
301 /* We add back in one because we will need to search for END */
302 memcached_server_response_increment(ptr);
303 return MEMCACHED_ITEM;
304 case 'C': /* CLIENT ERROR */
305 return MEMCACHED_CLIENT_ERROR;
306 default:
307 {
308 unsigned long long auto_return_value;
309
310 if (sscanf(buffer, "%llu", &auto_return_value) == 1)
311 return MEMCACHED_SUCCESS;
312
313 return MEMCACHED_UNKNOWN_READ_FAILURE;
314 }
315 }
316
317 /* NOTREACHED */
318 }
319
320 char *memcached_result_value(memcached_result_st *ptr)
321 {
322 memcached_string_st *sptr= &ptr->value;
323 return memcached_string_value(sptr);
324 }
325
326 size_t memcached_result_length(memcached_result_st *ptr)
327 {
328 memcached_string_st *sptr= &ptr->value;
329 return memcached_string_length(sptr);
330 }
331
332 static memcached_return_t binary_read_one_response(memcached_server_st *ptr,
333 char *buffer, size_t buffer_length,
334 memcached_result_st *result)
335 {
336 protocol_binary_response_header header;
337
338 unlikely (memcached_safe_read(ptr, &header.bytes,
339 sizeof(header.bytes)) != MEMCACHED_SUCCESS)
340 return MEMCACHED_UNKNOWN_READ_FAILURE;
341
342 unlikely (header.response.magic != PROTOCOL_BINARY_RES)
343 return MEMCACHED_PROTOCOL_ERROR;
344
345 /*
346 ** Convert the header to host local endian!
347 */
348 header.response.keylen= ntohs(header.response.keylen);
349 header.response.status= ntohs(header.response.status);
350 header.response.bodylen= ntohl(header.response.bodylen);
351 header.response.cas= ntohll(header.response.cas);
352 uint32_t bodylen= header.response.bodylen;
353
354 if (header.response.status == 0)
355 {
356 switch (header.response.opcode)
357 {
358 case PROTOCOL_BINARY_CMD_GETKQ:
359 /*
360 * We didn't increment the response counter for the GETKQ packet
361 * (only the final NOOP), so we need to increment the counter again.
362 */
363 memcached_server_response_increment(ptr);
364 /* FALLTHROUGH */
365 case PROTOCOL_BINARY_CMD_GETK:
366 {
367 uint16_t keylen= header.response.keylen;
368 memcached_result_reset(result);
369 result->cas= header.response.cas;
370
371 if (memcached_safe_read(ptr, &result->flags,
372 sizeof (result->flags)) != MEMCACHED_SUCCESS)
373 return MEMCACHED_UNKNOWN_READ_FAILURE;
374
375 result->flags= ntohl(result->flags);
376 bodylen -= header.response.extlen;
377
378 result->key_length= keylen;
379 if (memcached_safe_read(ptr, result->key, keylen) != MEMCACHED_SUCCESS)
380 return MEMCACHED_UNKNOWN_READ_FAILURE;
381
382 bodylen -= keylen;
383 if (memcached_string_check(&result->value,
384 bodylen) != MEMCACHED_SUCCESS)
385 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
386
387 char *vptr= memcached_string_value(&result->value);
388 if (memcached_safe_read(ptr, vptr, bodylen) != MEMCACHED_SUCCESS)
389 return MEMCACHED_UNKNOWN_READ_FAILURE;
390
391 memcached_string_set_length(&result->value, bodylen);
392 }
393 break;
394 case PROTOCOL_BINARY_CMD_INCREMENT:
395 case PROTOCOL_BINARY_CMD_DECREMENT:
396 {
397 if (bodylen != sizeof(uint64_t) || buffer_length != sizeof(uint64_t))
398 return MEMCACHED_PROTOCOL_ERROR;
399
400 WATCHPOINT_ASSERT(bodylen == buffer_length);
401 uint64_t val;
402 if (memcached_safe_read(ptr, &val, sizeof(val)) != MEMCACHED_SUCCESS)
403 return MEMCACHED_UNKNOWN_READ_FAILURE;
404
405 val= ntohll(val);
406 memcpy(buffer, &val, sizeof(val));
407 }
408 break;
409 case PROTOCOL_BINARY_CMD_VERSION:
410 {
411 memset(buffer, 0, buffer_length);
412 if (bodylen >= buffer_length)
413 /* not enough space in buffer.. should not happen... */
414 return MEMCACHED_UNKNOWN_READ_FAILURE;
415 else if (memcached_safe_read(ptr, buffer, bodylen) != MEMCACHED_SUCCESS)
416 return MEMCACHED_UNKNOWN_READ_FAILURE;
417 }
418 break;
419 case PROTOCOL_BINARY_CMD_FLUSH:
420 case PROTOCOL_BINARY_CMD_QUIT:
421 case PROTOCOL_BINARY_CMD_SET:
422 case PROTOCOL_BINARY_CMD_ADD:
423 case PROTOCOL_BINARY_CMD_REPLACE:
424 case PROTOCOL_BINARY_CMD_APPEND:
425 case PROTOCOL_BINARY_CMD_PREPEND:
426 case PROTOCOL_BINARY_CMD_DELETE:
427 {
428 WATCHPOINT_ASSERT(bodylen == 0);
429 return MEMCACHED_SUCCESS;
430 }
431 case PROTOCOL_BINARY_CMD_NOOP:
432 {
433 WATCHPOINT_ASSERT(bodylen == 0);
434 return MEMCACHED_END;
435 }
436 case PROTOCOL_BINARY_CMD_STAT:
437 {
438 if (bodylen == 0)
439 return MEMCACHED_END;
440 else if (bodylen + 1 > buffer_length)
441 /* not enough space in buffer.. should not happen... */
442 return MEMCACHED_UNKNOWN_READ_FAILURE;
443 else
444 {
445 size_t keylen= header.response.keylen;
446 memset(buffer, 0, buffer_length);
447 if (memcached_safe_read(ptr, buffer, keylen) != MEMCACHED_SUCCESS ||
448 memcached_safe_read(ptr, buffer + keylen + 1,
449 bodylen - keylen) != MEMCACHED_SUCCESS)
450 return MEMCACHED_UNKNOWN_READ_FAILURE;
451 }
452 }
453 break;
454 default:
455 {
456 /* Command not implemented yet! */
457 WATCHPOINT_ASSERT(0);
458 return MEMCACHED_PROTOCOL_ERROR;
459 }
460 }
461 }
462 else if (header.response.bodylen)
463 {
464 /* What should I do with the error message??? just discard it for now */
465 char hole[SMALL_STRING_LEN];
466 while (bodylen > 0)
467 {
468 size_t nr= (bodylen > SMALL_STRING_LEN) ? SMALL_STRING_LEN : bodylen;
469 if (memcached_safe_read(ptr, hole, nr) != MEMCACHED_SUCCESS)
470 return MEMCACHED_UNKNOWN_READ_FAILURE;
471 bodylen-= (uint32_t) nr;
472 }
473
474 /* This might be an error from one of the quiet commands.. if
475 * so, just throw it away and get the next one. What about creating
476 * a callback to the user with the error information?
477 */
478 switch (header.response.opcode)
479 {
480 case PROTOCOL_BINARY_CMD_SETQ:
481 case PROTOCOL_BINARY_CMD_ADDQ:
482 case PROTOCOL_BINARY_CMD_REPLACEQ:
483 case PROTOCOL_BINARY_CMD_APPENDQ:
484 case PROTOCOL_BINARY_CMD_PREPENDQ:
485 return binary_read_one_response(ptr, buffer, buffer_length, result);
486 default:
487 break;
488 }
489 }
490
491 memcached_return_t rc= MEMCACHED_SUCCESS;
492 unlikely(header.response.status != 0)
493 switch (header.response.status)
494 {
495 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT:
496 rc= MEMCACHED_NOTFOUND;
497 break;
498 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS:
499 rc= MEMCACHED_DATA_EXISTS;
500 break;
501 case PROTOCOL_BINARY_RESPONSE_NOT_STORED:
502 rc= MEMCACHED_NOTSTORED;
503 break;
504 case PROTOCOL_BINARY_RESPONSE_E2BIG:
505 rc= MEMCACHED_E2BIG;
506 break;
507 case PROTOCOL_BINARY_RESPONSE_ENOMEM:
508 rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
509 break;
510 case PROTOCOL_BINARY_RESPONSE_EINVAL:
511 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
512 default:
513 /* @todo fix the error mappings */
514 rc= MEMCACHED_PROTOCOL_ERROR;
515 break;
516 }
517
518 return rc;
519 }