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