Have incr/decr use the number the parser for asci finds.
[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 uint64_t& numeric_value)
192 {
193 numeric_value= UINT64_MAX;
194 size_t total_read;
195 memcached_return_t rc= memcached_io_readline(ptr, buffer, buffer_length, total_read);
196
197 if (memcached_failed(rc))
198 {
199 return rc;
200 }
201
202 switch(buffer[0])
203 {
204 case 'V': /* VALUE || VERSION */
205 if (buffer[1] == 'A' and buffer[2] == 'L' and buffer[3] == 'U' and buffer[4] == 'E') /* VALUE */
206 {
207 /* We add back in one because we will need to search for END */
208 memcached_server_response_increment(ptr);
209 return textual_value_fetch(ptr, buffer, result);
210 }
211 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 */
212 {
213 return MEMCACHED_SUCCESS;
214 }
215 break;
216
217 case 'O': /* OK */
218 if (buffer[1] == 'K')
219 {
220 return MEMCACHED_SUCCESS;
221 }
222 break;
223
224 case 'S': /* STORED STATS SERVER_ERROR */
225 {
226 if (buffer[1] == 'T' and buffer[2] == 'A' and buffer[3] == 'T') /* STORED STATS */
227 {
228 memcached_server_response_increment(ptr);
229 return MEMCACHED_STAT;
230 }
231 else if (buffer[1] == 'E' and buffer[2] == 'R' and buffer[3] == 'V' and buffer[4] == 'E' and buffer[5] == 'R'
232 and buffer[6] == '_'
233 and buffer[7] == 'E' and buffer[8] == 'R' and buffer[9] == 'R' and buffer[10] == 'O' and buffer[11] == 'R' ) /* SERVER_ERROR */
234 {
235 if (total_read == memcached_literal_param_size("SERVER_ERROR"))
236 {
237 return MEMCACHED_SERVER_ERROR;
238 }
239
240 if (total_read > memcached_literal_param_size("SERVER_ERROR object too large for cache") and
241 (memcmp(buffer, memcached_literal_param("SERVER_ERROR object too large for cache")) == 0))
242 {
243 return MEMCACHED_E2BIG;
244 }
245
246 // Move past the basic error message and whitespace
247 char *startptr= buffer + memcached_literal_param_size("SERVER_ERROR");
248 if (startptr[0] == ' ')
249 {
250 startptr++;
251 }
252
253 char *endptr= startptr;
254 while (*endptr != '\r' && *endptr != '\n') endptr++;
255
256 return memcached_set_error(*ptr, MEMCACHED_SERVER_ERROR, MEMCACHED_AT, startptr, size_t(endptr - startptr));
257 }
258 else if (buffer[1] == 'T' and buffer[2] == 'O' and buffer[3] == 'R' and buffer[4] == 'E' and buffer[5] == 'D')
259 {
260 return MEMCACHED_STORED;
261 }
262 }
263 break;
264
265 case 'D': /* DELETED */
266 if (buffer[1] == 'E' and buffer[2] == 'L' and buffer[3] == 'E' and buffer[4] == 'T' and buffer[5] == 'E' and buffer[6] == 'D')
267 {
268 return MEMCACHED_DELETED;
269 }
270 break;
271
272 case 'N': /* NOT_FOUND */
273 {
274 if (buffer[1] == 'O' and buffer[2] == 'T'
275 and buffer[3] == '_'
276 and buffer[4] == 'F' and buffer[5] == 'O' and buffer[6] == 'U' and buffer[7] == 'N' and buffer[8] == 'D')
277 {
278 return MEMCACHED_NOTFOUND;
279 }
280 else if (buffer[1] == 'O' and buffer[2] == 'T'
281 and buffer[3] == '_'
282 and buffer[4] == 'S' and buffer[5] == 'T' and buffer[6] == 'O' and buffer[7] == 'R' and buffer[8] == 'E' and buffer[9] == 'D')
283 {
284 return MEMCACHED_NOTSTORED;
285 }
286 }
287 break;
288
289 case 'E': /* PROTOCOL ERROR or END */
290 {
291 if (buffer[1] == 'N' and buffer[2] == 'D')
292 {
293 return MEMCACHED_END;
294 }
295 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'
296 and buffer[8] == '_'
297 and buffer[9] == 'E' and buffer[10] == 'R' and buffer[11] == 'R' and buffer[12] == 'O' and buffer[13] == 'R')
298 {
299 return MEMCACHED_PROTOCOL_ERROR;
300 }
301 else if (buffer[1] == 'X' and buffer[2] == 'I' and buffer[3] == 'S' and buffer[4] == 'T' and buffer[5] == 'S')
302 {
303 return MEMCACHED_DATA_EXISTS;
304 }
305 }
306 break;
307
308 case 'T': /* TOUCHED */
309 {
310 if (buffer[1] == 'O' and buffer[2] == 'U' and buffer[3] == 'C' and buffer[4] == 'H' and buffer[5] == 'E' and buffer[6] == 'D')
311 {
312 return MEMCACHED_SUCCESS;
313 }
314 }
315 break;
316
317 case 'I': /* ITEM */
318 if (buffer[1] == 'T' and buffer[2] == 'E' and buffer[3] == 'M')
319 {
320 /* We add back in one because we will need to search for END */
321 memcached_server_response_increment(ptr);
322 return MEMCACHED_ITEM;
323 }
324 break;
325
326 case 'C': /* CLIENT ERROR */
327 if (buffer[1] == 'L' and buffer[2] == 'I' and buffer[3] == 'E' and buffer[4] == 'N' and buffer[5] == 'T')
328 {
329 return MEMCACHED_CLIENT_ERROR;
330 }
331 break;
332
333 case '0': /* INCR/DECR response */
334 case '1': /* INCR/DECR response */
335 case '2': /* INCR/DECR response */
336 case '3': /* INCR/DECR response */
337 case '4': /* INCR/DECR response */
338 case '5': /* INCR/DECR response */
339 case '6': /* INCR/DECR response */
340 case '7': /* INCR/DECR response */
341 case '8': /* INCR/DECR response */
342 case '9': /* INCR/DECR response */
343 {
344 unsigned long long int auto_return_value= strtoull(buffer, (char **)NULL, 10);
345
346 if (auto_return_value == ULLONG_MAX and errno == ERANGE)
347 {
348 return MEMCACHED_UNKNOWN_READ_FAILURE;
349 }
350 else if (errno == EINVAL)
351 {
352 return MEMCACHED_UNKNOWN_READ_FAILURE;
353 }
354
355 numeric_value= uint64_t(auto_return_value);
356
357 WATCHPOINT_STRING(buffer);
358 return MEMCACHED_SUCCESS;
359 }
360
361 default:
362 break;
363 }
364
365 return MEMCACHED_UNKNOWN_READ_FAILURE;
366 }
367
368 static memcached_return_t binary_read_one_response(memcached_server_write_instance_st ptr,
369 char *buffer, size_t buffer_length,
370 memcached_result_st *result)
371 {
372 memcached_return_t rc;
373 protocol_binary_response_header header;
374
375 if ((rc= memcached_safe_read(ptr, &header.bytes, sizeof(header.bytes))) != MEMCACHED_SUCCESS)
376 {
377 WATCHPOINT_ERROR(rc);
378 return rc;
379 }
380
381 if (header.response.magic != PROTOCOL_BINARY_RES)
382 {
383 return MEMCACHED_PROTOCOL_ERROR;
384 }
385
386 /*
387 ** Convert the header to host local endian!
388 */
389 header.response.keylen= ntohs(header.response.keylen);
390 header.response.status= ntohs(header.response.status);
391 header.response.bodylen= ntohl(header.response.bodylen);
392 header.response.cas= memcached_ntohll(header.response.cas);
393 uint32_t bodylen= header.response.bodylen;
394
395 if (header.response.status == PROTOCOL_BINARY_RESPONSE_SUCCESS or
396 header.response.status == PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE)
397 {
398 switch (header.response.opcode)
399 {
400 case PROTOCOL_BINARY_CMD_GETKQ:
401 /*
402 * We didn't increment the response counter for the GETKQ packet
403 * (only the final NOOP), so we need to increment the counter again.
404 */
405 memcached_server_response_increment(ptr);
406 /* FALLTHROUGH */
407 case PROTOCOL_BINARY_CMD_GETK:
408 {
409 uint16_t keylen= header.response.keylen;
410 memcached_result_reset(result);
411 result->item_cas= header.response.cas;
412
413 if ((rc= memcached_safe_read(ptr, &result->item_flags, sizeof (result->item_flags))) != MEMCACHED_SUCCESS)
414 {
415 WATCHPOINT_ERROR(rc);
416 return MEMCACHED_UNKNOWN_READ_FAILURE;
417 }
418
419 result->item_flags= ntohl(result->item_flags);
420 bodylen -= header.response.extlen;
421
422 result->key_length= keylen;
423 if (memcached_failed(rc= memcached_safe_read(ptr, result->item_key, keylen)))
424 {
425 WATCHPOINT_ERROR(rc);
426 return MEMCACHED_UNKNOWN_READ_FAILURE;
427 }
428
429 // Only bother with doing this if key_length > 0
430 if (result->key_length)
431 {
432 if (memcached_array_size(ptr->root->_namespace) and memcached_array_size(ptr->root->_namespace) >= result->key_length)
433 {
434 return memcached_set_error(*ptr, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
435 }
436
437 if (memcached_array_size(ptr->root->_namespace))
438 {
439 result->key_length-= memcached_array_size(ptr->root->_namespace);
440 memmove(result->item_key, result->item_key +memcached_array_size(ptr->root->_namespace), result->key_length);
441 }
442 }
443
444 bodylen -= keylen;
445 if (memcached_failed(memcached_string_check(&result->value, bodylen)))
446 {
447 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
448 }
449
450 char *vptr= memcached_string_value_mutable(&result->value);
451 if (memcached_failed(rc= memcached_safe_read(ptr, vptr, bodylen)))
452 {
453 WATCHPOINT_ERROR(rc);
454 return MEMCACHED_UNKNOWN_READ_FAILURE;
455 }
456
457 memcached_string_set_length(&result->value, bodylen);
458 }
459 break;
460
461 case PROTOCOL_BINARY_CMD_INCREMENT:
462 case PROTOCOL_BINARY_CMD_DECREMENT:
463 {
464 if (bodylen != sizeof(uint64_t) or buffer_length != sizeof(uint64_t))
465 {
466 return MEMCACHED_PROTOCOL_ERROR;
467 }
468
469 WATCHPOINT_ASSERT(bodylen == buffer_length);
470 uint64_t val;
471 if ((rc= memcached_safe_read(ptr, &val, sizeof(val))) != MEMCACHED_SUCCESS)
472 {
473 WATCHPOINT_ERROR(rc);
474 return MEMCACHED_UNKNOWN_READ_FAILURE;
475 }
476
477 val= memcached_ntohll(val);
478 memcpy(buffer, &val, sizeof(val));
479 }
480 break;
481
482 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS:
483 case PROTOCOL_BINARY_CMD_VERSION:
484 {
485 memset(buffer, 0, buffer_length);
486 if (bodylen >= buffer_length)
487 {
488 /* not enough space in buffer.. should not happen... */
489 return MEMCACHED_UNKNOWN_READ_FAILURE;
490 }
491 else if ((rc= memcached_safe_read(ptr, buffer, bodylen)) != MEMCACHED_SUCCESS)
492 {
493 WATCHPOINT_ERROR(rc);
494 return MEMCACHED_UNKNOWN_READ_FAILURE;
495 }
496 }
497 break;
498 case PROTOCOL_BINARY_CMD_FLUSH:
499 case PROTOCOL_BINARY_CMD_QUIT:
500 case PROTOCOL_BINARY_CMD_SET:
501 case PROTOCOL_BINARY_CMD_ADD:
502 case PROTOCOL_BINARY_CMD_REPLACE:
503 case PROTOCOL_BINARY_CMD_APPEND:
504 case PROTOCOL_BINARY_CMD_PREPEND:
505 case PROTOCOL_BINARY_CMD_DELETE:
506 case PROTOCOL_BINARY_CMD_TOUCH:
507 {
508 WATCHPOINT_ASSERT(bodylen == 0);
509 return MEMCACHED_SUCCESS;
510 }
511
512 case PROTOCOL_BINARY_CMD_NOOP:
513 {
514 WATCHPOINT_ASSERT(bodylen == 0);
515 return MEMCACHED_END;
516 }
517
518 case PROTOCOL_BINARY_CMD_STAT:
519 {
520 if (bodylen == 0)
521 {
522 return MEMCACHED_END;
523 }
524 else if (bodylen + 1 > buffer_length)
525 {
526 /* not enough space in buffer.. should not happen... */
527 return MEMCACHED_UNKNOWN_READ_FAILURE;
528 }
529 else
530 {
531 size_t keylen= header.response.keylen;
532 memset(buffer, 0, buffer_length);
533 if ((rc= memcached_safe_read(ptr, buffer, keylen)) != MEMCACHED_SUCCESS ||
534 (rc= memcached_safe_read(ptr, buffer + keylen + 1, bodylen - keylen)) != MEMCACHED_SUCCESS)
535 {
536 WATCHPOINT_ERROR(rc);
537 return MEMCACHED_UNKNOWN_READ_FAILURE;
538 }
539 }
540 }
541 break;
542
543 case PROTOCOL_BINARY_CMD_SASL_AUTH:
544 case PROTOCOL_BINARY_CMD_SASL_STEP:
545 {
546 memcached_result_reset(result);
547 result->item_cas= header.response.cas;
548
549 if (memcached_string_check(&result->value,
550 bodylen) != MEMCACHED_SUCCESS)
551 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
552
553 char *vptr= memcached_string_value_mutable(&result->value);
554 if ((rc= memcached_safe_read(ptr, vptr, bodylen)) != MEMCACHED_SUCCESS)
555 {
556 WATCHPOINT_ERROR(rc);
557 return MEMCACHED_UNKNOWN_READ_FAILURE;
558 }
559
560 memcached_string_set_length(&result->value, bodylen);
561 }
562 break;
563 default:
564 {
565 /* Command not implemented yet! */
566 WATCHPOINT_ASSERT(0);
567 return MEMCACHED_PROTOCOL_ERROR;
568 }
569 }
570 }
571 else if (header.response.bodylen)
572 {
573 /* What should I do with the error message??? just discard it for now */
574 char hole[SMALL_STRING_LEN];
575 while (bodylen > 0)
576 {
577 size_t nr= (bodylen > SMALL_STRING_LEN) ? SMALL_STRING_LEN : bodylen;
578 if ((rc= memcached_safe_read(ptr, hole, nr)) != MEMCACHED_SUCCESS)
579 {
580 WATCHPOINT_ERROR(rc);
581 return memcached_set_error(*ptr, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
582 }
583 bodylen-= (uint32_t) nr;
584 }
585
586 /* This might be an error from one of the quiet commands.. if
587 * so, just throw it away and get the next one. What about creating
588 * a callback to the user with the error information?
589 */
590 switch (header.response.opcode)
591 {
592 case PROTOCOL_BINARY_CMD_SETQ:
593 case PROTOCOL_BINARY_CMD_ADDQ:
594 case PROTOCOL_BINARY_CMD_REPLACEQ:
595 case PROTOCOL_BINARY_CMD_APPENDQ:
596 case PROTOCOL_BINARY_CMD_PREPENDQ:
597 return binary_read_one_response(ptr, buffer, buffer_length, result);
598
599 default:
600 break;
601 }
602 }
603
604 rc= MEMCACHED_SUCCESS;
605 if (header.response.status != 0)
606 {
607 switch (header.response.status)
608 {
609 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT:
610 rc= MEMCACHED_NOTFOUND;
611 break;
612
613 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS:
614 rc= MEMCACHED_DATA_EXISTS;
615 break;
616
617 case PROTOCOL_BINARY_RESPONSE_NOT_STORED:
618 rc= MEMCACHED_NOTSTORED;
619 break;
620
621 case PROTOCOL_BINARY_RESPONSE_E2BIG:
622 rc= MEMCACHED_E2BIG;
623 break;
624
625 case PROTOCOL_BINARY_RESPONSE_ENOMEM:
626 rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
627 break;
628
629 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE:
630 rc= MEMCACHED_AUTH_CONTINUE;
631 break;
632
633 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR:
634 rc= MEMCACHED_AUTH_FAILURE;
635 break;
636
637 case PROTOCOL_BINARY_RESPONSE_EINVAL:
638 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
639 default:
640 /* @todo fix the error mappings */
641 rc= MEMCACHED_PROTOCOL_ERROR;
642 break;
643 }
644 }
645
646 return rc;
647 }
648
649 memcached_return_t memcached_read_one_response(memcached_server_write_instance_st ptr,
650 char *buffer, size_t buffer_length,
651 memcached_result_st *result)
652 {
653 uint64_t numeric_value;
654
655 return memcached_read_one_response(ptr, buffer, buffer_length, result, numeric_value);
656 }
657
658 memcached_return_t memcached_read_one_response(memcached_server_write_instance_st ptr,
659 char *buffer, size_t buffer_length,
660 memcached_result_st *result,
661 uint64_t& numeric_value)
662 {
663 memcached_server_response_decrement(ptr);
664
665 if (result == NULL)
666 {
667 memcached_st *root= (memcached_st *)ptr->root;
668 result = &root->result;
669 }
670
671 memcached_return_t rc;
672 if (ptr->root->flags.binary_protocol)
673 {
674 rc= binary_read_one_response(ptr, buffer, buffer_length, result);
675 }
676 else
677 {
678 rc= textual_read_one_response(ptr, buffer, buffer_length, result, numeric_value);
679 }
680
681 if (rc == MEMCACHED_UNKNOWN_READ_FAILURE or
682 rc == MEMCACHED_READ_FAILURE or
683 rc == MEMCACHED_PROTOCOL_ERROR or
684 rc == MEMCACHED_CLIENT_ERROR or
685 rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
686 {
687 memcached_io_reset(ptr);
688 }
689
690 return rc;
691 }
692
693 memcached_return_t memcached_response(memcached_server_write_instance_st ptr,
694 char *buffer, size_t buffer_length,
695 memcached_result_st *result)
696 {
697 uint64_t numeric_value;
698
699 return memcached_response(ptr, buffer, buffer_length, result, numeric_value);
700 }
701
702 memcached_return_t memcached_response(memcached_server_write_instance_st ptr,
703 char *buffer, size_t buffer_length,
704 memcached_result_st *result,
705 uint64_t& numeric_value)
706 {
707 /* We may have old commands in the buffer not set, first purge */
708 if ((ptr->root->flags.no_block) && (memcached_is_processing_input(ptr->root) == false))
709 {
710 (void)memcached_io_write(ptr, NULL, 0, true);
711 }
712
713 /*
714 * The previous implementation purged all pending requests and just
715 * returned the last one. Purge all pending messages to ensure backwards
716 * compatibility.
717 */
718 if (ptr->root->flags.binary_protocol == false)
719 {
720 while (memcached_server_response_count(ptr) > 1)
721 {
722 memcached_return_t rc= memcached_read_one_response(ptr, buffer, buffer_length, result, numeric_value);
723
724 if (rc != MEMCACHED_END &&
725 rc != MEMCACHED_STORED &&
726 rc != MEMCACHED_SUCCESS &&
727 rc != MEMCACHED_STAT &&
728 rc != MEMCACHED_DELETED &&
729 rc != MEMCACHED_NOTFOUND &&
730 rc != MEMCACHED_NOTSTORED &&
731 rc != MEMCACHED_DATA_EXISTS)
732 {
733 return rc;
734 }
735 }
736 }
737
738 return memcached_read_one_response(ptr, buffer, buffer_length, result, numeric_value);
739 }