Clean up the ASCII parser.
[m6w6/libmemcached] / libmemcached / response.cc
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * Libmemcached library
4 *
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
6 * Copyright (C) 2006-2009 Brian Aker All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37
38 #include <libmemcached/common.h>
39 #include <libmemcached/string.hpp>
40
41 static memcached_return_t textual_read_one_response(memcached_server_write_instance_st ptr,
42 char *buffer, size_t buffer_length,
43 memcached_result_st *result);
44 static memcached_return_t binary_read_one_response(memcached_server_write_instance_st ptr,
45 char *buffer, size_t buffer_length,
46 memcached_result_st *result);
47
48 memcached_return_t memcached_read_one_response(memcached_server_write_instance_st ptr,
49 char *buffer, size_t buffer_length,
50 memcached_result_st *result)
51 {
52 memcached_server_response_decrement(ptr);
53
54 if (result == NULL)
55 {
56 memcached_st *root= (memcached_st *)ptr->root;
57 result = &root->result;
58 }
59
60 memcached_return_t rc;
61 if (ptr->root->flags.binary_protocol)
62 {
63 rc= binary_read_one_response(ptr, buffer, buffer_length, result);
64 }
65 else
66 {
67 rc= textual_read_one_response(ptr, buffer, buffer_length, result);
68 }
69
70 unlikely(rc == MEMCACHED_UNKNOWN_READ_FAILURE or
71 rc == MEMCACHED_PROTOCOL_ERROR or
72 rc == MEMCACHED_CLIENT_ERROR or
73 rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
74 {
75 memcached_io_reset(ptr);
76 }
77
78 return rc;
79 }
80
81 memcached_return_t memcached_response(memcached_server_write_instance_st ptr,
82 char *buffer, size_t buffer_length,
83 memcached_result_st *result)
84 {
85 /* We may have old commands in the buffer not set, first purge */
86 if ((ptr->root->flags.no_block) && (memcached_is_processing_input(ptr->root) == false))
87 {
88 (void)memcached_io_write(ptr, NULL, 0, true);
89 }
90
91 /*
92 * The previous implementation purged all pending requests and just
93 * returned the last one. Purge all pending messages to ensure backwards
94 * compatibility.
95 */
96 if (ptr->root->flags.binary_protocol == false)
97 {
98 while (memcached_server_response_count(ptr) > 1)
99 {
100 memcached_return_t rc= memcached_read_one_response(ptr, buffer, buffer_length, result);
101
102 unlikely (rc != MEMCACHED_END &&
103 rc != MEMCACHED_STORED &&
104 rc != MEMCACHED_SUCCESS &&
105 rc != MEMCACHED_STAT &&
106 rc != MEMCACHED_DELETED &&
107 rc != MEMCACHED_NOTFOUND &&
108 rc != MEMCACHED_NOTSTORED &&
109 rc != MEMCACHED_DATA_EXISTS)
110 return rc;
111 }
112 }
113
114 return memcached_read_one_response(ptr, buffer, buffer_length, result);
115 }
116
117 static memcached_return_t textual_value_fetch(memcached_server_write_instance_st ptr,
118 char *buffer,
119 memcached_result_st *result)
120 {
121 char *string_ptr;
122 char *end_ptr;
123 char *next_ptr;
124 size_t value_length;
125 size_t to_read;
126 ssize_t read_length= 0;
127
128 if (ptr->root->flags.use_udp)
129 {
130 return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
131 }
132
133 WATCHPOINT_ASSERT(ptr->root);
134 end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
135
136 memcached_result_reset(result);
137
138 string_ptr= buffer;
139 string_ptr+= 6; /* "VALUE " */
140
141
142 /* We load the key */
143 {
144 char *key;
145 size_t prefix_length;
146
147 key= result->item_key;
148 result->key_length= 0;
149
150 for (prefix_length= memcached_array_size(ptr->root->_namespace); !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++)
151 {
152 if (prefix_length == 0)
153 {
154 *key= *string_ptr;
155 key++;
156 result->key_length++;
157 }
158 else
159 prefix_length--;
160 }
161 result->item_key[result->key_length]= 0;
162 }
163
164 if (end_ptr == string_ptr)
165 goto read_error;
166
167 /* Flags fetch move past space */
168 string_ptr++;
169 if (end_ptr == string_ptr)
170 goto read_error;
171
172 for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++) {};
173 result->item_flags= (uint32_t) strtoul(next_ptr, &string_ptr, 10);
174
175 if (end_ptr == string_ptr)
176 goto read_error;
177
178 /* Length fetch move past space*/
179 string_ptr++;
180 if (end_ptr == string_ptr)
181 goto read_error;
182
183 for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++) {};
184 value_length= (size_t)strtoull(next_ptr, &string_ptr, 10);
185
186 if (end_ptr == string_ptr)
187 {
188 goto read_error;
189 }
190
191 /* Skip spaces */
192 if (*string_ptr == '\r')
193 {
194 /* Skip past the \r\n */
195 string_ptr+= 2;
196 }
197 else
198 {
199 string_ptr++;
200 for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++) {};
201 result->item_cas= strtoull(next_ptr, &string_ptr, 10);
202 }
203
204 if (end_ptr < string_ptr)
205 goto read_error;
206
207 /* We add two bytes so that we can walk the \r\n */
208 if (memcached_failed(memcached_string_check(&result->value, value_length +2)))
209 {
210 return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
211 }
212
213 {
214 char *value_ptr= memcached_string_value_mutable(&result->value);
215 /*
216 We read the \r\n into the string since not doing so is more
217 cycles then the waster of memory to do so.
218
219 We are null terminating through, which will most likely make
220 some people lazy about using the return length.
221 */
222 to_read= (value_length) + 2;
223 memcached_return_t rrc= memcached_io_read(ptr, value_ptr, to_read, &read_length);
224 if (memcached_failed(rrc) and rrc == MEMCACHED_IN_PROGRESS)
225 {
226 memcached_quit_server(ptr, true);
227 return memcached_set_error(*ptr, MEMCACHED_IN_PROGRESS, MEMCACHED_AT);
228 }
229 else if (memcached_failed(rrc))
230 {
231 return rrc;
232 }
233 }
234
235 if (read_length != (ssize_t)(value_length + 2))
236 {
237 goto read_error;
238 }
239
240 /* This next bit blows the API, but this is internal....*/
241 {
242 char *char_ptr;
243 char_ptr= memcached_string_value_mutable(&result->value);;
244 char_ptr[value_length]= 0;
245 char_ptr[value_length +1]= 0;
246 memcached_string_set_length(&result->value, value_length);
247 }
248
249 return MEMCACHED_SUCCESS;
250
251 read_error:
252 memcached_io_reset(ptr);
253
254 return MEMCACHED_PARTIAL_READ;
255 }
256
257 static memcached_return_t textual_read_one_response(memcached_server_write_instance_st ptr,
258 char *buffer, size_t buffer_length,
259 memcached_result_st *result)
260 {
261 size_t total_read;
262 memcached_return_t rc= memcached_io_readline(ptr, buffer, buffer_length, total_read);
263
264 if (memcached_failed(rc))
265 {
266 return rc;
267 }
268
269 switch(buffer[0])
270 {
271 case 'V': /* VALUE || VERSION */
272 if (buffer[1] == 'A' and buffer[2] == 'L' and buffer[3] == 'U' and buffer[4] == 'E') /* VALUE */
273 {
274 /* We add back in one because we will need to search for END */
275 memcached_server_response_increment(ptr);
276 return textual_value_fetch(ptr, buffer, result);
277 }
278 else if (buffer[1] == 'E' and buffer[2] == 'R' and buffer[3] == 'S' and buffer[4] == 'I' and buffer[5] == 'O' and buffer[6] == 'N') /* VERSION */
279 {
280 return MEMCACHED_SUCCESS;
281 }
282 break;
283
284 case 'O': /* OK */
285 if (buffer[1] == 'K')
286 {
287 return MEMCACHED_SUCCESS;
288 }
289 break;
290
291 case 'S': /* STORED STATS SERVER_ERROR */
292 {
293 if (buffer[1] == 'T' and buffer[2] == 'A' and buffer[3] == 'T') /* STORED STATS */
294 {
295 memcached_server_response_increment(ptr);
296 return MEMCACHED_STAT;
297 }
298 else if (buffer[1] == 'E' and buffer[2] == 'R' and buffer[3] == 'V' and buffer[4] == 'E' and buffer[5] == 'R'
299 and buffer[6] == '_'
300 and buffer[7] == 'E' and buffer[8] == 'R' and buffer[9] == 'R' and buffer[10] == 'O' and buffer[11] == 'R' ) /* SERVER_ERROR */
301 {
302 if (total_read == memcached_literal_param_size("SERVER_ERROR"))
303 {
304 return MEMCACHED_SERVER_ERROR;
305 }
306
307 if (total_read > memcached_literal_param_size("SERVER_ERROR object too large for cache") and
308 (memcmp(buffer, memcached_literal_param("SERVER_ERROR object too large for cache")) == 0))
309 {
310 return MEMCACHED_E2BIG;
311 }
312
313 // Move past the basic error message and whitespace
314 char *startptr= buffer + memcached_literal_param_size("SERVER_ERROR");
315 if (startptr[0] == ' ')
316 {
317 startptr++;
318 }
319
320 char *endptr= startptr;
321 while (*endptr != '\r' && *endptr != '\n') endptr++;
322
323 return memcached_set_error(*ptr, MEMCACHED_SERVER_ERROR, MEMCACHED_AT, startptr, size_t(endptr - startptr));
324 }
325 else if (buffer[1] == 'T' and buffer[2] == 'O' and buffer[3] == 'R' and buffer[4] == 'E' and buffer[5] == 'D')
326 {
327 return MEMCACHED_STORED;
328 }
329 }
330 break;
331
332 case 'D': /* DELETED */
333 if (buffer[1] == 'E' and buffer[2] == 'L' and buffer[3] == 'E' and buffer[4] == 'T' and buffer[5] == 'E' and buffer[6] == 'D')
334 {
335 return MEMCACHED_DELETED;
336 }
337 break;
338
339 case 'N': /* NOT_FOUND */
340 {
341 if (buffer[1] == 'O' and buffer[2] == 'T'
342 and buffer[3] == '_'
343 and buffer[4] == 'F' and buffer[5] == 'O' and buffer[6] == 'U' and buffer[7] == 'N' and buffer[8] == 'D')
344 {
345 return MEMCACHED_NOTFOUND;
346 }
347 else if (buffer[1] == 'O' and buffer[2] == 'T'
348 and buffer[3] == '_'
349 and buffer[4] == 'S' and buffer[5] == 'T' and buffer[6] == 'O' and buffer[7] == 'R' and buffer[8] == 'E' and buffer[9] == 'D')
350 {
351 return MEMCACHED_NOTSTORED;
352 }
353 }
354 break;
355
356 case 'E': /* PROTOCOL ERROR or END */
357 {
358 if (buffer[1] == 'N' and buffer[2] == 'D')
359 {
360 return MEMCACHED_END;
361 }
362 else if (buffer[1] == 'R' and buffer[2] == 'R' and buffer[3] == 'O' and buffer[4] == 'R')
363 {
364 return MEMCACHED_PROTOCOL_ERROR;
365 }
366 else if (buffer[1] == 'X' and buffer[2] == 'I' and buffer[3] == 'S' and buffer[4] == 'T' and buffer[5] == 'S')
367 {
368 return MEMCACHED_DATA_EXISTS;
369 }
370 }
371 break;
372
373 case 'T': /* TOUCHED */
374 {
375 if (buffer[1] == 'O' and buffer[2] == 'U' and buffer[3] == 'C' and buffer[4] == 'H' and buffer[5] == 'E' and buffer[6] == 'D')
376 {
377 return MEMCACHED_SUCCESS;
378 }
379 }
380 break;
381
382 case 'I': /* ITEM */
383 if (buffer[1] == 'T' and buffer[2] == 'E' and buffer[3] == 'M')
384 {
385 /* We add back in one because we will need to search for END */
386 memcached_server_response_increment(ptr);
387 return MEMCACHED_ITEM;
388 }
389 break;
390
391 case 'C': /* CLIENT ERROR */
392 if (buffer[1] == 'L' and buffer[2] == 'I' and buffer[3] == 'E' and buffer[4] == 'N' and buffer[5] == 'T')
393 {
394 return MEMCACHED_CLIENT_ERROR;
395 }
396 break;
397
398 case '0': /* INCR/DECR response */
399 case '1': /* INCR/DECR response */
400 case '2': /* INCR/DECR response */
401 case '3': /* INCR/DECR response */
402 case '4': /* INCR/DECR response */
403 case '5': /* INCR/DECR response */
404 case '6': /* INCR/DECR response */
405 case '7': /* INCR/DECR response */
406 case '8': /* INCR/DECR response */
407 case '9': /* INCR/DECR response */
408 {
409 unsigned long long int auto_return_value= strtoull(buffer, (char **)NULL, 10);
410
411 if (auto_return_value == ULLONG_MAX and errno == ERANGE)
412 {
413 return MEMCACHED_UNKNOWN_READ_FAILURE;
414 }
415 else if (errno == EINVAL)
416 {
417 return MEMCACHED_UNKNOWN_READ_FAILURE;
418 }
419
420 WATCHPOINT_STRING(buffer);
421 return MEMCACHED_SUCCESS;
422 }
423
424 default:
425 break;
426 }
427
428 return MEMCACHED_UNKNOWN_READ_FAILURE;
429 }
430
431 static memcached_return_t binary_read_one_response(memcached_server_write_instance_st ptr,
432 char *buffer, size_t buffer_length,
433 memcached_result_st *result)
434 {
435 memcached_return_t rc;
436 protocol_binary_response_header header;
437
438 if ((rc= memcached_safe_read(ptr, &header.bytes, sizeof(header.bytes))) != MEMCACHED_SUCCESS)
439 {
440 WATCHPOINT_ERROR(rc);
441 return rc;
442 }
443
444 if (header.response.magic != PROTOCOL_BINARY_RES)
445 {
446 return MEMCACHED_PROTOCOL_ERROR;
447 }
448
449 /*
450 ** Convert the header to host local endian!
451 */
452 header.response.keylen= ntohs(header.response.keylen);
453 header.response.status= ntohs(header.response.status);
454 header.response.bodylen= ntohl(header.response.bodylen);
455 header.response.cas= memcached_ntohll(header.response.cas);
456 uint32_t bodylen= header.response.bodylen;
457
458 if (header.response.status == PROTOCOL_BINARY_RESPONSE_SUCCESS or
459 header.response.status == PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE)
460 {
461 switch (header.response.opcode)
462 {
463 case PROTOCOL_BINARY_CMD_GETKQ:
464 /*
465 * We didn't increment the response counter for the GETKQ packet
466 * (only the final NOOP), so we need to increment the counter again.
467 */
468 memcached_server_response_increment(ptr);
469 /* FALLTHROUGH */
470 case PROTOCOL_BINARY_CMD_GETK:
471 {
472 uint16_t keylen= header.response.keylen;
473 memcached_result_reset(result);
474 result->item_cas= header.response.cas;
475
476 if ((rc= memcached_safe_read(ptr, &result->item_flags, sizeof (result->item_flags))) != MEMCACHED_SUCCESS)
477 {
478 WATCHPOINT_ERROR(rc);
479 return MEMCACHED_UNKNOWN_READ_FAILURE;
480 }
481
482 result->item_flags= ntohl(result->item_flags);
483 bodylen -= header.response.extlen;
484
485 result->key_length= keylen;
486 if (memcached_failed(rc= memcached_safe_read(ptr, result->item_key, keylen)))
487 {
488 WATCHPOINT_ERROR(rc);
489 return MEMCACHED_UNKNOWN_READ_FAILURE;
490 }
491
492 // Only bother with doing this if key_length > 0
493 if (result->key_length)
494 {
495 if (memcached_array_size(ptr->root->_namespace) and memcached_array_size(ptr->root->_namespace) >= result->key_length)
496 {
497 return memcached_set_error(*ptr, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
498 }
499
500 if (memcached_array_size(ptr->root->_namespace))
501 {
502 result->key_length-= memcached_array_size(ptr->root->_namespace);
503 memmove(result->item_key, result->item_key +memcached_array_size(ptr->root->_namespace), result->key_length);
504 }
505 }
506
507 bodylen -= keylen;
508 if (memcached_failed(memcached_string_check(&result->value, bodylen)))
509 {
510 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
511 }
512
513 char *vptr= memcached_string_value_mutable(&result->value);
514 if (memcached_failed(rc= memcached_safe_read(ptr, vptr, bodylen)))
515 {
516 WATCHPOINT_ERROR(rc);
517 return MEMCACHED_UNKNOWN_READ_FAILURE;
518 }
519
520 memcached_string_set_length(&result->value, bodylen);
521 }
522 break;
523
524 case PROTOCOL_BINARY_CMD_INCREMENT:
525 case PROTOCOL_BINARY_CMD_DECREMENT:
526 {
527 if (bodylen != sizeof(uint64_t) || buffer_length != sizeof(uint64_t))
528 {
529 return MEMCACHED_PROTOCOL_ERROR;
530 }
531
532 WATCHPOINT_ASSERT(bodylen == buffer_length);
533 uint64_t val;
534 if ((rc= memcached_safe_read(ptr, &val, sizeof(val))) != MEMCACHED_SUCCESS)
535 {
536 WATCHPOINT_ERROR(rc);
537 return MEMCACHED_UNKNOWN_READ_FAILURE;
538 }
539
540 val= memcached_ntohll(val);
541 memcpy(buffer, &val, sizeof(val));
542 }
543 break;
544
545 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS:
546 case PROTOCOL_BINARY_CMD_VERSION:
547 {
548 memset(buffer, 0, buffer_length);
549 if (bodylen >= buffer_length)
550 {
551 /* not enough space in buffer.. should not happen... */
552 return MEMCACHED_UNKNOWN_READ_FAILURE;
553 }
554 else if ((rc= memcached_safe_read(ptr, buffer, bodylen)) != MEMCACHED_SUCCESS)
555 {
556 WATCHPOINT_ERROR(rc);
557 return MEMCACHED_UNKNOWN_READ_FAILURE;
558 }
559 }
560 break;
561 case PROTOCOL_BINARY_CMD_FLUSH:
562 case PROTOCOL_BINARY_CMD_QUIT:
563 case PROTOCOL_BINARY_CMD_SET:
564 case PROTOCOL_BINARY_CMD_ADD:
565 case PROTOCOL_BINARY_CMD_REPLACE:
566 case PROTOCOL_BINARY_CMD_APPEND:
567 case PROTOCOL_BINARY_CMD_PREPEND:
568 case PROTOCOL_BINARY_CMD_DELETE:
569 case PROTOCOL_BINARY_CMD_TOUCH:
570 {
571 WATCHPOINT_ASSERT(bodylen == 0);
572 return MEMCACHED_SUCCESS;
573 }
574
575 case PROTOCOL_BINARY_CMD_NOOP:
576 {
577 WATCHPOINT_ASSERT(bodylen == 0);
578 return MEMCACHED_END;
579 }
580
581 case PROTOCOL_BINARY_CMD_STAT:
582 {
583 if (bodylen == 0)
584 {
585 return MEMCACHED_END;
586 }
587 else if (bodylen + 1 > buffer_length)
588 {
589 /* not enough space in buffer.. should not happen... */
590 return MEMCACHED_UNKNOWN_READ_FAILURE;
591 }
592 else
593 {
594 size_t keylen= header.response.keylen;
595 memset(buffer, 0, buffer_length);
596 if ((rc= memcached_safe_read(ptr, buffer, keylen)) != MEMCACHED_SUCCESS ||
597 (rc= memcached_safe_read(ptr, buffer + keylen + 1, bodylen - keylen)) != MEMCACHED_SUCCESS)
598 {
599 WATCHPOINT_ERROR(rc);
600 return MEMCACHED_UNKNOWN_READ_FAILURE;
601 }
602 }
603 }
604 break;
605
606 case PROTOCOL_BINARY_CMD_SASL_AUTH:
607 case PROTOCOL_BINARY_CMD_SASL_STEP:
608 {
609 memcached_result_reset(result);
610 result->item_cas= header.response.cas;
611
612 if (memcached_string_check(&result->value,
613 bodylen) != MEMCACHED_SUCCESS)
614 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
615
616 char *vptr= memcached_string_value_mutable(&result->value);
617 if ((rc= memcached_safe_read(ptr, vptr, bodylen)) != MEMCACHED_SUCCESS)
618 {
619 WATCHPOINT_ERROR(rc);
620 return MEMCACHED_UNKNOWN_READ_FAILURE;
621 }
622
623 memcached_string_set_length(&result->value, bodylen);
624 }
625 break;
626 default:
627 {
628 /* Command not implemented yet! */
629 WATCHPOINT_ASSERT(0);
630 return MEMCACHED_PROTOCOL_ERROR;
631 }
632 }
633 }
634 else if (header.response.bodylen)
635 {
636 /* What should I do with the error message??? just discard it for now */
637 char hole[SMALL_STRING_LEN];
638 while (bodylen > 0)
639 {
640 size_t nr= (bodylen > SMALL_STRING_LEN) ? SMALL_STRING_LEN : bodylen;
641 if ((rc= memcached_safe_read(ptr, hole, nr)) != MEMCACHED_SUCCESS)
642 {
643 WATCHPOINT_ERROR(rc);
644 return memcached_set_error(*ptr, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
645 }
646 bodylen-= (uint32_t) nr;
647 }
648
649 /* This might be an error from one of the quiet commands.. if
650 * so, just throw it away and get the next one. What about creating
651 * a callback to the user with the error information?
652 */
653 switch (header.response.opcode)
654 {
655 case PROTOCOL_BINARY_CMD_SETQ:
656 case PROTOCOL_BINARY_CMD_ADDQ:
657 case PROTOCOL_BINARY_CMD_REPLACEQ:
658 case PROTOCOL_BINARY_CMD_APPENDQ:
659 case PROTOCOL_BINARY_CMD_PREPENDQ:
660 return binary_read_one_response(ptr, buffer, buffer_length, result);
661
662 default:
663 break;
664 }
665 }
666
667 rc= MEMCACHED_SUCCESS;
668 if (header.response.status != 0)
669 {
670 switch (header.response.status)
671 {
672 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT:
673 rc= MEMCACHED_NOTFOUND;
674 break;
675
676 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS:
677 rc= MEMCACHED_DATA_EXISTS;
678 break;
679
680 case PROTOCOL_BINARY_RESPONSE_NOT_STORED:
681 rc= MEMCACHED_NOTSTORED;
682 break;
683
684 case PROTOCOL_BINARY_RESPONSE_E2BIG:
685 rc= MEMCACHED_E2BIG;
686 break;
687
688 case PROTOCOL_BINARY_RESPONSE_ENOMEM:
689 rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
690 break;
691
692 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE:
693 rc= MEMCACHED_AUTH_CONTINUE;
694 break;
695
696 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR:
697 rc= MEMCACHED_AUTH_FAILURE;
698 break;
699
700 case PROTOCOL_BINARY_RESPONSE_EINVAL:
701 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
702 default:
703 /* @todo fix the error mappings */
704 rc= MEMCACHED_PROTOCOL_ERROR;
705 break;
706 }
707 }
708
709 return rc;
710 }