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