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(&current_epoch, NULL);
145   }
146 
147   struct tm current_tm;
148   if (current_epoch.tv_sec == 0)
149   {
150     (void)gettimeofday(&current_epoch, NULL);
151   }
152 
153   if ((gmtime_r(&current_epoch.tv_sec, &current_tm) == NULL))
154   {
155     memset(&current_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