faf20ff94149f15448c4c6a36a7d0d456419cb37
[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 instance,
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(instance->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 // Just used for cases of AES decrypt currently
59 memcached_return_t rc= MEMCACHED_SUCCESS;
60
61 /* We load the key */
62 {
63 char *key= result->item_key;
64 result->key_length= 0;
65
66 for (ptrdiff_t prefix_length= memcached_array_size(instance->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(*instance, 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(instance, value_ptr, to_read, read_length);
150 if (memcached_failed(rrc) and rrc == MEMCACHED_IN_PROGRESS)
151 {
152 memcached_quit_server(instance, true);
153 return memcached_set_error(*instance, 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 if (memcached_is_encrypted(instance->root) and memcached_result_length(result))
176 {
177 hashkit_string_st *destination;
178
179 if ((destination= hashkit_decrypt(&instance->root->hashkit,
180 memcached_result_value(result), memcached_result_length(result))) == NULL)
181 {
182 rc= memcached_set_error(*instance->root, MEMCACHED_FAILURE,
183 MEMCACHED_AT, memcached_literal_param("hashkit_decrypt() failed"));
184 }
185 else
186 {
187 memcached_result_reset_value(result);
188 if (memcached_failed(memcached_result_set_value(result, hashkit_string_c_str(destination), hashkit_string_length(destination))))
189 {
190 rc= memcached_set_error(*instance->root, MEMCACHED_FAILURE,
191 MEMCACHED_AT, memcached_literal_param("hashkit_decrypt() failed"));
192 }
193 }
194
195 if (memcached_failed(rc))
196 {
197 memcached_result_reset(result);
198 }
199 hashkit_string_free(destination);
200 }
201
202 return rc;
203
204 read_error:
205 memcached_io_reset(instance);
206
207 return MEMCACHED_PARTIAL_READ;
208 }
209
210 static memcached_return_t textual_read_one_response(memcached_server_write_instance_st instance,
211 char *buffer, const size_t buffer_length,
212 memcached_result_st *result)
213 {
214 size_t total_read;
215 memcached_return_t rc= memcached_io_readline(instance, buffer, buffer_length, total_read);
216
217 if (memcached_failed(rc))
218 {
219 return rc;
220 }
221 assert(total_read);
222
223 switch(buffer[0])
224 {
225 case 'V':
226 {
227 // VALUE
228 if (buffer[1] == 'A' and buffer[2] == 'L' and buffer[3] == 'U' and buffer[4] == 'E') /* VALUE */
229 {
230 /* We add back in one because we will need to search for END */
231 memcached_server_response_increment(instance);
232 return textual_value_fetch(instance, buffer, result);
233 }
234 // VERSION
235 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 */
236 {
237 /* Find the space, and then move one past it to copy version */
238 char *response_ptr= index(buffer, ' ');
239 response_ptr++;
240
241 long int version= strtol(response_ptr, (char **)NULL, 10);
242 if (version == LONG_MIN or version == LONG_MAX or errno == EINVAL or version > UINT8_MAX or version == 0)
243 {
244 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
245 return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse major version"));
246 }
247 instance->major_version= uint8_t(version);
248
249 response_ptr= index(response_ptr, '.');
250 response_ptr++;
251
252 version= strtol(response_ptr, (char **)NULL, 10);
253 if (version == LONG_MIN or version == LONG_MAX or errno == EINVAL or version > UINT8_MAX)
254 {
255 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
256 return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse minor version"));
257 }
258 instance->minor_version= uint8_t(version);
259
260 response_ptr= index(response_ptr, '.');
261 response_ptr++;
262
263 version= strtol(response_ptr, (char **)NULL, 10);
264 if (version == LONG_MIN or version == LONG_MAX or errno == EINVAL or version > UINT8_MAX)
265 {
266 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
267 return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse micro version"));
268 }
269 instance->micro_version= uint8_t(version);
270
271 return MEMCACHED_SUCCESS;
272 }
273 }
274 break;
275
276 case 'O':
277 {
278 // OK
279 if (buffer[1] == 'K')
280 {
281 return MEMCACHED_SUCCESS;
282 }
283 }
284 break;
285
286 case 'S':
287 {
288 // STAT
289 if (buffer[1] == 'T' and buffer[2] == 'A' and buffer[3] == 'T') /* STORED STATS */
290 {
291 memcached_server_response_increment(instance);
292 return MEMCACHED_STAT;
293 }
294 // SERVER_ERROR
295 else if (buffer[1] == 'E' and buffer[2] == 'R' and buffer[3] == 'V' and buffer[4] == 'E' and buffer[5] == 'R'
296 and buffer[6] == '_'
297 and buffer[7] == 'E' and buffer[8] == 'R' and buffer[9] == 'R' and buffer[10] == 'O' and buffer[11] == 'R' )
298 {
299 if (total_read == memcached_literal_param_size("SERVER_ERROR"))
300 {
301 return MEMCACHED_SERVER_ERROR;
302 }
303
304 if (total_read >= memcached_literal_param_size("SERVER_ERROR object too large for cache") and
305 (memcmp(buffer, memcached_literal_param("SERVER_ERROR object too large for cache")) == 0))
306 {
307 return MEMCACHED_E2BIG;
308 }
309
310 if (total_read >= memcached_literal_param_size("SERVER_ERROR out of memory storing object") and
311 (memcmp(buffer, memcached_literal_param("SERVER_ERROR out of memory storing object")) == 0))
312 {
313 return MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE;
314 }
315
316 // Move past the basic error message and whitespace
317 char *startptr= buffer + memcached_literal_param_size("SERVER_ERROR");
318 if (startptr[0] == ' ')
319 {
320 startptr++;
321 }
322
323 char *endptr= startptr;
324 while (*endptr != '\r' && *endptr != '\n') endptr++;
325
326 return memcached_set_error(*instance, MEMCACHED_SERVER_ERROR, MEMCACHED_AT, startptr, size_t(endptr - startptr));
327 }
328 // STORED
329 else if (buffer[1] == 'T' and buffer[2] == 'O' and buffer[3] == 'R') // and buffer[4] == 'E' and buffer[5] == 'D')
330 {
331 return MEMCACHED_STORED;
332 }
333 }
334 break;
335
336 case 'D':
337 {
338 // DELETED
339 if (buffer[1] == 'E' and buffer[2] == 'L' and buffer[3] == 'E' and buffer[4] == 'T' and buffer[5] == 'E' and buffer[6] == 'D')
340 {
341 return MEMCACHED_DELETED;
342 }
343 }
344 break;
345
346 case 'N':
347 {
348 // NOT_FOUND
349 if (buffer[1] == 'O' and buffer[2] == 'T'
350 and buffer[3] == '_'
351 and buffer[4] == 'F' and buffer[5] == 'O' and buffer[6] == 'U' and buffer[7] == 'N' and buffer[8] == 'D')
352 {
353 return MEMCACHED_NOTFOUND;
354 }
355 // NOT_STORED
356 else if (buffer[1] == 'O' and buffer[2] == 'T'
357 and buffer[3] == '_'
358 and buffer[4] == 'S' and buffer[5] == 'T' and buffer[6] == 'O' and buffer[7] == 'R' and buffer[8] == 'E' and buffer[9] == 'D')
359 {
360 return MEMCACHED_NOTSTORED;
361 }
362 }
363 break;
364
365 case 'E': /* PROTOCOL ERROR or END */
366 {
367 // END
368 if (buffer[1] == 'N' and buffer[2] == 'D')
369 {
370 return MEMCACHED_END;
371 }
372 #if 0
373 // PROTOCOL_ERROR
374 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'
375 and buffer[8] == '_'
376 and buffer[9] == 'E' and buffer[10] == 'R' and buffer[11] == 'R' and buffer[12] == 'O' and buffer[13] == 'R')
377 {
378 return MEMCACHED_PROTOCOL_ERROR;
379 }
380 #endif
381 // ERROR
382 else if (buffer[1] == 'R' and buffer[2] == 'R' and buffer[3] == 'O' and buffer[4] == 'R')
383 {
384 return MEMCACHED_ERROR;
385 }
386 // EXISTS
387 else if (buffer[1] == 'X' and buffer[2] == 'I' and buffer[3] == 'S' and buffer[4] == 'T' and buffer[5] == 'S')
388 {
389 return MEMCACHED_DATA_EXISTS;
390 }
391 }
392 break;
393
394 case 'T': /* TOUCHED */
395 {
396 // TOUCHED
397 if (buffer[1] == 'O' and buffer[2] == 'U' and buffer[3] == 'C' and buffer[4] == 'H' and buffer[5] == 'E' and buffer[6] == 'D')
398 {
399 return MEMCACHED_SUCCESS;
400 }
401 }
402 break;
403
404 case 'I': /* ITEM */
405 {
406 // ITEM
407 if (buffer[1] == 'T' and buffer[2] == 'E' and buffer[3] == 'M')
408 {
409 /* We add back in one because we will need to search for END */
410 memcached_server_response_increment(instance);
411 return MEMCACHED_ITEM;
412 }
413 }
414 break;
415
416 case 'C': /* CLIENT ERROR */
417 {
418 // CLIENT_ERROR
419 if (buffer[1] == 'L' and buffer[2] == 'I' and buffer[3] == 'E' and buffer[4] == 'N' and buffer[5] == 'T'
420 and buffer[6] == '_'
421 and buffer[7] == 'E' and buffer[8] == 'R' and buffer[9] == 'R' and buffer[10] == 'O' and buffer[11] == 'R')
422 {
423 return MEMCACHED_CLIENT_ERROR;
424 }
425 }
426 break;
427
428 case '0': /* INCR/DECR response */
429 case '1': /* INCR/DECR response */
430 case '2': /* INCR/DECR response */
431 case '3': /* INCR/DECR response */
432 case '4': /* INCR/DECR response */
433 case '5': /* INCR/DECR response */
434 case '6': /* INCR/DECR response */
435 case '7': /* INCR/DECR response */
436 case '8': /* INCR/DECR response */
437 case '9': /* INCR/DECR response */
438 {
439 unsigned long long int auto_return_value= strtoull(buffer, (char **)NULL, 10);
440
441 if (auto_return_value == ULLONG_MAX and errno == ERANGE)
442 {
443 result->numeric_value= UINT64_MAX;
444 return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT,
445 memcached_literal_param("Numeric response was out of range"));
446 }
447 else if (errno == EINVAL)
448 {
449 result->numeric_value= UINT64_MAX;
450 return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT,
451 memcached_literal_param("Numeric response was out of range"));
452 }
453
454 result->numeric_value= uint64_t(auto_return_value);
455
456 WATCHPOINT_STRING(buffer);
457 return MEMCACHED_SUCCESS;
458 }
459
460 default:
461 break;
462 }
463
464 buffer[total_read]= 0;
465 #if 0
466 if (total_read >= sizeof("STORSTORED") -1)
467 {
468 fprintf(stderr, "%s:%d '%s', %.*s\n", __FILE__, __LINE__,
469 buffer, MEMCACHED_MAX_BUFFER, instance->read_buffer);
470 assert(memcmp(buffer,"STORSTORED", sizeof("STORSTORED") -1));
471 }
472 #endif
473 return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT,
474 buffer, total_read);
475 }
476
477 static memcached_return_t binary_read_one_response(memcached_server_write_instance_st instance,
478 char *buffer, const size_t buffer_length,
479 memcached_result_st *result)
480 {
481 memcached_return_t rc;
482 protocol_binary_response_header header;
483
484 if ((rc= memcached_safe_read(instance, &header.bytes, sizeof(header.bytes))) != MEMCACHED_SUCCESS)
485 {
486 WATCHPOINT_ERROR(rc);
487 return rc;
488 }
489
490 if (header.response.magic != PROTOCOL_BINARY_RES)
491 {
492 return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
493 }
494
495 /*
496 ** Convert the header to host local endian!
497 */
498 header.response.keylen= ntohs(header.response.keylen);
499 header.response.status= ntohs(header.response.status);
500 header.response.bodylen= ntohl(header.response.bodylen);
501 header.response.cas= memcached_ntohll(header.response.cas);
502 uint32_t bodylen= header.response.bodylen;
503
504 if (header.response.status == PROTOCOL_BINARY_RESPONSE_SUCCESS or
505 header.response.status == PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE)
506 {
507 switch (header.response.opcode)
508 {
509 case PROTOCOL_BINARY_CMD_GETKQ:
510 /*
511 * We didn't increment the response counter for the GETKQ packet
512 * (only the final NOOP), so we need to increment the counter again.
513 */
514 memcached_server_response_increment(instance);
515 /* FALLTHROUGH */
516 case PROTOCOL_BINARY_CMD_GETK:
517 {
518 uint16_t keylen= header.response.keylen;
519 memcached_result_reset(result);
520 result->item_cas= header.response.cas;
521
522 if ((rc= memcached_safe_read(instance, &result->item_flags, sizeof (result->item_flags))) != MEMCACHED_SUCCESS)
523 {
524 WATCHPOINT_ERROR(rc);
525 return MEMCACHED_UNKNOWN_READ_FAILURE;
526 }
527
528 result->item_flags= ntohl(result->item_flags);
529 bodylen -= header.response.extlen;
530
531 result->key_length= keylen;
532 if (memcached_failed(rc= memcached_safe_read(instance, result->item_key, keylen)))
533 {
534 WATCHPOINT_ERROR(rc);
535 return MEMCACHED_UNKNOWN_READ_FAILURE;
536 }
537
538 // Only bother with doing this if key_length > 0
539 if (result->key_length)
540 {
541 if (memcached_array_size(instance->root->_namespace) and memcached_array_size(instance->root->_namespace) >= result->key_length)
542 {
543 return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
544 }
545
546 if (memcached_array_size(instance->root->_namespace))
547 {
548 result->key_length-= memcached_array_size(instance->root->_namespace);
549 memmove(result->item_key, result->item_key +memcached_array_size(instance->root->_namespace), result->key_length);
550 }
551 }
552
553 bodylen -= keylen;
554 if (memcached_failed(memcached_string_check(&result->value, bodylen)))
555 {
556 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
557 }
558
559 char *vptr= memcached_string_value_mutable(&result->value);
560 if (memcached_failed(rc= memcached_safe_read(instance, vptr, bodylen)))
561 {
562 WATCHPOINT_ERROR(rc);
563 return MEMCACHED_UNKNOWN_READ_FAILURE;
564 }
565
566 memcached_string_set_length(&result->value, bodylen);
567 }
568 break;
569
570 case PROTOCOL_BINARY_CMD_INCREMENT:
571 case PROTOCOL_BINARY_CMD_DECREMENT:
572 {
573 if (bodylen != sizeof(uint64_t))
574 {
575 result->numeric_value= UINT64_MAX;
576 return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
577 }
578
579 uint64_t val;
580 if ((rc= memcached_safe_read(instance, &val, sizeof(val))) != MEMCACHED_SUCCESS)
581 {
582 result->numeric_value= UINT64_MAX;
583 return MEMCACHED_UNKNOWN_READ_FAILURE;
584 }
585
586 result->numeric_value= memcached_ntohll(val);
587 }
588 break;
589
590 case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS:
591 case PROTOCOL_BINARY_CMD_VERSION:
592 {
593 char version_buffer[32]; // @todo document this number
594 memset(version_buffer, 0, sizeof(version_buffer));
595
596 if (memcached_safe_read(instance, version_buffer, bodylen) != MEMCACHED_SUCCESS)
597 {
598 return MEMCACHED_UNKNOWN_READ_FAILURE;
599 }
600
601 char *p;
602 long int version= strtol(version_buffer, &p, 10);
603 if (version == LONG_MIN or version == LONG_MAX or errno == EINVAL or version > UINT8_MAX or version == 0)
604 {
605 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
606 return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse major version"));
607 }
608 instance->major_version= uint8_t(version);
609
610 version= strtol(p +1, &p, 10);
611 if (version == LONG_MIN or version == LONG_MAX or errno == EINVAL or version > UINT8_MAX)
612 {
613 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
614 return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse micro version"));
615 }
616 instance->minor_version= uint8_t(version);
617
618 version= strtol(p + 1, NULL, 10);
619 if (errno == ERANGE)
620 {
621 instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
622 return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse micro version"));
623 }
624 instance->micro_version= uint8_t(version);
625 }
626 break;
627
628 case PROTOCOL_BINARY_CMD_FLUSH:
629 case PROTOCOL_BINARY_CMD_QUIT:
630 case PROTOCOL_BINARY_CMD_SET:
631 case PROTOCOL_BINARY_CMD_ADD:
632 case PROTOCOL_BINARY_CMD_REPLACE:
633 case PROTOCOL_BINARY_CMD_APPEND:
634 case PROTOCOL_BINARY_CMD_PREPEND:
635 case PROTOCOL_BINARY_CMD_DELETE:
636 case PROTOCOL_BINARY_CMD_TOUCH:
637 {
638 WATCHPOINT_ASSERT(bodylen == 0);
639 return MEMCACHED_SUCCESS;
640 }
641
642 case PROTOCOL_BINARY_CMD_NOOP:
643 {
644 WATCHPOINT_ASSERT(bodylen == 0);
645 return MEMCACHED_END;
646 }
647
648 case PROTOCOL_BINARY_CMD_STAT:
649 {
650 if (bodylen == 0)
651 {
652 return MEMCACHED_END;
653 }
654 else if (bodylen + 1 > buffer_length)
655 {
656 /* not enough space in buffer.. should not happen... */
657 return MEMCACHED_UNKNOWN_READ_FAILURE;
658 }
659 else
660 {
661 size_t keylen= header.response.keylen;
662 memset(buffer, 0, buffer_length);
663 if ((rc= memcached_safe_read(instance, buffer, keylen)) != MEMCACHED_SUCCESS ||
664 (rc= memcached_safe_read(instance, buffer + keylen + 1, bodylen - keylen)) != MEMCACHED_SUCCESS)
665 {
666 WATCHPOINT_ERROR(rc);
667 return MEMCACHED_UNKNOWN_READ_FAILURE;
668 }
669 }
670 }
671 break;
672
673 case PROTOCOL_BINARY_CMD_SASL_AUTH:
674 case PROTOCOL_BINARY_CMD_SASL_STEP:
675 {
676 memcached_result_reset(result);
677 result->item_cas= header.response.cas;
678
679 if (memcached_string_check(&result->value,
680 bodylen) != MEMCACHED_SUCCESS)
681 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
682
683 char *vptr= memcached_string_value_mutable(&result->value);
684 if ((rc= memcached_safe_read(instance, vptr, bodylen)) != MEMCACHED_SUCCESS)
685 {
686 WATCHPOINT_ERROR(rc);
687 return MEMCACHED_UNKNOWN_READ_FAILURE;
688 }
689
690 memcached_string_set_length(&result->value, bodylen);
691 }
692 break;
693 default:
694 {
695 /* Command not implemented yet! */
696 return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
697 }
698 }
699 }
700 else if (header.response.bodylen)
701 {
702 /* What should I do with the error message??? just discard it for now */
703 char hole[SMALL_STRING_LEN];
704 while (bodylen > 0)
705 {
706 size_t nr= (bodylen > SMALL_STRING_LEN) ? SMALL_STRING_LEN : bodylen;
707 if ((rc= memcached_safe_read(instance, hole, nr)) != MEMCACHED_SUCCESS)
708 {
709 WATCHPOINT_ERROR(rc);
710 return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
711 }
712 bodylen-= (uint32_t) nr;
713 }
714
715 /* This might be an error from one of the quiet commands.. if
716 * so, just throw it away and get the next one. What about creating
717 * a callback to the user with the error information?
718 */
719 switch (header.response.opcode)
720 {
721 case PROTOCOL_BINARY_CMD_SETQ:
722 case PROTOCOL_BINARY_CMD_ADDQ:
723 case PROTOCOL_BINARY_CMD_REPLACEQ:
724 case PROTOCOL_BINARY_CMD_APPENDQ:
725 case PROTOCOL_BINARY_CMD_PREPENDQ:
726 return binary_read_one_response(instance, buffer, buffer_length, result);
727
728 default:
729 break;
730 }
731 }
732
733 rc= MEMCACHED_SUCCESS;
734 if (header.response.status != 0)
735 {
736 switch (header.response.status)
737 {
738 case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT:
739 rc= MEMCACHED_NOTFOUND;
740 break;
741
742 case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS:
743 rc= MEMCACHED_DATA_EXISTS;
744 break;
745
746 case PROTOCOL_BINARY_RESPONSE_NOT_STORED:
747 rc= MEMCACHED_NOTSTORED;
748 break;
749
750 case PROTOCOL_BINARY_RESPONSE_E2BIG:
751 rc= MEMCACHED_E2BIG;
752 break;
753
754 case PROTOCOL_BINARY_RESPONSE_ENOMEM:
755 rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
756 break;
757
758 case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE:
759 rc= MEMCACHED_AUTH_CONTINUE;
760 break;
761
762 case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR:
763 rc= MEMCACHED_AUTH_FAILURE;
764 break;
765
766 case PROTOCOL_BINARY_RESPONSE_EINVAL:
767 case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
768 default:
769 return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
770 break;
771 }
772 }
773
774 return rc;
775 }
776
777 static memcached_return_t _read_one_response(memcached_server_write_instance_st instance,
778 char *buffer, const size_t buffer_length,
779 memcached_result_st *result)
780 {
781 memcached_server_response_decrement(instance);
782
783 if (result == NULL)
784 {
785 memcached_st *root= (memcached_st *)instance->root;
786 result = &root->result;
787 }
788
789 memcached_return_t rc;
790 if (memcached_is_binary(instance->root))
791 {
792 rc= binary_read_one_response(instance, buffer, buffer_length, result);
793 }
794 else
795 {
796 rc= textual_read_one_response(instance, buffer, buffer_length, result);
797 }
798
799 if (memcached_fatal(rc))
800 {
801 memcached_io_reset(instance);
802 }
803
804 return rc;
805 }
806
807 memcached_return_t memcached_read_one_response(memcached_server_write_instance_st instance,
808 memcached_result_st *result)
809 {
810 char buffer[SMALL_STRING_LEN];
811
812 if (memcached_is_udp(instance->root))
813 {
814 return memcached_set_error(*instance, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
815 }
816
817
818 return _read_one_response(instance, buffer, sizeof(buffer), result);
819 }
820
821 memcached_return_t memcached_response(memcached_server_write_instance_st instance,
822 memcached_result_st *result)
823 {
824 char buffer[1024];
825
826 return memcached_response(instance, buffer, sizeof(buffer), result);
827 }
828
829 memcached_return_t memcached_response(memcached_server_write_instance_st instance,
830 char *buffer, size_t buffer_length,
831 memcached_result_st *result)
832 {
833 if (memcached_is_udp(instance->root))
834 {
835 return memcached_set_error(*instance, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
836 }
837
838 /* We may have old commands in the buffer not set, first purge */
839 if ((instance->root->flags.no_block) and (memcached_is_processing_input(instance->root) == false))
840 {
841 (void)memcached_io_write(instance);
842 }
843
844 /*
845 * The previous implementation purged all pending requests and just
846 * returned the last one. Purge all pending messages to ensure backwards
847 * compatibility.
848 */
849 if (memcached_is_binary(instance->root) == false and memcached_server_response_count(instance) > 1)
850 {
851 memcached_result_st junked_result;
852 memcached_result_st *junked_result_ptr= memcached_result_create(instance->root, &junked_result);
853
854 assert(junked_result_ptr);
855
856 while (memcached_server_response_count(instance) > 1)
857 {
858 memcached_return_t rc= _read_one_response(instance, buffer, buffer_length, junked_result_ptr);
859
860 // @TODO should we return an error on another but a bad read case?
861 if (memcached_fatal(rc))
862 {
863 memcached_result_free(junked_result_ptr);
864 return rc;
865 }
866 }
867 memcached_result_free(junked_result_ptr);
868 }
869
870 return _read_one_response(instance, buffer, buffer_length, result);
871 }