Make sure we use the correct strerror() in case someone is using threads.
[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 <cassert>
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_st& memc, memcached_string_t *str, memcached_return_t &rc, const char *at, int local_errno= 0)
54 {
55 (void)at;
56 if (memc.error_messages && memc.error_messages->query_id != memc.query_id)
57 {
58 memcached_error_free(&memc);
59 }
60
61 // For memory allocation we use our error since it is a bit more specific
62 if (local_errno == ENOMEM and rc == MEMCACHED_ERRNO)
63 {
64 rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
65 }
66
67 if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
68 {
69 local_errno= ENOMEM;
70 }
71
72 if (rc == MEMCACHED_ERRNO and not local_errno)
73 {
74 local_errno= errno;
75 rc= MEMCACHED_ERRNO;
76 }
77
78 if (rc == MEMCACHED_ERRNO and local_errno == ENOTCONN)
79 {
80 rc= MEMCACHED_CONNECTION_FAILURE;
81 }
82
83 if (local_errno == EINVAL)
84 {
85 rc= MEMCACHED_INVALID_ARGUMENTS;
86 }
87
88 if (local_errno == ECONNREFUSED)
89 {
90 rc= MEMCACHED_CONNECTION_FAILURE;
91 }
92
93 memcached_error_t *error= (struct memcached_error_t *)libmemcached_malloc(&memc, sizeof(struct memcached_error_t));
94 if (not error) // Bad business if this happens
95 return;
96
97 error->root= &memc;
98 error->query_id= memc.query_id;
99 error->rc= rc;
100 error->local_errno= local_errno;
101
102 const char *errmsg_ptr;
103 char errmsg[MAX_ERROR_LENGTH];
104 errmsg[0]= 0;
105 errmsg_ptr= errmsg;
106
107 if (local_errno)
108 {
109 #ifdef STRERROR_R_CHAR_P
110 errmsg_ptr= strerror_r(local_errno, errmsg, sizeof(errmsg));
111 #else
112 strerror_r(local_errno, errmsg, sizeof(errmsg));
113 errmsg_ptr= errmsg;
114 #endif
115 }
116
117
118 if (str and str->size and local_errno)
119 {
120 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "%s(%s), %.*s -> %s",
121 memcached_strerror(&memc, rc),
122 errmsg_ptr,
123 memcached_string_printf(*str), at);
124 }
125 else if (local_errno)
126 {
127 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "%s(%s) -> %s",
128 memcached_strerror(&memc, rc),
129 errmsg_ptr,
130 at);
131 }
132 else if (str and str->size)
133 {
134 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "%s, %.*s -> %s",
135 memcached_strerror(&memc, rc),
136 int(str->size), str->c_str, at);
137 }
138 else
139 {
140 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "%s -> %s",
141 memcached_strerror(&memc, rc), at);
142 }
143
144 error->next= memc.error_messages;
145 memc.error_messages= error;
146 }
147
148 memcached_return_t memcached_set_error(memcached_st& memc, memcached_return_t rc, const char *at, const char *str, size_t length)
149 {
150 assert(rc != MEMCACHED_ERRNO);
151 memcached_string_t tmp= { str, length };
152 return memcached_set_error(memc, rc, at, tmp);
153 }
154
155 memcached_return_t memcached_set_error(memcached_server_st& self, memcached_return_t rc, const char *at, const char *str, size_t length)
156 {
157 assert(rc != MEMCACHED_ERRNO);
158 memcached_string_t tmp= { str, length };
159 return memcached_set_error(self, rc, at, tmp);
160 }
161
162 memcached_return_t memcached_set_error(memcached_st& memc, memcached_return_t rc, const char *at, memcached_string_t& str)
163 {
164 assert(rc != MEMCACHED_ERRNO);
165 if (memcached_success(rc))
166 return MEMCACHED_SUCCESS;
167
168 _set(memc, &str, rc, at);
169
170 return rc;
171 }
172
173 memcached_return_t memcached_set_error(memcached_server_st& self, memcached_return_t rc, const char *at, memcached_string_t& str)
174 {
175 assert(rc != MEMCACHED_ERRNO);
176 if (memcached_success(rc))
177 return MEMCACHED_SUCCESS;
178
179 char hostname_port_message[MAX_ERROR_LENGTH];
180 int size;
181 if (str.size)
182 {
183 size= snprintf(hostname_port_message, sizeof(hostname_port_message), "%.*s, host: %s:%d",
184 memcached_string_printf(str),
185 self.hostname, int(self.port));
186 }
187 else
188 {
189 size= snprintf(hostname_port_message, sizeof(hostname_port_message), "host: %s:%d",
190 self.hostname, int(self.port));
191 }
192
193 memcached_string_t error_host= { hostname_port_message, size };
194
195 if (not self.root)
196 return rc;
197
198 _set(*self.root, &error_host, rc, at);
199
200 return rc;
201 }
202
203 memcached_return_t memcached_set_error(memcached_server_st& self, memcached_return_t rc, const char *at)
204 {
205 assert(rc != MEMCACHED_ERRNO);
206 if (memcached_success(rc))
207 return MEMCACHED_SUCCESS;
208
209 char hostname_port[NI_MAXHOST +NI_MAXSERV + sizeof("host : ")];
210 int size= snprintf(hostname_port, sizeof(hostname_port), "host: %s:%d", self.hostname, int(self.port));
211
212 memcached_string_t error_host= { hostname_port, size};
213
214 if (not self.root)
215 return rc;
216
217 _set(*self.root, &error_host, rc, at);
218
219 return rc;
220 }
221
222 memcached_return_t memcached_set_error(memcached_st& self, memcached_return_t rc, const char *at)
223 {
224 assert(rc != MEMCACHED_ERRNO);
225 if (memcached_success(rc))
226 return MEMCACHED_SUCCESS;
227
228 _set(self, NULL, rc, at);
229
230 return rc;
231 }
232
233 memcached_return_t memcached_set_errno(memcached_st& self, int local_errno, const char *at, const char *str, size_t length)
234 {
235 memcached_string_t tmp= { str, length };
236 return memcached_set_errno(self, local_errno, at, tmp);
237 }
238
239 memcached_return_t memcached_set_errno(memcached_server_st& self, int local_errno, const char *at, const char *str, size_t length)
240 {
241 memcached_string_t tmp= { str, length };
242 return memcached_set_errno(self, local_errno, at, tmp);
243 }
244
245 memcached_return_t memcached_set_errno(memcached_st& self, int local_errno, const char *at)
246 {
247 if (not local_errno)
248 return MEMCACHED_SUCCESS;
249
250 memcached_return_t rc= MEMCACHED_ERRNO;
251 _set(self, NULL, rc, at, local_errno);
252
253 return rc;
254 }
255
256 memcached_return_t memcached_set_errno(memcached_st& memc, int local_errno, const char *at, memcached_string_t& str)
257 {
258 if (not local_errno)
259 return MEMCACHED_SUCCESS;
260
261 memcached_return_t rc= MEMCACHED_ERRNO;
262 _set(memc, &str, rc, at, local_errno);
263
264 return rc;
265 }
266
267 memcached_return_t memcached_set_errno(memcached_server_st& self, int local_errno, const char *at, memcached_string_t& str)
268 {
269 if (not local_errno)
270 return MEMCACHED_SUCCESS;
271
272 char hostname_port_message[MAX_ERROR_LENGTH];
273 int size;
274 if (str.size)
275 {
276 size= snprintf(hostname_port_message, sizeof(hostname_port_message), "%.*s, host: %s:%d",
277 memcached_string_printf(str),
278 self.hostname, int(self.port));
279 }
280 else
281 {
282 size= snprintf(hostname_port_message, sizeof(hostname_port_message), "host: %s:%d",
283 self.hostname, int(self.port));
284 }
285
286 memcached_string_t error_host= { hostname_port_message, size };
287
288 self.cached_errno= local_errno; // Store in the actual server
289
290 memcached_return_t rc= MEMCACHED_ERRNO;
291 if (not self.root)
292 return rc;
293
294 _set(*self.root, &error_host, rc, at, local_errno);
295
296 return rc;
297 }
298
299 memcached_return_t memcached_set_errno(memcached_server_st& self, int local_errno, const char *at)
300 {
301 if (not local_errno)
302 return MEMCACHED_SUCCESS;
303
304 char hostname_port_message[MAX_ERROR_LENGTH];
305 int size = snprintf(hostname_port_message, sizeof(hostname_port_message), "host: %s:%d",
306 self.hostname, int(self.port));
307
308 memcached_string_t error_host= { hostname_port_message, size };
309
310 self.cached_errno= local_errno; // Store in the actual server
311
312 memcached_return_t rc= MEMCACHED_ERRNO;
313 if (not self.root)
314 return rc;
315
316 _set(*self.root, &error_host, rc, at, local_errno);
317
318 return rc;
319 }
320
321 static void _error_print(const memcached_error_t *error)
322 {
323 if (not error)
324 return;
325
326 if (not error->size)
327 {
328 fprintf(stderr, "%s\n", memcached_strerror(NULL, error->rc) );
329 }
330 else
331 {
332 fprintf(stderr, "%s %s\n", memcached_strerror(NULL, error->rc), error->message);
333 }
334
335 _error_print(error->next);
336 }
337
338 void memcached_error_print(const memcached_st *self)
339 {
340 if (not self)
341 return;
342
343 _error_print(self->error_messages);
344 }
345
346 static void _error_free(memcached_error_t *error)
347 {
348 if (not error)
349 return;
350
351 _error_free(error->next);
352
353 if (error && error->root)
354 {
355 libmemcached_free(error->root, error);
356 }
357 else if (error)
358 {
359 free(error);
360 }
361 }
362
363 void memcached_error_free(memcached_st *self)
364 {
365 if (not self)
366 return;
367
368 _error_free(self->error_messages);
369 self->error_messages= NULL;
370 }
371
372 const char *memcached_last_error_message(memcached_st *memc)
373 {
374 if (not memc)
375 return memcached_strerror(memc, MEMCACHED_INVALID_ARGUMENTS);
376
377 if (not memc->error_messages)
378 return memcached_strerror(memc, MEMCACHED_SUCCESS);
379
380 if (not memc->error_messages->size)
381 return memcached_strerror(memc, memc->error_messages->rc);
382
383 return memc->error_messages->message;
384 }
385
386
387 bool memcached_has_current_error(memcached_st &memc)
388 {
389 if (memc.error_messages
390 and memc.error_messages->query_id == memc.query_id
391 and memcached_failed(memc.error_messages->rc))
392 {
393 return true;
394 }
395
396 return false;
397 }
398
399 memcached_return_t memcached_last_error(memcached_st *memc)
400 {
401 if (not memc)
402 return MEMCACHED_INVALID_ARGUMENTS;
403
404 if (not memc->error_messages)
405 return MEMCACHED_SUCCESS;
406
407 return memc->error_messages->rc;
408 }
409
410 int memcached_last_error_errno(memcached_st *memc)
411 {
412 if (not memc)
413 return 0;
414
415 if (not memc->error_messages)
416 return 0;
417
418 return memc->error_messages->local_errno;
419 }