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