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