1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * Gearmand client and server library.
4 *
5 * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
6 * Copyright (C) 2008 Brian Aker, Eric Day
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are
11 * met:
12 *
13 * * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * * Redistributions in binary form must reproduce the above
17 * copyright notice, this list of conditions and the following disclaimer
18 * in the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * * The names of its contributors may not be used to endorse or
22 * promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 */
38
39 /**
40 * @file
41 * @brief Gearman State Definitions
42 */
43
44 #include "gear_config.h"
45
46 #include "libgearman-server/common.h"
47 #include "libgearman-server/timer.h"
48
49 #include <algorithm>
50 #include <cerrno>
51 #include <cstddef>
52 #include <cstdlib>
53 #include <cstring>
54 #include <ctime>
55 #include <pthread.h>
56
57 #ifdef _WIN32
58 # include <malloc.h>
59 #elif defined(__FreeBSD__)
60 # include <stdlib.h>
61 #else
62 # include <alloca.h>
63 #endif
64
65 #ifndef __INTEL_COMPILER
66 # pragma GCC diagnostic ignored "-Wold-style-cast"
67 # pragma GCC diagnostic ignored "-Wformat-nonliteral"
68 # pragma GCC diagnostic ignored "-Wformat-security"
69 #endif
70
71
72 static pthread_key_t logging_key;
73 static pthread_once_t intitialize_log_once= PTHREAD_ONCE_INIT;
74
delete_log(void * ptr)75 static void delete_log(void * ptr)
76 {
77 if (ptr)
78 {
79 free(ptr);
80 }
81 }
82
create_log(void)83 static void create_log(void)
84 {
85 int pthread_error;
86 if ((pthread_error= pthread_key_create(&logging_key, delete_log)))
87 {
88 gearmand_log_fatal_perror(GEARMAND_AT, "pthread_key_create", pthread_error, "pthread_key_create");
89 abort();
90 }
91 }
92
gearmand_initialize_thread_logging(const char * identity)93 gearmand_error_t gearmand_initialize_thread_logging(const char *identity)
94 {
95 if (identity)
96 {
97 int pthread_error;
98 if ((pthread_error= pthread_once(&intitialize_log_once, create_log)))
99 {
100 return gearmand_log_fatal_perror(GEARMAND_AT, "pthread_once", pthread_error, "identity: %s", identity);
101 }
102
103 if (pthread_getspecific(logging_key) == NULL)
104 {
105 const char *key_to_use= strdup(identity);
106 if ((pthread_error= pthread_setspecific(logging_key, key_to_use)))
107 {
108 return gearmand_log_fatal_perror(GEARMAND_AT, "pthread_setspecific", pthread_error, "identity: %s", identity);
109 }
110 }
111
112 return GEARMAN_SUCCESS;
113 }
114
115 gearmand_fatal("identity was NULL");
116
117 return GEARMAN_INVALID_ARGUMENT;
118 }
119
120 /**
121 * Log a message.
122 *
123 * @param[in] gearman Structure previously initialized with gearman_create() or
124 * gearman_clone().
125 * @param[in] verbose Logging level of the message.
126 * @param[in] format Format and variable argument list of message.
127 * @param[in] args Variable argument list that has been initialized.
128 */
129
gearmand_log(const char * position,const char * func,gearmand_verbose_t verbose,const gearmand_error_t error_arg,const char * format,va_list args)130 static void gearmand_log(const char *position, const char *func /* func */,
131 gearmand_verbose_t verbose,
132 const gearmand_error_t error_arg,
133 const char *format, va_list args)
134 {
135 struct timeval current_epoch;
136
137 if (Gearmand() and Gearmand()->verbose < GEARMAND_VERBOSE_DEBUG)
138 {
139 current_epoch= libgearman::server::Epoch::current();
140 current_epoch.tv_usec= 0;
141 }
142 else
143 {
144 (void)gettimeofday(¤t_epoch, NULL);
145 }
146
147 struct tm current_tm;
148 if (current_epoch.tv_sec == 0)
149 {
150 (void)gettimeofday(¤t_epoch, NULL);
151 }
152
153 if ((gmtime_r(¤t_epoch.tv_sec, ¤t_tm) == NULL))
154 {
155 memset(¤t_epoch, 0, sizeof(current_epoch));
156 }
157
158 (void) pthread_once(&intitialize_log_once, create_log);
159
160 const char *identity= (const char *)pthread_getspecific(logging_key);
161
162 if (identity == NULL)
163 {
164 identity= "[ main ]";
165 }
166
167 char log_buffer[GEARMAN_MAX_ERROR_SIZE*2] = { 0 };
168 if (Gearmand() && Gearmand()->log_fn)
169 {
170 char *log_buffer_ptr= log_buffer;
171 size_t remaining_size= sizeof(log_buffer);
172
173 {
174 int length= snprintf(log_buffer, sizeof(log_buffer), "%04d-%02d-%02d %02d:%02d:%02d.%06d %s ",
175 int(1900 +current_tm.tm_year), current_tm.tm_mon +1, current_tm.tm_mday, current_tm.tm_hour,
176 current_tm.tm_min, current_tm.tm_sec, int(current_epoch.tv_usec),
177 identity);
178 // We just return whatever we have if this occurs
179 if (length <= 0 or (size_t)length >= sizeof(log_buffer))
180 {
181 remaining_size= 0;
182 }
183 else
184 {
185 remaining_size-= size_t(length);
186 log_buffer_ptr+= length;
187 }
188 }
189
190 if (remaining_size)
191 {
192 int length= vsnprintf(log_buffer_ptr, remaining_size, format, args);
193 if (length <= 0 or size_t(length) >= remaining_size)
194 {
195 remaining_size= 0;
196 }
197 else
198 {
199 remaining_size-= size_t(length);
200 log_buffer_ptr+= length;
201 }
202 }
203
204 if (remaining_size and error_arg != GEARMAN_SUCCESS)
205 {
206 int length= snprintf(log_buffer_ptr, remaining_size, " %s(%s)", func, gearmand_strerror(error_arg));
207 if (length <= 0 or size_t(length) >= remaining_size)
208 {
209 remaining_size= 0;
210 }
211 else
212 {
213 remaining_size-= size_t(length);
214 log_buffer_ptr+= length;
215 }
216 }
217
218 if (remaining_size and position and verbose != GEARMAND_VERBOSE_INFO)
219 {
220 int length= snprintf(log_buffer_ptr, remaining_size, " -> %s", position);
221 if (length <= 0 or size_t(length) >= remaining_size)
222 {
223 remaining_size= 0;
224 }
225 }
226
227 // Make sure this is null terminated
228 log_buffer[sizeof(log_buffer) -1]= 0;
229 }
230
231 if (Gearmand() and Gearmand()->log_fn)
232 {
233 Gearmand()->log_fn(log_buffer, verbose, (void *)Gearmand()->log_context);
234 }
235 else
236 {
237 fprintf(stderr, "%s -> %s",
238 log_buffer, gearmand_verbose_name(verbose));
239 vfprintf(stderr, format, args);
240 fprintf(stderr, "\n");
241 }
242 }
243
244
gearmand_log_fatal(const char * position,const char * func,const char * format,...)245 gearmand_error_t gearmand_log_fatal(const char *position, const char *func, const char *format, ...)
246 {
247 if (Gearmand() and Gearmand()->verbose < GEARMAND_VERBOSE_FATAL)
248 {
249 return GEARMAN_ERRNO;
250 }
251
252 {
253 va_list args;
254 va_start(args, format);
255 gearmand_log(position, func, GEARMAND_VERBOSE_FATAL, GEARMAN_SUCCESS, format, args);
256 va_end(args);
257 }
258
259 return GEARMAN_ERRNO;
260 }
261
gearmand_log_fatal_perror(const char * position,const char * function,const int local_errno,const char * format,...)262 gearmand_error_t gearmand_log_fatal_perror(const char *position, const char *function, const int local_errno, const char *format, ...)
263 {
264 if (Gearmand() and Gearmand()->verbose < GEARMAND_VERBOSE_FATAL)
265 {
266 return GEARMAN_ERRNO;
267 }
268
269 char* message_buffer= NULL;
270 {
271 va_list args;
272 va_start(args, format);
273
274 size_t ask= snprintf(0, 0, format);
275 ask++; // for null
276 message_buffer= (char*)alloca(sizeof(char) * ask);
277 if (message_buffer)
278 {
279 vsnprintf(message_buffer, ask, format, args);
280 }
281 va_end(args);
282 }
283
284 {
285 const char *errmsg_ptr;
286 char errmsg[GEARMAN_MAX_ERROR_SIZE];
287 errmsg[0]= 0;
288
289 #ifdef STRERROR_R_CHAR_P
290 errmsg_ptr= strerror_r(local_errno, errmsg, sizeof(errmsg));
291 #else
292 strerror_r(local_errno, errmsg, sizeof(errmsg));
293 errmsg_ptr= errmsg;
294 #endif
295
296 if (message_buffer)
297 {
298 gearmand_log_fatal(position, function, "%s(%s)", message_buffer, errmsg_ptr);
299 }
300 else
301 {
302 gearmand_log_fatal(position, function, "%s", errmsg_ptr);
303 }
304 }
305
306 switch (local_errno)
307 {
308 case ENOMEM:
309 return GEARMAN_MEMORY_ALLOCATION_FAILURE;
310
311 case ECONNRESET:
312 case EHOSTDOWN:
313 return GEARMAN_LOST_CONNECTION;
314
315 default:
316 break;
317 }
318
319 return GEARMAN_ERRNO;
320 }
321
gearmand_log_error(const char * position,const char * function,const char * format,...)322 gearmand_error_t gearmand_log_error(const char *position, const char *function, const char *format, ...)
323 {
324 if (not Gearmand() or Gearmand()->verbose >= GEARMAND_VERBOSE_ERROR)
325 {
326 va_list args;
327 va_start(args, format);
328 gearmand_log(position, function, GEARMAND_VERBOSE_ERROR, GEARMAN_SUCCESS, format, args);
329 va_end(args);
330 }
331
332 return GEARMAN_UNKNOWN_OPTION;
333 }
334
gearmand_log_warning(const char * position,const char * function,const char * format,...)335 void gearmand_log_warning(const char *position, const char *function, const char *format, ...)
336 {
337 if (not Gearmand() or Gearmand()->verbose >= GEARMAND_VERBOSE_WARN)
338 {
339 va_list args;
340 va_start(args, format);
341 gearmand_log(position, function, GEARMAND_VERBOSE_WARN, GEARMAN_SUCCESS, format, args);
342 va_end(args);
343 }
344 }
345
346 // LOG_NOTICE is only used for reporting job status.
gearmand_log_notice(const char * position,const char * function,const char * format,...)347 void gearmand_log_notice(const char *position, const char *function, const char *format, ...)
348 {
349 if (not Gearmand() or Gearmand()->verbose >= GEARMAND_VERBOSE_NOTICE)
350 {
351 va_list args;
352 va_start(args, format);
353 gearmand_log(position, function, GEARMAND_VERBOSE_NOTICE, GEARMAN_SUCCESS, format, args);
354 va_end(args);
355 }
356 }
357
gearmand_log_info(const char * position,const char * function,const char * format,...)358 void gearmand_log_info(const char *position, const char *function, const char *format, ...)
359 {
360 if (not Gearmand() or Gearmand()->verbose >= GEARMAND_VERBOSE_INFO)
361 {
362 va_list args;
363 va_start(args, format);
364 gearmand_log(position, function, GEARMAND_VERBOSE_INFO, GEARMAN_SUCCESS, format, args);
365 va_end(args);
366 }
367 }
368
gearmand_log_debug(const char * position,const char * function,const char * format,...)369 void gearmand_log_debug(const char *position, const char *function, const char *format, ...)
370 {
371 va_list args;
372
373 if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_DEBUG)
374 {
375 va_start(args, format);
376 gearmand_log(position, function, GEARMAND_VERBOSE_DEBUG, GEARMAN_SUCCESS, format, args);
377 va_end(args);
378 }
379 }
380
gearmand_log_perror(const char * position,const char * function,const int local_errno,const char * format,...)381 gearmand_error_t gearmand_log_perror(const char *position, const char *function, const int local_errno, const char *format, ...)
382 {
383 if (not Gearmand() or (Gearmand()->verbose >= GEARMAND_VERBOSE_ERROR))
384 {
385 char* message_buffer= NULL;
386 {
387 va_list args;
388 va_start(args, format);
389
390 size_t ask= snprintf(0, 0, format);
391 ask++; // for null
392 message_buffer= (char*)alloca(sizeof(char) * ask);
393 vsnprintf(message_buffer, ask, format, args);
394
395 va_end(args);
396 }
397
398 const char *errmsg_ptr;
399 char errmsg[GEARMAN_MAX_ERROR_SIZE];
400 errmsg[0]= 0;
401
402 #ifdef STRERROR_R_CHAR_P
403 errmsg_ptr= strerror_r(local_errno, errmsg, sizeof(errmsg));
404 #else
405 strerror_r(local_errno, errmsg, sizeof(errmsg));
406 errmsg_ptr= errmsg;
407 #endif
408 if (message_buffer)
409 {
410 gearmand_log_error(position, function, "%s(%s)", message_buffer, errmsg_ptr);
411 }
412 else
413 {
414 gearmand_log_error(position, function, "%s", errmsg_ptr);
415 }
416 }
417
418 switch (local_errno)
419 {
420 case ENOMEM:
421 return GEARMAN_MEMORY_ALLOCATION_FAILURE;
422
423 case ECONNRESET:
424 case EHOSTDOWN:
425 return GEARMAN_LOST_CONNECTION;
426
427 default:
428 break;
429 }
430
431 return GEARMAN_ERRNO;
432 }
433
gearmand_log_gerror(const char * position,const char * function,const gearmand_error_t rc,const char * format,...)434 gearmand_error_t gearmand_log_gerror(const char *position, const char *function, const gearmand_error_t rc, const char *format, ...)
435 {
436 if (gearmand_failed(rc) and rc != GEARMAN_IO_WAIT)
437 {
438 va_list args;
439
440 if (Gearmand() == NULL or Gearmand()->verbose >= GEARMAND_VERBOSE_ERROR)
441 {
442 va_start(args, format);
443 gearmand_log(position, function, GEARMAND_VERBOSE_ERROR, rc, format, args);
444 va_end(args);
445 }
446 }
447 else if (rc == GEARMAN_IO_WAIT)
448 { }
449
450 return rc;
451 }
452
gearmand_log_gerror_warn(const char * position,const char * function,const gearmand_error_t rc,const char * format,...)453 gearmand_error_t gearmand_log_gerror_warn(const char *position, const char *function, const gearmand_error_t rc, const char *format, ...)
454 {
455 if (gearmand_failed(rc) and rc != GEARMAN_IO_WAIT)
456 {
457 va_list args;
458
459 if (Gearmand() == NULL or Gearmand()->verbose >= GEARMAND_VERBOSE_WARN)
460 {
461 va_start(args, format);
462 gearmand_log(position, function, GEARMAND_VERBOSE_WARN, rc, format, args);
463 va_end(args);
464 }
465 }
466 else if (rc == GEARMAN_IO_WAIT)
467 { }
468
469 return rc;
470 }
471
gearmand_log_gai_error(const char * position,const char * function,const int rc,const char * message)472 gearmand_error_t gearmand_log_gai_error(const char *position, const char *function, const int rc, const char *message)
473 {
474 if (rc == EAI_SYSTEM)
475 {
476 return gearmand_log_perror(position, function, errno, message);
477 }
478
479 gearmand_log_error(position, function, "%s getaddrinfo(%s)", message, gai_strerror(rc));
480
481 return GEARMAN_GETADDRINFO;
482 }
483
gearmand_log_memory_error(const char * position,const char * function,const char * allocator,const char * object_type,size_t count,size_t size)484 gearmand_error_t gearmand_log_memory_error(const char *position, const char *function, const char *allocator, const char *object_type, size_t count, size_t size)
485 {
486 if (count > 1)
487 {
488 gearmand_log_error(position, function, "%s(%s, count: %lu size: %lu)", allocator, object_type, static_cast<unsigned long>(count), static_cast<unsigned long>(size));
489 }
490 else
491 {
492 gearmand_log_error(position, function, "%s(%s, size: %lu)", allocator, object_type, static_cast<unsigned long>(count), static_cast<unsigned long>(size));
493 }
494
495 return GEARMAN_MEMORY_ALLOCATION_FAILURE;
496 }
497