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