Navigation


source: freeDiameter/libfdproto/log.c

Last change on this file was 1554:566bb46cc73f, checked in by Sebastien Decugis <sdecugis@freediameter.net>, 5 months ago

Updated copyright information

File size: 9.8 KB
Line 
1/*********************************************************************************************************
2* Software License Agreement (BSD License)                                                               *
3* Author: Sebastien Decugis <sdecugis@freediameter.net>                                                  *
4*                                                                                                        *
5* Copyright (c) 2020, WIDE Project and NICT                                                              *
6* All rights reserved.                                                                                   *
7*                                                                                                        *
8* Redistribution and use of this software in source and binary forms, with or without modification, are  *
9* permitted provided that the following conditions are met:                                              *
10*                                                                                                        *
11* * Redistributions of source code must retain the above                                                 *
12*   copyright notice, this list of conditions and the                                                    *
13*   following disclaimer.                                                                                *
14*                                                                                                        *
15* * Redistributions in binary form must reproduce the above                                              *
16*   copyright notice, this list of conditions and the                                                    *
17*   following disclaimer in the documentation and/or other                                               *
18*   materials provided with the distribution.                                                            *
19*                                                                                                        *
20* * Neither the name of the WIDE Project or NICT nor the                                                 *
21*   names of its contributors may be used to endorse or                                                  *
22*   promote products derived from this software without                                                  *
23*   specific prior written permission of WIDE Project and                                                *
24*   NICT.                                                                                                *
25*                                                                                                        *
26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT     *
30* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS    *
31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
33* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                                             *
34*********************************************************************************************************/
35
36#include "fdproto-internal.h"
37
38#include <stdarg.h>
39
40pthread_mutex_t fd_log_lock = PTHREAD_MUTEX_INITIALIZER;
41pthread_key_t   fd_log_thname;
42int fd_g_debug_lvl = FD_LOG_NOTICE;
43
44static void fd_internal_logger( int, const char *, va_list );
45static int use_colors = 0; /* 0: not init, 1: yes, 2: no */
46
47/* These may be used to pass specific debug requests via the command-line parameters */
48char * fd_debug_one_function = NULL;
49char * fd_debug_one_file = NULL;
50
51/* Useless function, only to ease setting up a breakpoint in gdb (break fd_breakhere) -- use TRACE_HERE */
52int fd_breaks = 0;
53int fd_breakhere(void) { return ++fd_breaks; }
54
55/* Allow passing of the log and debug information from base stack to extensions */
56void (*fd_logger)( int loglevel, const char * format, va_list args ) = fd_internal_logger;
57
58/* Register an external call back for tracing and debug */
59int fd_log_handler_register( void (*logger)(int loglevel, const char * format, va_list args) )
60{
61        CHECK_PARAMS( logger );
62
63        if ( fd_logger != fd_internal_logger )
64        {
65               return EALREADY; /* only one registration allowed */
66        }
67        else
68        {
69               fd_logger = logger;
70        }
71
72        return 0;
73}
74
75/* Implement a simple reset function here */
76int fd_log_handler_unregister ( void )
77{
78        fd_logger = fd_internal_logger;
79        return 0; /* Successfull in all cases. */
80}
81
82static void fd_cleanup_mutex_silent( void * mutex )
83{
84        (void)pthread_mutex_unlock((pthread_mutex_t *)mutex);
85}
86
87
88static void fd_internal_logger( int printlevel, const char *format, va_list ap )
89{
90    char buf[25];
91
92    /* Do we need to trace this ? */
93    if (printlevel < fd_g_debug_lvl)
94        return;
95
96    /* add timestamp */
97    printf("%s  ", fd_log_time(NULL, buf, sizeof(buf), 
98#if (defined(DEBUG) && defined(DEBUG_WITH_META))
99        1, 1
100#else /* (defined(DEBUG) && defined(DEBUG_WITH_META)) */
101        0, 0
102#endif /* (defined(DEBUG) && defined(DEBUG_WITH_META)) */
103            ));
104    /* Use colors on stdout ? */
105    if (!use_colors) {
106        if (isatty(STDOUT_FILENO))
107                use_colors = 1;
108        else
109                use_colors = 2;
110    }
111   
112    switch(printlevel) {
113            case FD_LOG_ANNOYING:  printf("%s   A   ", (use_colors == 1) ? "\e[0;37m" : ""); break;
114            case FD_LOG_DEBUG:     printf("%s DBG   ", (use_colors == 1) ? "\e[0;37m" : ""); break;
115            case FD_LOG_INFO:      printf("%sINFO   ", (use_colors == 1) ? "\e[1;37m" : ""); break;
116            case FD_LOG_NOTICE:    printf("%sNOTI   ", (use_colors == 1) ? "\e[1;37m" : ""); break;
117            case FD_LOG_ERROR:     printf("%sERROR  ", (use_colors == 1) ? "\e[0;31m" : ""); break;
118            case FD_LOG_FATAL:     printf("%sFATAL! ", (use_colors == 1) ? "\e[0;31m" : ""); break;
119            default:               printf("%s ???   ", (use_colors == 1) ? "\e[0;31m" : "");
120    }
121    vprintf(format, ap);
122    if (use_colors == 1)
123             printf("\e[00m");
124    printf("\n");
125   
126    fflush(stdout);
127}
128
129/* Log a debug message */
130void fd_log ( int loglevel, const char * format, ... )
131{
132        va_list ap;
133       
134        (void)pthread_mutex_lock(&fd_log_lock);
135       
136        pthread_cleanup_push(fd_cleanup_mutex_silent, &fd_log_lock);
137       
138        va_start(ap, format);
139        fd_logger(loglevel, format, ap);
140        va_end(ap);
141
142        pthread_cleanup_pop(0);
143       
144        (void)pthread_mutex_unlock(&fd_log_lock);
145}
146
147/* Log a debug message */
148void fd_log_va ( int loglevel, const char * format, va_list args )
149{
150        (void)pthread_mutex_lock(&fd_log_lock);
151       
152        pthread_cleanup_push(fd_cleanup_mutex_silent, &fd_log_lock);
153        fd_logger(loglevel, format, args);
154        pthread_cleanup_pop(0);
155       
156        (void)pthread_mutex_unlock(&fd_log_lock);
157}
158
159/* Function to set the thread's friendly name */
160void fd_log_threadname ( const char * name )
161{
162        void * val = NULL;
163       
164        TRACE_ENTRY("%p(%s)", name, name?:"/");
165       
166        /* First, check if a value is already assigned to the current thread */
167        val = pthread_getspecific(fd_log_thname);
168        if (TRACE_BOOL(ANNOYING)) {
169                if (val) {
170                        fd_log_debug("(Thread '%s' renamed to '%s')", (char *)val, name?:"(nil)");
171                } else {
172                        fd_log_debug("(Thread %p named '%s')", (void *)pthread_self(), name?:"(nil)");
173                }
174        }
175        if (val != NULL) {
176                free(val);
177        }
178       
179        /* Now create the new string */
180        if (name == NULL) {
181                CHECK_POSIX_DO( pthread_setspecific(fd_log_thname, NULL), /* continue */);
182                return;
183        }
184       
185        CHECK_MALLOC_DO( val = strdup(name), return );
186       
187        CHECK_POSIX_DO( pthread_setspecific(fd_log_thname, val), /* continue */);
188        return;
189}
190
191/* Write time into a buffer */
192char * fd_log_time ( struct timespec * ts, char * buf, size_t len, int incl_date, int incl_ms )
193{
194        int ret;
195        size_t offset = 0;
196        struct timespec tp;
197        struct tm tm;
198       
199        /* Get current time */
200        if (!ts) {
201                ret = clock_gettime(CLOCK_REALTIME, &tp);
202                if (ret != 0) {
203                        snprintf(buf, len, "%s", strerror(ret));
204                        return buf;
205                }
206                ts = &tp;
207        }
208       
209        offset += strftime(buf + offset, len - offset, incl_date?"%D,%T":"%T", localtime_r( &ts->tv_sec , &tm ));
210        if (incl_ms)
211                offset += snprintf(buf + offset, len - offset, ".%6.6ld", ts->tv_nsec / 1000);
212
213        return buf;
214}
215
216
217static size_t sys_mempagesz = 0;
218
219static size_t get_mempagesz(void) {
220        if (!sys_mempagesz) {
221                sys_mempagesz = sysconf(_SC_PAGESIZE); /* We alloc buffer by memory pages for efficiency. This can be readjusted if too memory consuming */
222                if (sys_mempagesz <= 0)
223                        sys_mempagesz = 256; /* default size if above call failed */
224        }
225        return sys_mempagesz;
226}
227
228
229/* Helper function for fd_*_dump. Prints the format string from 'offset' into '*buf', extends if needed. The location of buf can be updated by this function. */
230char * fd_dump_extend(char ** buf, size_t *len, size_t *offset, const char * format, ... )
231{
232        va_list ap;
233        int to_write;
234        size_t o = 0;
235        size_t mempagesz = get_mempagesz();
236       
237        /* we do not TRACE_ENTRY this one on purpose */
238       
239        CHECK_PARAMS_DO(buf && len, return NULL);
240       
241        if (*buf == NULL) {
242                CHECK_MALLOC_DO(*buf = malloc(mempagesz), return NULL);
243                *len = mempagesz;
244        }
245       
246        if (offset)
247                o = *offset;
248       
249        va_start(ap, format);
250        to_write = vsnprintf(*buf + o, *len - o, format, ap);
251        va_end(ap);
252       
253        if (to_write + o >= *len) {
254                /* There was no room in the buffer, we extend and redo */
255                size_t new_len = (((to_write + o) / mempagesz) + 1) * mempagesz;
256                CHECK_MALLOC_DO(*buf = realloc(*buf, new_len), return NULL);
257                *len = new_len;
258               
259                va_start(ap, format);
260                to_write = vsnprintf(*buf + o, *len - o, format, ap);
261                va_end(ap);
262        }
263       
264        if (offset)
265                *offset += to_write;
266       
267        return *buf;
268}
269
270char * fd_dump_extend_hexdump(char ** buf, size_t *len, size_t *offset, uint8_t *data, size_t datalen, size_t trunc, size_t wrap )
271{
272        int truncated = 0;
273        size_t towrite = 0;
274        size_t o = 0;
275        int i;
276        char * p;
277        size_t mempagesz = get_mempagesz();
278#define TRUNK_MARK "[...]"
279
280        CHECK_PARAMS_DO(buf && len && data, return NULL);
281       
282        if (trunc && (datalen > trunc)) {
283                datalen = trunc;
284                truncated = 1;
285        }
286       
287        towrite = datalen * 2;
288       
289        if (wrap)
290                towrite += datalen / wrap; /* add 1 '\n' every wrap byte */
291       
292        if (truncated)
293                towrite += CONSTSTRLEN(TRUNK_MARK);
294       
295       
296        if (offset)
297                o = *offset;
298       
299        if (*buf == NULL) {
300                /* Directly allocate the size we need */
301                *len = (((towrite + o) / mempagesz) + 1 ) * mempagesz;
302                CHECK_MALLOC_DO(*buf = malloc(*len), return NULL);
303        } else if ((towrite + o) >= *len) {
304                /* There is no room in the buffer, we extend and redo */
305                size_t new_len = (((towrite + o) / mempagesz) + 1) * mempagesz;
306                CHECK_MALLOC_DO(*buf = realloc(*buf, new_len), return NULL);
307                *len = new_len;
308        }
309       
310        p = *buf + o;
311        for (i = 0; i < datalen; i++) {
312                sprintf(p, "%02hhX", data[i]);
313                p+=2;
314                if ((wrap) && ((i+1) % wrap == 0)) {
315                        *p++='\n'; *p ='\0'; /* we want to ensure the buffer is always 0-terminated */
316                }
317        }
318       
319        if (truncated)
320                memcpy(p, TRUNK_MARK, CONSTSTRLEN(TRUNK_MARK));
321               
322        if (offset)
323                *offset += towrite;
324       
325        return *buf;
326}
Note: See TracBrowser for help on using the repository browser.