1 /*
2 * Copyright (c) 2008 Sippy Software, Inc., http://www.sippysoft.com
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28 #include <sys/types.h>
29 #include <errno.h>
30 #include <math.h>
31 #include <syslog.h>
32 #include <stdatomic.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 #include "rtpp_log.h"
40 #include "rtpp_cfg_stable.h"
41 #ifdef RTPP_LOG_ADVANCED
42 #include "rtpp_syslog_async.h"
43 #endif
44 #include "rtpp_time.h"
45 #include "rtpp_mallocs.h"
46
47 #ifdef RTPP_LOG_ADVANCED
48 static int syslog_async_opened = 0;
49 #endif
50 static double iitime = 0.0;
51
52 #define CALL_ID_NONE "GLOBAL"
53
54 static struct {
55 atomic_uint next_ticket;
56 atomic_uint now_serving;
57 } _log_lock = {ATOMIC_VAR_INIT(0), ATOMIC_VAR_INIT(0)};
58
59 struct rtpp_log_inst {
60 char *call_id;
61 int level;
62 const char *format_sl[2];
63 const char *eformat_sl[2];
64 const char *format_se[2];
65 const char *eformat_se[2];
66 double itime;
67 };
68
69 struct rtpp_log_inst *
_rtpp_log_open(struct rtpp_cfg_stable * cf,const char * app,const char * call_id)70 _rtpp_log_open(struct rtpp_cfg_stable *cf, const char *app, const char *call_id)
71 {
72 const char *stritime;
73 const char *tform;
74 char *se;
75 struct rtpp_log_inst *rli;
76 #ifdef RTPP_LOG_ADVANCED
77 int facility;
78
79 facility = cf->log_facility;
80 if (facility == -1)
81 facility = LOG_DAEMON;
82
83 if (cf->nodaemon == 0 && syslog_async_opened == 0) {
84 if (syslog_async_init(app, facility) == 0)
85 syslog_async_opened = 1;
86 }
87 #endif
88 rli = rtpp_zmalloc(sizeof(struct rtpp_log_inst));
89 if (rli == NULL) {
90 return (NULL);
91 }
92 tform = getenv("RTPP_LOG_TFORM");
93 if (tform != NULL && strcmp(tform, "rel") == 0) {
94 stritime = getenv("RTPP_LOG_TSTART");
95 if (stritime != NULL) {
96 rli->itime = strtod(stritime, &se);
97 } else {
98 if (iitime == 0.0) {
99 iitime = getdtime();
100 }
101 rli->itime = iitime;
102 }
103 }
104 if (call_id != NULL) {
105 rli->call_id = strdup(call_id);
106 }
107 if (cf->log_level == -1) {
108 rli->level = (cf->nodaemon != 0) ? RTPP_LOG_DBUG : RTPP_LOG_WARN;
109 } else {
110 rli->level = cf->log_level;
111 }
112 rli->format_se[0] = "%s%s:%s:%s: ";
113 rli->format_se[1] = "\n";
114 rli->eformat_se[0] = "%s%s:%s:%s: ";
115 rli->eformat_se[1] = ": %s (%d)\n";
116 rli->format_sl[0] = "%s:%s:%s: ";
117 rli->format_sl[1] = NULL;
118 rli->eformat_sl[0] = "%s:%s:%s: ";
119 rli->eformat_sl[1] = ": %s (%d)";
120 return (rli);
121 }
122
123 void
_rtpp_log_close(struct rtpp_log_inst * rli)124 _rtpp_log_close(struct rtpp_log_inst *rli)
125 {
126 if (rli->call_id != NULL) {
127 free(rli->call_id);
128 }
129 free(rli);
130 return;
131 }
132
133 static const char *
strlvl(int level)134 strlvl(int level)
135 {
136
137 switch(level) {
138 case RTPP_LOG_DBUG:
139 return "DBUG";
140
141 case RTPP_LOG_INFO:
142 return "INFO";
143
144 case RTPP_LOG_WARN:
145 return "WARN";
146
147 case RTPP_LOG_ERR:
148 return "ERR";
149
150 case RTPP_LOG_CRIT:
151 return "CRIT";
152
153 default:
154 break;
155 }
156
157 abort();
158
159 return NULL;
160 }
161
162 int
rtpp_log_str2lvl(const char * strl)163 rtpp_log_str2lvl(const char *strl)
164 {
165
166 if (strcasecmp(strl, "DBUG") == 0)
167 return RTPP_LOG_DBUG;
168
169 if (strcasecmp(strl, "INFO") == 0)
170 return RTPP_LOG_INFO;
171
172 if (strcasecmp(strl, "WARN") == 0)
173 return RTPP_LOG_WARN;
174
175 if (strcasecmp(strl, "ERR") == 0)
176 return RTPP_LOG_ERR;
177
178 if (strcasecmp(strl, "CRIT") == 0)
179 return RTPP_LOG_CRIT;
180
181 return -1;
182 }
183
184 static int
check_level(struct rtpp_log_inst * rli,int level)185 check_level(struct rtpp_log_inst *rli, int level)
186 {
187
188 return (level <= rli->level);
189 }
190
191 void
rtpp_log_setlevel(struct rtpp_log_inst * rli,int level)192 rtpp_log_setlevel(struct rtpp_log_inst *rli, int level)
193 {
194
195 rli->level = level;
196 }
197
198 static void
ftime(struct rtpp_log_inst * rli,double ltime,char * buf,int buflen)199 ftime(struct rtpp_log_inst *rli, double ltime, char *buf, int buflen)
200 {
201 int hrs, mins, secs, msec;
202
203 if (rli->itime != 0.0) {
204 ltime -= rli->itime;
205 msec = modf(ltime, <ime) * 1000;
206 hrs = (int)(ltime / (60 * 60));
207 ltime -= (hrs * 60 * 60);
208 mins = (int)(ltime / 60);
209 ltime -= (mins * 60);
210 secs = (int)(ltime);
211 snprintf(buf, buflen, "%.2d:%.2d:%.2d.%.3d/", hrs, mins, secs, msec);
212 } else {
213 buf[0] = '\0';
214 }
215 }
216
217 static void
_rtpp_log_lock(void)218 _rtpp_log_lock(void)
219 {
220 unsigned int my_ticket;
221
222 my_ticket = atomic_fetch_add_explicit(&(_log_lock.next_ticket), 1,
223 memory_order_acq_rel);
224 while (atomic_load_explicit(&(_log_lock.now_serving),
225 memory_order_acquire) != my_ticket) {
226 usleep(1);
227 }
228 }
229
230 static void
_rtpp_log_unlock(void)231 _rtpp_log_unlock(void)
232 {
233
234 atomic_fetch_add_explicit(&(_log_lock.now_serving), 1,
235 memory_order_release);
236 }
237
238 void
_rtpp_log_write_va(struct rtpp_log_inst * rli,int level,const char * function,const char * format,va_list ap)239 _rtpp_log_write_va(struct rtpp_log_inst *rli, int level, const char *function,
240 const char *format, va_list ap)
241 {
242 char rtpp_time_buff[32];
243 const char *call_id;
244 #ifdef RTPP_LOG_ADVANCED
245 char rtpp_log_buff[2048];
246 va_list apc;
247 #endif
248
249 if (check_level(rli, level) == 0)
250 return;
251
252 if (rli->call_id != NULL) {
253 call_id = rli->call_id;
254 } else {
255 call_id = CALL_ID_NONE;
256 }
257
258 #ifdef RTPP_LOG_ADVANCED
259 if (syslog_async_opened != 0) {
260 snprintf(rtpp_log_buff, sizeof(rtpp_log_buff), rli->format_sl[0],
261 strlvl(level), call_id, function);
262 va_copy(apc, ap);
263 vsyslog_async(level, rtpp_log_buff, rli->format_sl[1], format, apc);
264 va_end(apc);
265 #if !defined(RTPP_DEBUG)
266 return;
267 #endif
268 }
269 #endif
270
271 ftime(rli, getdtime(), rtpp_time_buff, sizeof(rtpp_time_buff));
272 _rtpp_log_lock();
273 fprintf(stderr, rli->format_se[0], rtpp_time_buff, strlvl(level),
274 call_id, function);
275 vfprintf(stderr, format, ap);
276 fprintf(stderr, rli->format_se[1]);
277 fflush(stderr);
278 _rtpp_log_unlock();
279 }
280
281 void
_rtpp_log_write(struct rtpp_log_inst * rli,int level,const char * function,const char * format,...)282 _rtpp_log_write(struct rtpp_log_inst *rli, int level, const char *function, const char *format, ...)
283 {
284 va_list ap;
285
286 va_start(ap, format);
287 _rtpp_log_write_va(rli, level, function, format, ap);
288 va_end(ap);
289 }
290
291 void
_rtpp_log_ewrite_va(struct rtpp_log_inst * rli,int level,const char * function,const char * format,va_list ap)292 _rtpp_log_ewrite_va(struct rtpp_log_inst *rli, int level, const char *function,
293 const char *format, va_list ap)
294 {
295 char rtpp_time_buff[32];
296 const char *call_id;
297 #ifdef RTPP_LOG_ADVANCED
298 char rtpp_log_buff[2048];
299 va_list apc;
300 char *post;
301 #endif
302
303 if (check_level(rli, level) == 0)
304 return;
305
306 if (rli->call_id != NULL) {
307 call_id = rli->call_id;
308 } else {
309 call_id = CALL_ID_NONE;
310 }
311
312 #ifdef RTPP_LOG_ADVANCED
313 if (syslog_async_opened != 0) {
314 int nch, m;
315
316 m = sizeof(rtpp_log_buff);
317 nch = snprintf(rtpp_log_buff, m, rli->eformat_sl[0],
318 strlvl(level), call_id, function);
319 nch += 1;
320 post = " TRUNCATED! ";
321 if (nch < m) {
322 post = rtpp_log_buff + nch;
323 snprintf(post, m - nch, rli->eformat_sl[1],
324 strerror(errno), errno);
325 }
326 va_copy(apc, ap);
327 vsyslog_async(level, rtpp_log_buff, post, format, apc);
328 va_end(apc);
329 #if !defined(RTPP_DEBUG)
330 return;
331 #endif
332 }
333 #endif
334 ftime(rli, getdtime(), rtpp_time_buff, sizeof(rtpp_time_buff));
335 _rtpp_log_lock();
336 fprintf(stderr, rli->eformat_se[0], rtpp_time_buff, strlvl(level), call_id,
337 function);
338 vfprintf(stderr, format, ap);
339 fprintf(stderr, rli->eformat_se[1], strerror(errno), errno);
340 fflush(stderr);
341 _rtpp_log_unlock();
342 }
343
344 void
_rtpp_log_ewrite(struct rtpp_log_inst * rli,int level,const char * function,const char * format,...)345 _rtpp_log_ewrite(struct rtpp_log_inst *rli, int level, const char *function, const char *format, ...)
346 {
347 va_list ap;
348
349 va_start(ap, format);
350 _rtpp_log_ewrite_va(rli, level, function, format, ap);
351 va_end(ap);
352 }
353
354 static struct {
355 const char *str_fac;
356 int int_fac;
357 } str2fac[] = {
358 {"LOG_AUTH", LOG_AUTH},
359 {"LOG_CRON", LOG_CRON},
360 {"LOG_DAEMON", LOG_DAEMON},
361 {"LOG_KERN", LOG_KERN},
362 {"LOG_LOCAL0", LOG_LOCAL0},
363 {"LOG_LOCAL1", LOG_LOCAL1},
364 {"LOG_LOCAL2", LOG_LOCAL2},
365 {"LOG_LOCAL3", LOG_LOCAL3},
366 {"LOG_LOCAL4", LOG_LOCAL4},
367 {"LOG_LOCAL5", LOG_LOCAL5},
368 {"LOG_LOCAL6", LOG_LOCAL6},
369 {"LOG_LOCAL7", LOG_LOCAL7},
370 {"LOG_LPR", LOG_LPR},
371 {"LOG_MAIL", LOG_MAIL},
372 {"LOG_NEWS", LOG_NEWS},
373 {"LOG_USER", LOG_USER},
374 {"LOG_UUCP", LOG_UUCP},
375 #if !defined(__solaris__) && !defined(__sun) && !defined(__svr4__)
376 {"LOG_AUTHPRIV", LOG_AUTHPRIV},
377 {"LOG_FTP", LOG_FTP},
378 {"LOG_SYSLOG", LOG_SYSLOG},
379 #endif
380 {NULL, 0}
381 };
382
383 int
rtpp_log_str2fac(const char * s)384 rtpp_log_str2fac(const char *s)
385 {
386 int i;
387
388 for (i=0; str2fac[i].str_fac != NULL; i++) {
389 if (strcasecmp(s, str2fac[i].str_fac) == 0 || \
390 strcasecmp(s, str2fac[i].str_fac + 4) == 0)
391 return str2fac[i].int_fac;
392 }
393 return -1;
394 }
395