msvc support
[m6w6/libmemcached] / src / libmemcached / error.cc
1 /*
2 +--------------------------------------------------------------------+
3 | libmemcached - C/C++ Client Library for memcached |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted under the terms of the BSD license. |
7 | You should have received a copy of the license in a bundled file |
8 | named LICENSE; in case you did not receive a copy you can review |
9 | the terms online at: https://opensource.org/licenses/BSD-3-Clause |
10 +--------------------------------------------------------------------+
11 | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ |
12 | Copyright (c) 2020 Michael Wallner <mike@php.net> |
13 +--------------------------------------------------------------------+
14 */
15
16 #include "libmemcached/common.h"
17
18 #include "libmemcached/assert.hpp"
19
20 #include <cerrno>
21 #include <cstdarg>
22 #include <cstdio>
23
24 #define MAX_ERROR_LENGTH 2048
25 struct memcached_error_t {
26 Memcached *root;
27 uint64_t query_id;
28 struct memcached_error_t *next;
29 memcached_return_t rc;
30 int local_errno;
31 size_t size;
32 char message[MAX_ERROR_LENGTH];
33 };
34
35 static void _set(memcached_instance_st &server, Memcached &memc) {
36 if (server.error_messages and server.error_messages->query_id != server.root->query_id) {
37 memcached_error_free(server);
38 }
39
40 if (memc.error_messages) {
41 if (memc.error_messages->rc == MEMCACHED_TIMEOUT) {
42 server.io_wait_count.timeouts++;
43 }
44
45 memcached_error_t *error = libmemcached_xmalloc(&memc, memcached_error_t);
46 if (error) {
47 memcpy(error, memc.error_messages, sizeof(memcached_error_t));
48 error->next = server.error_messages;
49 server.error_messages = error;
50 }
51 }
52 }
53
54 #if 0
55 static int error_log_fd= -1;
56 #endif
57
58 static void _set(Memcached &memc, memcached_string_t *str, memcached_return_t &rc, const char *at,
59 int local_errno = 0) {
60 if (memc.error_messages && memc.error_messages->query_id != memc.query_id) {
61 memcached_error_free(memc);
62 }
63
64 if (memcached_fatal(rc) or rc == MEMCACHED_CLIENT_ERROR) {
65 // For memory allocation we use our error since it is a bit more specific
66 if (local_errno == ENOMEM and rc == MEMCACHED_ERRNO) {
67 rc = MEMCACHED_MEMORY_ALLOCATION_FAILURE;
68 }
69
70 if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE) {
71 local_errno = ENOMEM;
72 }
73
74 if (rc == MEMCACHED_ERRNO and not local_errno) {
75 local_errno = errno;
76 rc = MEMCACHED_ERRNO;
77 }
78
79 if (rc == MEMCACHED_ERRNO and local_errno == ENOTCONN) {
80 rc = MEMCACHED_CONNECTION_FAILURE;
81 }
82
83 if (rc == MEMCACHED_ERRNO and local_errno == ECONNRESET) {
84 rc = MEMCACHED_CONNECTION_FAILURE;
85 }
86
87 if (local_errno == EINVAL) {
88 rc = MEMCACHED_INVALID_ARGUMENTS;
89 }
90
91 if (local_errno == ECONNREFUSED) {
92 rc = MEMCACHED_CONNECTION_FAILURE;
93 }
94
95 if (rc == MEMCACHED_TIMEOUT) {
96 }
97
98 memcached_error_t *error = libmemcached_xmalloc(&memc, memcached_error_t);
99 if (error == NULL) // Bad business if this happens
100 {
101 assert_msg(error, "libmemcached_xmalloc() failed to allocate a memcached_error_t");
102 return;
103 }
104
105 error->root = &memc;
106 error->query_id = memc.query_id;
107 error->rc = rc;
108 error->local_errno = local_errno;
109
110 // MEMCACHED_CLIENT_ERROR is a special case because it is an error coming from the server
111 if (rc == MEMCACHED_CLIENT_ERROR) {
112 assert(str);
113 assert(str->size);
114 if (str and str->size) {
115 assert(error->local_errno == 0);
116 error->local_errno = 0;
117
118 error->size = (int) snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %.*s", error->root,
119 int(str->size), str->c_str);
120 }
121 } else if (local_errno) {
122 const char *errmsg_ptr;
123 char errmsg[MAX_ERROR_LENGTH];
124 errmsg[0] = 0;
125 errmsg_ptr = errmsg;
126
127 #if defined(HAVE_STRERROR_R_CHAR_P) && HAVE_STRERROR_R_CHAR_P
128 errmsg_ptr = strerror_r(local_errno, errmsg, sizeof(errmsg));
129 #elif defined(HAVE_STRERROR_R) && HAVE_STRERROR_R
130 strerror_r(local_errno, errmsg, sizeof(errmsg));
131 errmsg_ptr = errmsg;
132 #else
133 snprintf(errmsg, sizeof(errmsg), "%s", strerror(local_errno));
134 errmsg_ptr = errmsg;
135 #endif
136
137 if (str and str->size and local_errno) {
138 error->size = (int) snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s(%s), %.*s -> %s",
139 error->root, memcached_strerror(&memc, rc), errmsg_ptr,
140 memcached_string_printf(*str), at);
141 } else {
142 error->size = (int) snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s(%s) -> %s",
143 error->root, memcached_strerror(&memc, rc), errmsg_ptr, at);
144 }
145 } else if (rc == MEMCACHED_PARSE_ERROR and str and str->size) {
146 error->size = (int) snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %.*s -> %s", error->root,
147 int(str->size), str->c_str, at);
148 } else if (str and str->size) {
149 error->size =
150 (int) snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s, %.*s -> %s", error->root,
151 memcached_strerror(&memc, rc), int(str->size), str->c_str, at);
152 } else {
153 error->size = (int) snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s -> %s", error->root,
154 memcached_strerror(&memc, rc), at);
155 }
156
157 error->next = memc.error_messages;
158 memc.error_messages = error;
159 #if 0
160 if (error_log_fd == -1)
161 {
162 // unlink("/tmp/libmemcachd.log");
163 if ((error_log_fd= open("/tmp/libmemcachd.log", O_CREAT | O_WRONLY | O_APPEND, 0644)) < 0)
164 {
165 perror("open");
166 error_log_fd= -1;
167 }
168 }
169 ::write(error_log_fd, error->message, error->size);
170 ::write(error_log_fd, "\n", 1);
171 #endif
172 }
173 }
174
175 memcached_return_t memcached_set_error(Memcached &memc, memcached_return_t rc, const char *at,
176 const char *str, size_t length) {
177 assert_msg(rc != MEMCACHED_ERRNO,
178 "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
179 memcached_string_t tmp = {str, length};
180 return memcached_set_error(memc, rc, at, tmp);
181 }
182
183 memcached_return_t memcached_set_error(memcached_instance_st &self, memcached_return_t rc,
184 const char *at, const char *str, size_t length) {
185 assert_msg(rc != MEMCACHED_ERRNO,
186 "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
187 assert_msg(rc != MEMCACHED_SOME_ERRORS,
188 "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a Instance");
189
190 memcached_string_t tmp = {str, length};
191 return memcached_set_error(self, rc, at, tmp);
192 }
193
194 memcached_return_t memcached_set_error(Memcached &memc, memcached_return_t rc, const char *at,
195 memcached_string_t &str) {
196 assert_msg(rc != MEMCACHED_ERRNO,
197 "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
198 if (memcached_fatal(rc)) {
199 _set(memc, &str, rc, at);
200 }
201
202 return rc;
203 }
204
205 memcached_return_t memcached_set_parser_error(Memcached &memc, const char *at, const char *format,
206 ...) {
207 va_list args;
208
209 char buffer[BUFSIZ];
210 va_start(args, format);
211 int length = vsnprintf(buffer, sizeof(buffer), format, args);
212 va_end(args);
213
214 return memcached_set_error(memc, MEMCACHED_PARSE_ERROR, at, buffer, length);
215 }
216
217 static inline size_t append_host_to_string(memcached_instance_st &self, char *buffer,
218 const size_t buffer_length) {
219 size_t size = 0;
220 switch (self.type) {
221 case MEMCACHED_CONNECTION_TCP:
222 case MEMCACHED_CONNECTION_UDP:
223 size += snprintf(buffer, buffer_length, " host: %s:%d", self.hostname(), int(self.port()));
224 break;
225
226 case MEMCACHED_CONNECTION_UNIX_SOCKET:
227 size += snprintf(buffer, buffer_length, " socket: %s", self.hostname());
228 break;
229 }
230
231 return size;
232 }
233
234 memcached_return_t memcached_set_error(memcached_instance_st &self, memcached_return_t rc,
235 const char *at, memcached_string_t &str) {
236 assert_msg(rc != MEMCACHED_ERRNO,
237 "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
238 assert_msg(
239 rc != MEMCACHED_SOME_ERRORS,
240 "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a memcached_instance_st");
241 if (memcached_fatal(rc) == false and rc != MEMCACHED_CLIENT_ERROR) {
242 return rc;
243 }
244
245 char hostname_port_message[MAX_ERROR_LENGTH];
246 char *hostname_port_message_ptr = hostname_port_message;
247 int size = 0;
248 if (str.size) {
249 size = snprintf(hostname_port_message_ptr, sizeof(hostname_port_message), "%.*s, ",
250 memcached_string_printf(str));
251 hostname_port_message_ptr += size;
252 }
253
254 size +=
255 append_host_to_string(self, hostname_port_message_ptr, sizeof(hostname_port_message) - size);
256
257 memcached_string_t error_host = {hostname_port_message, size_t(size)};
258
259 assert_msg(self.root, "Programmer error, root was not set on instance");
260 if (self.root) {
261 _set(*self.root, &error_host, rc, at);
262 _set(self, (*self.root));
263 assert(self.error_messages);
264 assert(self.root->error_messages);
265 assert(self.error_messages->rc == self.root->error_messages->rc);
266 }
267
268 return rc;
269 }
270
271 memcached_return_t memcached_set_error(memcached_instance_st &self, memcached_return_t rc,
272 const char *at) {
273 assert_msg(
274 rc != MEMCACHED_SOME_ERRORS,
275 "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a memcached_instance_st");
276 if (memcached_fatal(rc) == false) {
277 return rc;
278 }
279
280 char hostname_port[MEMCACHED_NI_MAXHOST + MEMCACHED_NI_MAXSERV + sizeof("host : ")];
281 size_t size = append_host_to_string(self, hostname_port, sizeof(hostname_port));
282
283 memcached_string_t error_host = {hostname_port, size};
284
285 if (self.root) {
286 _set(*self.root, &error_host, rc, at);
287 _set(self, *self.root);
288 }
289
290 return rc;
291 }
292
293 memcached_return_t memcached_set_error(Memcached &self, memcached_return_t rc, const char *at) {
294 assert_msg(rc != MEMCACHED_ERRNO,
295 "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
296 if (memcached_fatal(rc) == false) {
297 return rc;
298 }
299
300 _set(self, NULL, rc, at);
301
302 return rc;
303 }
304
305 memcached_return_t memcached_set_errno(Memcached &self, int local_errno, const char *at,
306 const char *str, size_t length) {
307 memcached_string_t tmp = {str, length};
308 return memcached_set_errno(self, local_errno, at, tmp);
309 }
310
311 memcached_return_t memcached_set_errno(memcached_instance_st &self, int local_errno, const char *at,
312 const char *str, size_t length) {
313 memcached_string_t tmp = {str, length};
314 return memcached_set_errno(self, local_errno, at, tmp);
315 }
316
317 memcached_return_t memcached_set_errno(Memcached &self, int local_errno, const char *at) {
318 if (local_errno == 0) {
319 return MEMCACHED_SUCCESS;
320 }
321
322 memcached_return_t rc = MEMCACHED_ERRNO;
323 _set(self, NULL, rc, at, local_errno);
324
325 return rc;
326 }
327
328 memcached_return_t memcached_set_errno(Memcached &memc, int local_errno, const char *at,
329 memcached_string_t &str) {
330 if (local_errno == 0) {
331 return MEMCACHED_SUCCESS;
332 }
333
334 memcached_return_t rc = MEMCACHED_ERRNO;
335 _set(memc, &str, rc, at, local_errno);
336
337 return rc;
338 }
339
340 memcached_return_t memcached_set_errno(memcached_instance_st &self, int local_errno, const char *at,
341 memcached_string_t &str) {
342 if (local_errno == 0) {
343 return MEMCACHED_SUCCESS;
344 }
345
346 char hostname_port_message[MAX_ERROR_LENGTH];
347 char *hostname_port_message_ptr = hostname_port_message;
348 size_t size = 0;
349 if (str.size) {
350 size = snprintf(hostname_port_message_ptr, sizeof(hostname_port_message), "%.*s, ",
351 memcached_string_printf(str));
352 }
353 size +=
354 append_host_to_string(self, hostname_port_message_ptr, sizeof(hostname_port_message) - size);
355
356 memcached_string_t error_host = {hostname_port_message, size};
357
358 memcached_return_t rc = MEMCACHED_ERRNO;
359 if (self.root == NULL) {
360 return rc;
361 }
362
363 _set(*self.root, &error_host, rc, at, local_errno);
364 _set(self, (*self.root));
365
366 #if 0
367 if (self.root->error_messages->rc != self.error_messages->rc)
368 {
369 fprintf(stderr, "%s:%d %s != %s\n", __FILE__, __LINE__,
370 memcached_strerror(NULL, self.root->error_messages->rc),
371 memcached_strerror(NULL, self.error_messages->rc));
372 }
373 #endif
374
375 return rc;
376 }
377
378 memcached_return_t memcached_set_errno(memcached_instance_st &self, int local_errno,
379 const char *at) {
380 if (local_errno == 0) {
381 return MEMCACHED_SUCCESS;
382 }
383
384 char hostname_port_message[MAX_ERROR_LENGTH];
385 size_t size = append_host_to_string(self, hostname_port_message, sizeof(hostname_port_message));
386
387 memcached_string_t error_host = {hostname_port_message, size};
388
389 memcached_return_t rc = MEMCACHED_ERRNO;
390 if (self.root == NULL) {
391 return rc;
392 }
393
394 _set(*self.root, &error_host, rc, at, local_errno);
395 _set(self, (*self.root));
396
397 return rc;
398 }
399
400 static void _error_print(const memcached_error_t *error) {
401 if (error == NULL) {
402 return;
403 }
404
405 if (error->size == 0) {
406 fprintf(stderr, "\t%s\n", memcached_strerror(NULL, error->rc));
407 } else {
408 fprintf(stderr, "\t%s %s\n", memcached_strerror(NULL, error->rc), error->message);
409 }
410
411 _error_print(error->next);
412 }
413
414 void memcached_error_print(const Memcached *shell) {
415 const Memcached *self = memcached2Memcached(shell);
416 if (self == NULL) {
417 return;
418 }
419
420 _error_print(self->error_messages);
421
422 for (uint32_t x = 0; x < memcached_server_count(self); x++) {
423 memcached_instance_st *instance = memcached_instance_by_position(self, x);
424
425 _error_print(instance->error_messages);
426 }
427 }
428
429 static void _error_free(memcached_error_t *error) {
430 if (error) {
431 _error_free(error->next);
432
433 libmemcached_free(error->root, error);
434 }
435 }
436
437 void memcached_error_free(Memcached &self) {
438 _error_free(self.error_messages);
439 self.error_messages = NULL;
440 }
441
442 void memcached_error_free(memcached_instance_st &self) {
443 _error_free(self.error_messages);
444 self.error_messages = NULL;
445 }
446
447 void memcached_error_free(memcached_server_st &self) {
448 _error_free(self.error_messages);
449 self.error_messages = NULL;
450 }
451
452 const char *memcached_error(const memcached_st *memc) {
453 return memcached_last_error_message(memc);
454 }
455
456 const char *memcached_last_error_message(const memcached_st *shell) {
457 const Memcached *memc = memcached2Memcached(shell);
458 if (memc) {
459 if (memc->error_messages) {
460 if (memc->error_messages->size and memc->error_messages->message[0]) {
461 return memc->error_messages->message;
462 }
463
464 return memcached_strerror(memc, memc->error_messages->rc);
465 }
466
467 return memcached_strerror(memc, MEMCACHED_SUCCESS);
468 }
469
470 return memcached_strerror(memc, MEMCACHED_INVALID_ARGUMENTS);
471 }
472
473 bool memcached_has_current_error(Memcached &memc) {
474 if (memc.error_messages and memc.error_messages->query_id == memc.query_id
475 and memcached_failed(memc.error_messages->rc))
476 {
477 return true;
478 }
479
480 return false;
481 }
482
483 bool memcached_has_current_error(memcached_instance_st &server) {
484 return memcached_has_current_error(*(server.root));
485 }
486
487 memcached_return_t memcached_last_error(const memcached_st *shell) {
488 const Memcached *memc = memcached2Memcached(shell);
489 if (memc) {
490 if (memc->error_messages) {
491 return memc->error_messages->rc;
492 }
493
494 return MEMCACHED_SUCCESS;
495 }
496
497 return MEMCACHED_INVALID_ARGUMENTS;
498 }
499
500 int memcached_last_error_errno(const memcached_st *shell) {
501 const Memcached *memc = memcached2Memcached(shell);
502 if (memc == NULL) {
503 return 0;
504 }
505
506 if (memc->error_messages == NULL) {
507 return 0;
508 }
509
510 return memc->error_messages->local_errno;
511 }
512
513 const char *memcached_server_error(const memcached_instance_st *server) {
514 if (server == NULL) {
515 return NULL;
516 }
517
518 if (server->error_messages == NULL) {
519 return memcached_strerror(server->root, MEMCACHED_SUCCESS);
520 }
521
522 if (server->error_messages->size == 0) {
523 return memcached_strerror(server->root, server->error_messages->rc);
524 }
525
526 return server->error_messages->message;
527 }
528
529 memcached_error_t *memcached_error_copy(const memcached_instance_st &server) {
530 if (server.error_messages == NULL) {
531 return NULL;
532 }
533
534 memcached_error_t *error = libmemcached_xmalloc(server.root, memcached_error_t);
535 memcpy(error, server.error_messages, sizeof(memcached_error_t));
536 error->next = NULL;
537
538 return error;
539 }
540
541 memcached_return_t memcached_server_error_return(const memcached_instance_st *ptr) {
542 if (ptr == NULL) {
543 return MEMCACHED_INVALID_ARGUMENTS;
544 }
545
546 if (ptr->error_messages) {
547 return ptr->error_messages->rc;
548 }
549
550 return MEMCACHED_SUCCESS;
551 }
552
553 memcached_return_t memcached_instance_error_return(memcached_instance_st *instance) {
554 if (instance == NULL) {
555 return MEMCACHED_INVALID_ARGUMENTS;
556 }
557
558 if (instance->error_messages) {
559 return instance->error_messages->rc;
560 }
561
562 return MEMCACHED_SUCCESS;
563 }