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