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