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