Revert "Revert "and added files""
[bcm963xx.git] / userapps / opensource / siproxd / src / log.c
1 /*
2     Copyright (C) 2002-2005  Thomas Ries <tries@gmx.net>
3
4     This file is part of Siproxd.
5     
6     Siproxd is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10     
11     Siproxd is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15     
16     You should have received a copy of the GNU General Public License
17     along with Siproxd; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
19 */
20
21
22 #include "config.h"
23 #include "log.h"
24
25 #include <pthread.h>
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <time.h>
31 #include <syslog.h>
32
33 #include <errno.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39
40 #include <signal.h>
41
42 static char const ident[]="$Id: log.c,v 1.18 2005/01/08 10:41:46 hb9xar Exp $";
43
44 /* module local variables */
45 static int log_to_stderr=0;
46 static int debug_pattern=0;
47
48 static int debug_listen_port=0;
49 static int debug_listen_fd=0;
50 static int debug_fd=0;
51 static char outbuf[512];
52 /*
53  * What shall I log to syslog?
54  *   0 - DEBUGs, INFOs, WARNINGs and ERRORs
55  *   1 - INFOs, WARNINGs and ERRORs (this is the default)
56  *   2 - WARNINGs and ERRORs
57  *   3 - only ERRORs
58  *   4 - absolutely nothing
59  */
60 static int silence_level=1;
61
62 /*
63  * Mutex for threat synchronization when writing log data
64  *
65  * use a 'fast' mutex for synchronizing - as these are portable... 
66  */
67 static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
68
69 void log_set_pattern(int pattern) {
70    debug_pattern=pattern;
71    return;
72 }
73
74 int  log_get_pattern(void) {
75    return debug_pattern;
76 }
77
78 void log_set_stderr(int tostdout) {
79    log_to_stderr=tostdout;
80    return;
81 }
82
83 void log_set_silence(int level) {
84    silence_level=level;
85    return;
86 }
87
88 /*
89  * TCP logging
90  */
91 void log_set_listen_port(int port){
92    debug_listen_port = port;
93    log_tcp_listen();
94    return;
95 }
96
97 void log_tcp_listen(void) {
98    struct sockaddr_in my_addr;
99    int sts, on=1;
100    int flags;
101
102    /* disabled in configuration? */
103    if (debug_listen_port == 0) {
104       debug_listen_fd=-1;
105       return;
106    }
107
108    /* ignore SIGPIPE of lost TCP connection */
109    signal (SIGPIPE, SIG_IGN);
110
111    memset(&my_addr, 0, sizeof(my_addr));
112    my_addr.sin_family = AF_INET;
113    my_addr.sin_port = htons(debug_listen_port);
114
115    debug_listen_fd=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
116    INFO("DEBUG listener on TCP port %i",debug_listen_port);
117    if (debug_listen_fd < 0) {
118       ERROR("socket returned error [%i:%s]",errno, strerror(errno));
119       return;
120    }
121
122    if (setsockopt(debug_listen_fd, SOL_SOCKET, SO_REUSEADDR, &on , sizeof(on)) < 0) {
123       ERROR("socket returned error [%i:%s]",errno, strerror(errno));
124       return;
125    }
126
127
128    sts=bind(debug_listen_fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
129    if (sts != 0) {
130       ERROR("bind returned error [%i:%s]",errno, strerror(errno));
131       close(debug_listen_fd);
132       debug_listen_fd=-1;
133       return;
134    }
135
136    /* set non-blocking */
137    flags = fcntl(debug_listen_fd, F_GETFL);
138    if (flags < 0) {
139       ERROR("fcntl returned error [%i:%s]",errno, strerror(errno));
140       close(debug_listen_fd);
141       debug_listen_fd=-1;
142       return;
143    }
144    if (fcntl(debug_listen_fd, F_SETFL, (long) flags | O_NONBLOCK) < 0) {
145       ERROR("fcntl returned error [%i:%s]",errno, strerror(errno));
146       close(debug_listen_fd);
147       debug_listen_fd=-1;
148       return;
149    }
150
151    listen (debug_listen_fd, 1);
152    return;
153 }
154
155 void log_tcp_connect(void) {
156    int sts;
157    fd_set fdset;
158    struct timeval timeout;
159    int tmpfd;
160
161    if (debug_listen_fd <= 0) return;
162
163    timeout.tv_sec=0;
164    timeout.tv_usec=0;
165
166    FD_ZERO(&fdset);
167    FD_SET (debug_listen_fd, &fdset);
168
169    sts=select(debug_listen_fd+1, &fdset, NULL, NULL, &timeout);
170    if (sts > 0) {
171       if (debug_fd != 0) {
172          tmpfd=accept(debug_listen_fd, NULL, NULL);
173          close(tmpfd);
174          INFO("Rejected DEBUG TCP connection");
175       } else {
176          debug_fd=accept(debug_listen_fd, NULL, NULL);
177          INFO("Accepted DEBUG TCP connection [fd=%i]", debug_fd);
178          INFO(PACKAGE"-"VERSION"-"BUILDSTR" "UNAME);
179       }
180    }
181
182    /* check the TCP connection */
183    if (debug_fd > 0) {
184       timeout.tv_sec=0;
185       timeout.tv_usec=0;
186
187       FD_ZERO(&fdset);
188       FD_SET (debug_fd, &fdset);
189
190       sts=select(debug_fd+1, &fdset, NULL, NULL, &timeout);
191       if (sts > 0) {
192          char buf[32];
193          sts = recv(debug_fd, buf, sizeof(buf), 0);
194          /* got disconnected? */
195          if (sts == 0) {
196             close(debug_fd);
197             INFO("Disconnected DEBUG TCP connection [fd=%i]", debug_fd);
198             debug_fd=0;
199          }
200       }
201    }
202    return;
203 }
204
205
206 /* for all the LOGGING routines:
207    They should figure out if we are running as a daemon, then write
208    their stuff to syslog or something like that
209 */
210
211
212 void log_debug(int class, char *file, int line, const char *format, ...) {
213    va_list ap;
214    time_t t;
215    struct tm *tim;
216    char string[128];
217
218    if ((debug_pattern & class) == 0) return;
219
220    va_start(ap, format);
221
222    pthread_mutex_lock(&log_mutex);
223    /*
224     * DEBUG output is either STDOUT or SYSLOG, but not both
225     */
226    if (log_to_stderr) {
227       /* not running as daemon - log to STDERR */
228       time(&t);
229       tim=localtime(&t);
230       fprintf(stderr,"%2.2i:%2.2i:%2.2i %s:%i ", tim->tm_hour,
231                       tim->tm_min, tim->tm_sec, file, line);
232       vfprintf(stderr, format, ap);
233       fprintf(stderr,"\n");
234       fflush(stderr);
235    } else if (silence_level < 1) {
236       /* running as daemon - log via SYSLOG facility */
237       vsnprintf(string, sizeof(string), format, ap);
238       syslog(LOG_USER|LOG_DEBUG, "%s:%i %s", file, line, string);
239    }
240    /*
241     * Log to TCP
242     */
243    if (debug_fd > 0) {
244       /* log to TCP socket */
245       time(&t);
246       tim=localtime(&t);
247       snprintf(outbuf, sizeof(outbuf) ,"%2.2i:%2.2i:%2.2i %s:%i ",
248                        tim->tm_hour, tim->tm_min, tim->tm_sec, file, line);
249       write(debug_fd, outbuf, strlen(outbuf));
250       vsnprintf(outbuf, sizeof(outbuf) , format, ap);
251       write(debug_fd, outbuf, strlen(outbuf));
252       snprintf(outbuf, sizeof(outbuf) ,"\n");
253       write(debug_fd, outbuf, strlen(outbuf));
254    }
255    pthread_mutex_unlock(&log_mutex);
256
257    va_end(ap);
258    return;
259
260 }
261
262
263 void log_error(char *file, int line, const char *format, ...) {
264    va_list ap;
265    time_t t;
266    struct tm *tim;
267    char string[128];
268
269    va_start(ap, format);
270
271    pthread_mutex_lock(&log_mutex);
272    /*
273     * INFO, WARN, ERROR output is always to syslog and if not daemonized
274     * st STDOUT as well.
275     */
276    if (log_to_stderr) {
277       /* not running as daemon - log to STDERR */
278       time(&t);
279       tim=localtime(&t);
280       fprintf(stderr,"%2.2i:%2.2i:%2.2i ERROR:%s:%i ",tim->tm_hour,
281                       tim->tm_min, tim->tm_sec, file, line);
282       vfprintf(stderr, format, ap);
283       fprintf(stderr,"\n");
284       fflush(stderr);
285    }
286    if (silence_level < 4) {
287       /* running as daemon - log via SYSLOG facility */
288       vsnprintf(string, sizeof(string), format, ap);
289       syslog(LOG_USER|LOG_WARNING, "%s:%i ERROR:%s", file, line, string);
290    }
291    /*
292     * Log to TCP
293     */
294    if (debug_fd > 0) {
295       /* log to TCP socket */
296       time(&t);
297       tim=localtime(&t);
298       snprintf(outbuf, sizeof(outbuf) ,"%2.2i:%2.2i:%2.2i ERROR:%s:%i ",
299                        tim->tm_hour, tim->tm_min, tim->tm_sec, file, line);
300       write(debug_fd, outbuf, strlen(outbuf));
301       vsnprintf(outbuf, sizeof(outbuf) , format, ap);
302       write(debug_fd, outbuf, strlen(outbuf));
303       snprintf(outbuf, sizeof(outbuf) ,"\n");
304       write(debug_fd, outbuf, strlen(outbuf));
305    }
306    pthread_mutex_unlock(&log_mutex);
307
308    va_end(ap);
309    return;
310
311 }
312
313
314 void log_warn(char *file, int line, const char *format, ...) {
315    va_list ap;
316    time_t t;
317    struct tm *tim;
318    char string[128];
319
320    va_start(ap, format);
321
322    pthread_mutex_lock(&log_mutex);
323    /*
324     * INFO, WARN, ERROR output is always to syslog and if not daemonized
325     * st STDOUT as well.
326     */
327    if (log_to_stderr) {
328       /* not running as daemon - log to STDERR */
329       time(&t);
330       tim=localtime(&t);
331       fprintf(stderr,"%2.2i:%2.2i:%2.2i WARNING:%s:%i ",tim->tm_hour,
332                       tim->tm_min, tim->tm_sec,file,line);
333       vfprintf(stderr, format, ap);
334       fprintf(stderr,"\n");
335       fflush(stderr);
336    }
337    if (silence_level < 3) {
338       /* running as daemon - log via SYSLOG facility */
339       vsnprintf(string, sizeof(string), format, ap);
340       syslog(LOG_USER|LOG_NOTICE, "%s:%i WARNING:%s", file, line, string);
341    }
342    /*
343     * Log to TCP
344     */
345    if (debug_fd > 0) {
346       /* log to TCP socket */
347       time(&t);
348       tim=localtime(&t);
349       snprintf(outbuf, sizeof(outbuf) ,"%2.2i:%2.2i:%2.2i WARNING:%s:%i ",
350                        tim->tm_hour, tim->tm_min, tim->tm_sec, file, line);
351       write(debug_fd, outbuf, strlen(outbuf));
352       vsnprintf(outbuf, sizeof(outbuf) , format, ap);
353       write(debug_fd, outbuf, strlen(outbuf));
354       snprintf(outbuf, sizeof(outbuf) ,"\n");
355       write(debug_fd, outbuf, strlen(outbuf));
356    }
357    pthread_mutex_unlock(&log_mutex);
358    
359    va_end(ap);
360    return;
361
362 }
363
364
365 void log_info(char *file, int line, const char *format, ...) {
366    va_list ap;
367    time_t t;
368    struct tm *tim;
369    char string[128];
370
371    va_start(ap, format);
372
373    pthread_mutex_lock(&log_mutex);
374    /*
375     * INFO, WARN, ERROR output is always to syslog and if not daemonized
376     * st STDOUT as well.
377     */
378    if (log_to_stderr) {
379       /* not running as daemon - log to STDERR */
380       time(&t);
381       tim=localtime(&t);
382       fprintf(stderr,"%2.2i:%2.2i:%2.2i INFO:%s:%i ",tim->tm_hour,
383                       tim->tm_min, tim->tm_sec,file,line);
384       vfprintf(stderr, format, ap);
385       fprintf(stderr,"\n");
386       fflush(stderr);
387    }
388    if (silence_level < 2) {
389       /* running as daemon - log via SYSLOG facility */
390       vsnprintf(string, sizeof(string), format, ap);
391       syslog(LOG_USER|LOG_NOTICE, "%s:%i INFO:%s", file, line, string);
392    }
393    /*
394     * Log to TCP
395     */
396    if (debug_fd > 0) {
397       /* log to TCP socket */
398       time(&t);
399       tim=localtime(&t);
400       snprintf(outbuf, sizeof(outbuf) ,"%2.2i:%2.2i:%2.2i INFO:%s:%i ",
401                        tim->tm_hour, tim->tm_min, tim->tm_sec, file, line);
402       write(debug_fd, outbuf, strlen(outbuf));
403       vsnprintf(outbuf, sizeof(outbuf) , format, ap);
404       write(debug_fd, outbuf, strlen(outbuf));
405       snprintf(outbuf, sizeof(outbuf) ,"\n");
406       write(debug_fd, outbuf, strlen(outbuf));
407    }
408    pthread_mutex_unlock(&log_mutex);
409    
410    va_end(ap);
411    return;
412
413 }
414
415
416 void log_dump_buffer(int class, char *file, int line,
417                      char *buffer, int length) {
418    int i, j;
419    char tmp[8], tmplin1[80], tmplin2[80];
420
421    if ((debug_pattern & class) == 0) return;
422    if ((!log_to_stderr) && (debug_fd <= 0)) return;
423
424    pthread_mutex_lock(&log_mutex);
425    if (log_to_stderr) fprintf(stderr,  "---BUFFER DUMP follows---\n");
426    if (debug_fd > 0) {
427       snprintf(outbuf, sizeof(outbuf) ,"---BUFFER DUMP follows---\n");
428       write(debug_fd, outbuf, strlen(outbuf));
429    }
430
431    for (i=0; i<length; i+=16) {
432       strcpy(tmplin1,"");
433       strcpy(tmplin2,"");
434       for (j=0;(j<16) && (i+j)<length ;j++) {
435          sprintf(tmp,"%2.2x ",(unsigned char)buffer[i+j]);
436          strcat(tmplin1, tmp);
437          sprintf(tmp, "%c",(isprint((int)buffer[i+j]))? buffer[i+j]: '.');
438          strcat(tmplin2, tmp);
439       }
440       if (log_to_stderr) {
441          fprintf(stderr, "  %-47.47s %-16.16s\n",tmplin1, tmplin2);
442       }
443       if (debug_fd > 0) {
444          snprintf(outbuf, sizeof(outbuf) ,"  %-47.47s %-16.16s\n",
445                   tmplin1, tmplin2);
446          write(debug_fd, outbuf, strlen(outbuf));
447       }
448    }
449
450    if (log_to_stderr) {
451       fprintf(stderr,"\n---end of BUFFER DUMP---\n");
452       fflush(stderr);
453    }
454    if (debug_fd > 0) {
455       snprintf(outbuf, sizeof(outbuf) ,"---end of BUFFER DUMP---\n");
456       write(debug_fd, outbuf, strlen(outbuf));
457    }
458    pthread_mutex_unlock(&log_mutex);
459
460    return;
461 }
462