Fix for case where key may not be checked.
[awesomized/libmemcached] / libmemcached / error.cc
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * LibMemcached
4 *
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
6 * 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
40 #include "libmemcached/assert.hpp"
41
42 #include <cerrno>
43 #include <cstdarg>
44 #include <cstdio>
45
46 #define MAX_ERROR_LENGTH 2048
47 struct memcached_error_t
48 {
49 Memcached *root;
50 uint64_t query_id;
51 struct memcached_error_t *next;
52 memcached_return_t rc;
53 int local_errno;
54 size_t size;
55 char message[MAX_ERROR_LENGTH];
56 };
57
58 static void _set(memcached_instance_st& server, Memcached& memc)
59 {
60 if (server.error_messages and server.error_messages->query_id != server.root->query_id)
61 {
62 memcached_error_free(server);
63 }
64
65 if (memc.error_messages)
66 {
67 if (memc.error_messages->rc == MEMCACHED_TIMEOUT)
68 {
69 server.io_wait_count.timeouts++;
70 }
71
72 memcached_error_t *error= libmemcached_xmalloc(&memc, memcached_error_t);
73 if (error)
74 {
75 memcpy(error, memc.error_messages, sizeof(memcached_error_t));
76 error->next= server.error_messages;
77 server.error_messages= error;
78 }
79 }
80 }
81
82 #if 0
83 static int error_log_fd= -1;
84 #endif
85
86 static void _set(Memcached& memc, memcached_string_t *str, memcached_return_t &rc, const char *at, int local_errno= 0)
87 {
88 if (memc.error_messages && memc.error_messages->query_id != memc.query_id)
89 {
90 memcached_error_free(memc);
91 }
92
93 if (memcached_fatal(rc))
94 {
95 // For memory allocation we use our error since it is a bit more specific
96 if (local_errno == ENOMEM and rc == MEMCACHED_ERRNO)
97 {
98 rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
99 }
100
101 if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
102 {
103 local_errno= ENOMEM;
104 }
105
106 if (rc == MEMCACHED_ERRNO and not local_errno)
107 {
108 local_errno= errno;
109 rc= MEMCACHED_ERRNO;
110 }
111
112 if (rc == MEMCACHED_ERRNO and local_errno == ENOTCONN)
113 {
114 rc= MEMCACHED_CONNECTION_FAILURE;
115 }
116
117 if (rc == MEMCACHED_ERRNO and local_errno == ECONNRESET)
118 {
119 rc= MEMCACHED_CONNECTION_FAILURE;
120 }
121
122 if (local_errno == EINVAL)
123 {
124 rc= MEMCACHED_INVALID_ARGUMENTS;
125 }
126
127 if (local_errno == ECONNREFUSED)
128 {
129 rc= MEMCACHED_CONNECTION_FAILURE;
130 }
131
132 if (rc == MEMCACHED_TIMEOUT)
133 {
134 }
135
136 memcached_error_t *error= libmemcached_xmalloc(&memc, memcached_error_t);
137 if (error == NULL) // Bad business if this happens
138 {
139 assert_msg(error, "libmemcached_xmalloc() failed to allocate a memcached_error_t");
140 return;
141 }
142
143 error->root= &memc;
144 error->query_id= memc.query_id;
145 error->rc= rc;
146 error->local_errno= local_errno;
147
148 const char *errmsg_ptr;
149 char errmsg[MAX_ERROR_LENGTH];
150 errmsg[0]= 0;
151 errmsg_ptr= errmsg;
152
153 if (local_errno)
154 {
155 #if defined(STRERROR_R_CHAR_P) && STRERROR_R_CHAR_P
156 errmsg_ptr= strerror_r(local_errno, errmsg, sizeof(errmsg));
157 #elif defined(HAVE_STRERROR_R) && HAVE_STRERROR_R
158 strerror_r(local_errno, errmsg, sizeof(errmsg));
159 errmsg_ptr= errmsg;
160 #elif defined(HAVE_STRERROR) && HAVE_STRERROR
161 snprintf(errmsg, sizeof(errmsg), "%s", strerror(local_errno));
162 errmsg_ptr= errmsg;
163 #endif
164 }
165
166
167 if (str and str->size and local_errno)
168 {
169 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s(%s), %.*s -> %s",
170 error->root,
171 memcached_strerror(&memc, rc),
172 errmsg_ptr,
173 memcached_string_printf(*str), at);
174 }
175 else if (local_errno)
176 {
177 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s(%s) -> %s",
178 error->root,
179 memcached_strerror(&memc, rc),
180 errmsg_ptr,
181 at);
182 }
183 else if (rc == MEMCACHED_PARSE_ERROR and str and str->size)
184 {
185 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %.*s -> %s",
186 error->root,
187 int(str->size), str->c_str, at);
188 }
189 else if (str and str->size)
190 {
191 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s, %.*s -> %s",
192 error->root,
193 memcached_strerror(&memc, rc),
194 int(str->size), str->c_str, at);
195 }
196 else
197 {
198 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s -> %s",
199 error->root,
200 memcached_strerror(&memc, rc), at);
201 }
202
203 error->next= memc.error_messages;
204 memc.error_messages= error;
205 }
206
207 #if 0
208 if (error_log_fd == -1)
209 {
210 // unlink("/tmp/libmemcachd.log");
211 if ((error_log_fd= open("/tmp/libmemcachd.log", O_CREAT | O_WRONLY | O_APPEND, 0644)) < 0)
212 {
213 perror("open");
214 error_log_fd= -1;
215 }
216 }
217 ::write(error_log_fd, error->message, error->size);
218 ::write(error_log_fd, "\n", 1);
219 #endif
220 }
221
222 memcached_return_t memcached_set_error(Memcached& memc, memcached_return_t rc, const char *at, const char *str, size_t length)
223 {
224 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
225 memcached_string_t tmp= { str, length };
226 return memcached_set_error(memc, rc, at, tmp);
227 }
228
229 memcached_return_t memcached_set_error(memcached_instance_st& self, memcached_return_t rc, const char *at, const char *str, size_t length)
230 {
231 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
232 assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a Instance");
233
234 memcached_string_t tmp= { str, length };
235 return memcached_set_error(self, rc, at, tmp);
236 }
237
238 #ifndef __INTEL_COMPILER
239 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
240 #endif
241
242 memcached_return_t memcached_set_error(Memcached& memc, memcached_return_t rc, const char *at, memcached_string_t& str)
243 {
244 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
245 if (memcached_fatal(rc))
246 {
247 _set(memc, &str, rc, at);
248 }
249
250 return rc;
251 }
252
253 memcached_return_t memcached_set_parser_error(Memcached& memc,
254 const char *at,
255 const char *format, ...)
256 {
257 va_list args;
258
259 char buffer[BUFSIZ];
260 va_start(args, format);
261 int length= vsnprintf(buffer, sizeof(buffer), format, args);
262 va_end(args);
263
264 return memcached_set_error(memc, MEMCACHED_PARSE_ERROR, at, buffer, length);
265 }
266
267 static inline size_t append_host_to_string(memcached_instance_st& self, char* buffer, const size_t buffer_length)
268 {
269 size_t size= 0;
270 switch (self.type)
271 {
272 case MEMCACHED_CONNECTION_TCP:
273 case MEMCACHED_CONNECTION_UDP:
274 size+= snprintf(buffer, buffer_length, " host: %s:%d",
275 self.hostname(), int(self.port()));
276 break;
277
278 case MEMCACHED_CONNECTION_UNIX_SOCKET:
279 size+= snprintf(buffer, buffer_length, " socket: %s",
280 self.hostname());
281 break;
282 }
283
284 return size;
285 }
286
287 memcached_return_t memcached_set_error(memcached_instance_st& self, memcached_return_t rc, const char *at, memcached_string_t& str)
288 {
289 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
290 assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a memcached_instance_st");
291 if (memcached_fatal(rc) == false and rc != MEMCACHED_CLIENT_ERROR)
292 {
293 return rc;
294 }
295
296 char hostname_port_message[MAX_ERROR_LENGTH];
297 char* hostname_port_message_ptr= hostname_port_message;
298 int size= 0;
299 if (str.size)
300 {
301 size= snprintf(hostname_port_message_ptr, sizeof(hostname_port_message), "%.*s, ",
302 memcached_string_printf(str));
303 hostname_port_message_ptr+= size;
304 }
305
306 size+= append_host_to_string(self, hostname_port_message_ptr, sizeof(hostname_port_message) -size);
307
308 memcached_string_t error_host= { hostname_port_message, size_t(size) };
309
310 assert_msg(self.root, "Programmer error, root was not set on instance");
311 if (self.root)
312 {
313 _set(*self.root, &error_host, rc, at);
314 _set(self, (*self.root));
315 assert(self.root->error_messages);
316 assert(self.error_messages);
317 assert(self.error_messages->rc == self.root->error_messages->rc);
318 }
319
320 return rc;
321 }
322
323 memcached_return_t memcached_set_error(memcached_instance_st& self, memcached_return_t rc, const char *at)
324 {
325 assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a memcached_instance_st");
326 if (memcached_fatal(rc) == false)
327 {
328 return rc;
329 }
330
331 char hostname_port[MEMCACHED_NI_MAXHOST +MEMCACHED_NI_MAXSERV + sizeof("host : ")];
332 size_t size= append_host_to_string(self, hostname_port, sizeof(hostname_port));
333
334 memcached_string_t error_host= { hostname_port, size};
335
336 if (self.root)
337 {
338 _set(*self.root, &error_host, rc, at);
339 _set(self, *self.root);
340 }
341
342 return rc;
343 }
344
345 memcached_return_t memcached_set_error(Memcached& self, memcached_return_t rc, const char *at)
346 {
347 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
348 if (memcached_fatal(rc) == false)
349 {
350 return rc;
351 }
352
353 _set(self, NULL, rc, at);
354
355 return rc;
356 }
357
358 memcached_return_t memcached_set_errno(Memcached& self, int local_errno, const char *at, const char *str, size_t length)
359 {
360 memcached_string_t tmp= { str, length };
361 return memcached_set_errno(self, local_errno, at, tmp);
362 }
363
364 memcached_return_t memcached_set_errno(memcached_instance_st& self, int local_errno, const char *at, const char *str, size_t length)
365 {
366 memcached_string_t tmp= { str, length };
367 return memcached_set_errno(self, local_errno, at, tmp);
368 }
369
370 memcached_return_t memcached_set_errno(Memcached& self, int local_errno, const char *at)
371 {
372 if (local_errno == 0)
373 {
374 return MEMCACHED_SUCCESS;
375 }
376
377 memcached_return_t rc= MEMCACHED_ERRNO;
378 _set(self, NULL, rc, at, local_errno);
379
380 return rc;
381 }
382
383 memcached_return_t memcached_set_errno(Memcached& memc, int local_errno, const char *at, memcached_string_t& str)
384 {
385 if (local_errno == 0)
386 {
387 return MEMCACHED_SUCCESS;
388 }
389
390 memcached_return_t rc= MEMCACHED_ERRNO;
391 _set(memc, &str, rc, at, local_errno);
392
393 return rc;
394 }
395
396 memcached_return_t memcached_set_errno(memcached_instance_st& self, int local_errno, const char *at, memcached_string_t& str)
397 {
398 if (local_errno == 0)
399 {
400 return MEMCACHED_SUCCESS;
401 }
402
403 char hostname_port_message[MAX_ERROR_LENGTH];
404 char* hostname_port_message_ptr= hostname_port_message;
405 size_t size= 0;
406 if (str.size)
407 {
408 size= snprintf(hostname_port_message_ptr, sizeof(hostname_port_message), "%.*s, ", memcached_string_printf(str));
409 }
410 size+= append_host_to_string(self, hostname_port_message_ptr, sizeof(hostname_port_message) -size);
411
412 memcached_string_t error_host= { hostname_port_message, size };
413
414 memcached_return_t rc= MEMCACHED_ERRNO;
415 if (self.root == NULL)
416 {
417 return rc;
418 }
419
420 _set(*self.root, &error_host, rc, at, local_errno);
421 _set(self, (*self.root));
422
423 #if 0
424 if (self.root->error_messages->rc != self.error_messages->rc)
425 {
426 fprintf(stderr, "%s:%d %s != %s\n", __FILE__, __LINE__,
427 memcached_strerror(NULL, self.root->error_messages->rc),
428 memcached_strerror(NULL, self.error_messages->rc));
429 }
430 #endif
431
432 return rc;
433 }
434
435 memcached_return_t memcached_set_errno(memcached_instance_st& self, int local_errno, const char *at)
436 {
437 if (local_errno == 0)
438 {
439 return MEMCACHED_SUCCESS;
440 }
441
442 char hostname_port_message[MAX_ERROR_LENGTH];
443 size_t size= append_host_to_string(self, hostname_port_message, sizeof(hostname_port_message));
444
445 memcached_string_t error_host= { hostname_port_message, size };
446
447 memcached_return_t rc= MEMCACHED_ERRNO;
448 if (self.root == NULL)
449 {
450 return rc;
451 }
452
453 _set(*self.root, &error_host, rc, at, local_errno);
454 _set(self, (*self.root));
455
456 return rc;
457 }
458
459 static void _error_print(const memcached_error_t *error)
460 {
461 if (error == NULL)
462 {
463 return;
464 }
465
466 if (error->size == 0)
467 {
468 fprintf(stderr, "\t%s\n", memcached_strerror(NULL, error->rc) );
469 }
470 else
471 {
472 fprintf(stderr, "\t%s %s\n", memcached_strerror(NULL, error->rc), error->message);
473 }
474
475 _error_print(error->next);
476 }
477
478 void memcached_error_print(const Memcached *shell)
479 {
480 const Memcached* self= memcached2Memcached(shell);
481 if (self == NULL)
482 {
483 return;
484 }
485
486 _error_print(self->error_messages);
487
488 for (uint32_t x= 0; x < memcached_server_count(self); x++)
489 {
490 memcached_instance_st* instance= memcached_instance_by_position(self, x);
491
492 _error_print(instance->error_messages);
493 }
494 }
495
496 static void _error_free(memcached_error_t *error)
497 {
498 if (error)
499 {
500 _error_free(error->next);
501
502 libmemcached_free(error->root, error);
503 }
504 }
505
506 void memcached_error_free(Memcached& self)
507 {
508 _error_free(self.error_messages);
509 self.error_messages= NULL;
510 }
511
512 void memcached_error_free(memcached_instance_st& self)
513 {
514 _error_free(self.error_messages);
515 self.error_messages= NULL;
516 }
517
518 void memcached_error_free(memcached_server_st& self)
519 {
520 _error_free(self.error_messages);
521 self.error_messages= NULL;
522 }
523
524 const char *memcached_error(const memcached_st *memc)
525 {
526 return memcached_last_error_message(memc);
527 }
528
529 const char *memcached_last_error_message(const memcached_st *shell)
530 {
531 const Memcached* memc= memcached2Memcached(shell);
532 if (memc)
533 {
534 if (memc->error_messages)
535 {
536 if (memc->error_messages->size and memc->error_messages->message[0])
537 {
538 return memc->error_messages->message;
539 }
540
541 return memcached_strerror(memc, memc->error_messages->rc);
542 }
543
544 return memcached_strerror(memc, MEMCACHED_SUCCESS);
545 }
546
547 return memcached_strerror(memc, MEMCACHED_INVALID_ARGUMENTS);
548 }
549
550 bool memcached_has_current_error(Memcached &memc)
551 {
552 if (memc.error_messages
553 and memc.error_messages->query_id == memc.query_id
554 and memcached_failed(memc.error_messages->rc))
555 {
556 return true;
557 }
558
559 return false;
560 }
561
562 bool memcached_has_current_error(memcached_instance_st& server)
563 {
564 return memcached_has_current_error(*(server.root));
565 }
566
567 memcached_return_t memcached_last_error(const memcached_st *shell)
568 {
569 const Memcached* memc= memcached2Memcached(shell);
570 if (memc)
571 {
572 if (memc->error_messages)
573 {
574 return memc->error_messages->rc;
575 }
576
577 return MEMCACHED_SUCCESS;
578 }
579
580 return MEMCACHED_INVALID_ARGUMENTS;
581 }
582
583 int memcached_last_error_errno(const memcached_st *shell)
584 {
585 const Memcached* memc= memcached2Memcached(shell);
586 if (memc == NULL)
587 {
588 return 0;
589 }
590
591 if (memc->error_messages == NULL)
592 {
593 return 0;
594 }
595
596 return memc->error_messages->local_errno;
597 }
598
599 const char *memcached_server_error(const memcached_instance_st * server)
600 {
601 if (server == NULL)
602 {
603 return NULL;
604 }
605
606 if (server->error_messages == NULL)
607 {
608 return memcached_strerror(server->root, MEMCACHED_SUCCESS);
609 }
610
611 if (server->error_messages->size == 0)
612 {
613 return memcached_strerror(server->root, server->error_messages->rc);
614 }
615
616 return server->error_messages->message;
617 }
618
619
620 memcached_error_t *memcached_error_copy(const memcached_instance_st& server)
621 {
622 if (server.error_messages == NULL)
623 {
624 return NULL;
625 }
626
627 memcached_error_t *error= libmemcached_xmalloc(server.root, memcached_error_t);
628 memcpy(error, server.error_messages, sizeof(memcached_error_t));
629 error->next= NULL;
630
631 return error;
632 }
633
634 memcached_return_t memcached_server_error_return(const memcached_instance_st * ptr)
635 {
636 if (ptr == NULL)
637 {
638 return MEMCACHED_INVALID_ARGUMENTS;
639 }
640
641 if (ptr and ptr->error_messages)
642 {
643 return ptr->error_messages->rc;
644 }
645
646 return MEMCACHED_SUCCESS;
647 }
648
649 memcached_return_t memcached_instance_error_return(memcached_instance_st* instance)
650 {
651 if (instance == NULL)
652 {
653 return MEMCACHED_INVALID_ARGUMENTS;
654 }
655
656 if (instance and instance->error_messages)
657 {
658 return instance->error_messages->rc;
659 }
660
661 return MEMCACHED_SUCCESS;
662 }