2 +--------------------------------------------------------------------+
3 | libmemcached-awesome - 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-2021 Michael Wallner https://awesome.co/ |
13 +--------------------------------------------------------------------+
16 #include "libmemcached/common.h"
18 #include "libmemcached/assert.hpp"
24 #define MAX_ERROR_LENGTH 2048
25 struct memcached_error_t
{
28 struct memcached_error_t
*next
;
29 memcached_return_t rc
;
32 char message
[MAX_ERROR_LENGTH
];
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
);
40 if (memc
.error_messages
) {
41 if (memc
.error_messages
->rc
== MEMCACHED_TIMEOUT
) {
42 server
.io_wait_count
.timeouts
++;
45 memcached_error_t
*error
= libmemcached_xmalloc(&memc
, memcached_error_t
);
47 memcpy(error
, memc
.error_messages
, sizeof(memcached_error_t
));
48 error
->next
= server
.error_messages
;
49 server
.error_messages
= error
;
55 static int error_log_fd
= -1;
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
);
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
;
70 if (rc
== MEMCACHED_MEMORY_ALLOCATION_FAILURE
) {
74 if (rc
== MEMCACHED_ERRNO
and not local_errno
) {
79 if (rc
== MEMCACHED_ERRNO
and local_errno
== ENOTCONN
) {
80 rc
= MEMCACHED_CONNECTION_FAILURE
;
83 if (rc
== MEMCACHED_ERRNO
and local_errno
== ECONNRESET
) {
84 rc
= MEMCACHED_CONNECTION_FAILURE
;
87 if (local_errno
== EINVAL
) {
88 rc
= MEMCACHED_INVALID_ARGUMENTS
;
91 if (local_errno
== ECONNREFUSED
) {
92 rc
= MEMCACHED_CONNECTION_FAILURE
;
95 if (rc
== MEMCACHED_TIMEOUT
) {
98 memcached_error_t
*error
= libmemcached_xmalloc(&memc
, memcached_error_t
);
99 if (error
== NULL
) // Bad business if this happens
101 assert_msg(error
, "libmemcached_xmalloc() failed to allocate a memcached_error_t");
106 error
->query_id
= memc
.query_id
;
108 error
->local_errno
= local_errno
;
110 // MEMCACHED_CLIENT_ERROR is a special case because it is an error coming from the server
111 if (rc
== MEMCACHED_CLIENT_ERROR
) {
114 if (str
and str
->size
) {
115 assert(error
->local_errno
== 0);
116 error
->local_errno
= 0;
118 error
->size
= (int) snprintf(error
->message
, MAX_ERROR_LENGTH
, "(%p) %.*s", error
->root
,
119 int(str
->size
), str
->c_str
);
121 } else if (local_errno
) {
122 const char *errmsg_ptr
;
123 char errmsg
[MAX_ERROR_LENGTH
];
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
));
133 snprintf(errmsg
, sizeof(errmsg
), "%s", strerror(local_errno
));
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
);
142 error
->size
= (int) snprintf(error
->message
, MAX_ERROR_LENGTH
, "(%p) %s(%s) -> %s",
143 error
->root
, memcached_strerror(&memc
, rc
), errmsg_ptr
, at
);
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
) {
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
);
153 error
->size
= (int) snprintf(error
->message
, MAX_ERROR_LENGTH
, "(%p) %s -> %s", error
->root
,
154 memcached_strerror(&memc
, rc
), at
);
157 error
->next
= memc
.error_messages
;
158 memc
.error_messages
= error
;
160 if (error_log_fd
== -1)
162 // unlink("/tmp/libmemcachd.log");
163 if ((error_log_fd
= open("/tmp/libmemcachd.log", O_CREAT
| O_WRONLY
| O_APPEND
, 0644)) < 0)
169 ::write(error_log_fd
, error
->message
, error
->size
);
170 ::write(error_log_fd
, "\n", 1);
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
);
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");
190 memcached_string_t tmp
= {str
, length
};
191 return memcached_set_error(self
, rc
, at
, tmp
);
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
);
205 memcached_return_t
memcached_set_parser_error(Memcached
&memc
, const char *at
, const char *format
,
210 va_start(args
, format
);
211 int length
= vsnprintf(buffer
, sizeof(buffer
), format
, args
);
214 return memcached_set_error(memc
, MEMCACHED_PARSE_ERROR
, at
, buffer
, length
);
217 static inline size_t append_host_to_string(memcached_instance_st
&self
, char *buffer
,
218 const size_t buffer_length
) {
221 case MEMCACHED_CONNECTION_TCP
:
222 case MEMCACHED_CONNECTION_UDP
:
223 size
+= snprintf(buffer
, buffer_length
, " host: %s:%d", self
.hostname(), int(self
.port()));
226 case MEMCACHED_CONNECTION_UNIX_SOCKET
:
227 size
+= snprintf(buffer
, buffer_length
, " socket: %s", self
.hostname());
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");
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
) {
245 char hostname_port_message
[MAX_ERROR_LENGTH
];
246 char *hostname_port_message_ptr
= hostname_port_message
;
249 size
= snprintf(hostname_port_message_ptr
, sizeof(hostname_port_message
), "%.*s, ",
250 memcached_string_printf(str
));
251 hostname_port_message_ptr
+= size
;
255 append_host_to_string(self
, hostname_port_message_ptr
, sizeof(hostname_port_message
) - size
);
257 memcached_string_t error_host
= {hostname_port_message
, size_t(size
)};
259 assert_msg(self
.root
, "Programmer error, root was not set on instance");
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
);
271 memcached_return_t
memcached_set_error(memcached_instance_st
&self
, memcached_return_t rc
,
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) {
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
));
283 memcached_string_t error_host
= {hostname_port
, size
};
286 _set(*self
.root
, &error_host
, rc
, at
);
287 _set(self
, *self
.root
);
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) {
300 _set(self
, NULL
, rc
, at
);
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
);
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
);
317 memcached_return_t
memcached_set_errno(Memcached
&self
, int local_errno
, const char *at
) {
318 if (local_errno
== 0) {
319 return MEMCACHED_SUCCESS
;
322 memcached_return_t rc
= MEMCACHED_ERRNO
;
323 _set(self
, NULL
, rc
, at
, local_errno
);
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
;
334 memcached_return_t rc
= MEMCACHED_ERRNO
;
335 _set(memc
, &str
, rc
, at
, local_errno
);
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
;
346 char hostname_port_message
[MAX_ERROR_LENGTH
];
347 char *hostname_port_message_ptr
= hostname_port_message
;
350 size
= snprintf(hostname_port_message_ptr
, sizeof(hostname_port_message
), "%.*s, ",
351 memcached_string_printf(str
));
354 append_host_to_string(self
, hostname_port_message_ptr
, sizeof(hostname_port_message
) - size
);
356 memcached_string_t error_host
= {hostname_port_message
, size
};
358 memcached_return_t rc
= MEMCACHED_ERRNO
;
359 if (self
.root
== NULL
) {
363 _set(*self
.root
, &error_host
, rc
, at
, local_errno
);
364 _set(self
, (*self
.root
));
367 if (self
.root
->error_messages
->rc
!= self
.error_messages
->rc
)
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
));
378 memcached_return_t
memcached_set_errno(memcached_instance_st
&self
, int local_errno
,
380 if (local_errno
== 0) {
381 return MEMCACHED_SUCCESS
;
384 char hostname_port_message
[MAX_ERROR_LENGTH
];
385 size_t size
= append_host_to_string(self
, hostname_port_message
, sizeof(hostname_port_message
));
387 memcached_string_t error_host
= {hostname_port_message
, size
};
389 memcached_return_t rc
= MEMCACHED_ERRNO
;
390 if (self
.root
== NULL
) {
394 _set(*self
.root
, &error_host
, rc
, at
, local_errno
);
395 _set(self
, (*self
.root
));
400 static void _error_print(const memcached_error_t
*error
) {
405 if (error
->size
== 0) {
406 fprintf(stderr
, "\t%s\n", memcached_strerror(NULL
, error
->rc
));
408 fprintf(stderr
, "\t%s %s\n", memcached_strerror(NULL
, error
->rc
), error
->message
);
411 _error_print(error
->next
);
414 void memcached_error_print(const Memcached
*shell
) {
415 const Memcached
*self
= memcached2Memcached(shell
);
420 _error_print(self
->error_messages
);
422 for (uint32_t x
= 0; x
< memcached_server_count(self
); x
++) {
423 memcached_instance_st
*instance
= memcached_instance_by_position(self
, x
);
425 _error_print(instance
->error_messages
);
429 static void _error_free(memcached_error_t
*error
) {
431 _error_free(error
->next
);
433 libmemcached_free(error
->root
, error
);
437 void memcached_error_free(Memcached
&self
) {
438 _error_free(self
.error_messages
);
439 self
.error_messages
= NULL
;
442 void memcached_error_free(memcached_instance_st
&self
) {
443 _error_free(self
.error_messages
);
444 self
.error_messages
= NULL
;
447 void memcached_error_free(memcached_server_st
&self
) {
448 _error_free(self
.error_messages
);
449 self
.error_messages
= NULL
;
452 const char *memcached_error(const memcached_st
*memc
) {
453 return memcached_last_error_message(memc
);
456 const char *memcached_last_error_message(const memcached_st
*shell
) {
457 const Memcached
*memc
= memcached2Memcached(shell
);
459 if (memc
->error_messages
) {
460 if (memc
->error_messages
->size
and memc
->error_messages
->message
[0]) {
461 return memc
->error_messages
->message
;
464 return memcached_strerror(memc
, memc
->error_messages
->rc
);
467 return memcached_strerror(memc
, MEMCACHED_SUCCESS
);
470 return memcached_strerror(memc
, MEMCACHED_INVALID_ARGUMENTS
);
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
))
483 bool memcached_has_current_error(memcached_instance_st
&server
) {
484 return memcached_has_current_error(*(server
.root
));
487 memcached_return_t
memcached_last_error(const memcached_st
*shell
) {
488 const Memcached
*memc
= memcached2Memcached(shell
);
490 if (memc
->error_messages
) {
491 return memc
->error_messages
->rc
;
494 return MEMCACHED_SUCCESS
;
497 return MEMCACHED_INVALID_ARGUMENTS
;
500 int memcached_last_error_errno(const memcached_st
*shell
) {
501 const Memcached
*memc
= memcached2Memcached(shell
);
506 if (memc
->error_messages
== NULL
) {
510 return memc
->error_messages
->local_errno
;
513 const char *memcached_server_error(const memcached_instance_st
*server
) {
514 if (server
== NULL
) {
518 if (server
->error_messages
== NULL
) {
519 return memcached_strerror(server
->root
, MEMCACHED_SUCCESS
);
522 if (server
->error_messages
->size
== 0) {
523 return memcached_strerror(server
->root
, server
->error_messages
->rc
);
526 return server
->error_messages
->message
;
529 memcached_error_t
*memcached_error_copy(const memcached_instance_st
&server
) {
530 if (server
.error_messages
== NULL
) {
534 memcached_error_t
*error
= libmemcached_xmalloc(server
.root
, memcached_error_t
);
535 memcpy(error
, server
.error_messages
, sizeof(memcached_error_t
));
541 memcached_return_t
memcached_server_error_return(const memcached_instance_st
*ptr
) {
543 return MEMCACHED_INVALID_ARGUMENTS
;
546 if (ptr
->error_messages
) {
547 return ptr
->error_messages
->rc
;
550 return MEMCACHED_SUCCESS
;
553 memcached_return_t
memcached_instance_error_return(memcached_instance_st
*instance
) {
554 if (instance
== NULL
) {
555 return MEMCACHED_INVALID_ARGUMENTS
;
558 if (instance
->error_messages
) {
559 return instance
->error_messages
->rc
;
562 return MEMCACHED_SUCCESS
;