1 /*
2 * Copyright (C) 2008-2009 Andrej Stepanchuk
3 * Copyright (C) 2009-2010 Howard Chu
4 *
5 * This file is part of librtmp.
6 *
7 * librtmp is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1,
10 * or (at your option) any later version.
11 *
12 * librtmp is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with librtmp see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 * http://www.gnu.org/copyleft/lgpl.html
22 */
23
24 #include <stdio.h>
25 #include <stdarg.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <ctype.h>
29
30 #include "rtmp_sys.h"
31 #include "log.h"
32
33 #define MAX_PRINT_LEN 2048
34
35 RTMP_LogLevel RTMP_debuglevel = RTMP_LOGERROR;
36
37 static int neednl;
38
39 static FILE *fmsg;
40
41 static RTMP_LogCallback rtmp_log_default, *cb = rtmp_log_default;
42
43 static const char *levels[] = {
44 "CRIT", "ERROR", "WARNING", "INFO",
45 "DEBUG", "DEBUG2"
46 };
47
rtmp_log_default(int level,const char * format,va_list vl)48 static void rtmp_log_default(int level, const char *format, va_list vl)
49 {
50 char str[MAX_PRINT_LEN]="";
51
52 vsnprintf(str, MAX_PRINT_LEN-1, format, vl);
53
54 /* Filter out 'no-name' */
55 if ( RTMP_debuglevel<RTMP_LOGALL && strstr(str, "no-name" ) != NULL )
56 return;
57
58 if ( !fmsg ) fmsg = stderr;
59
60 if ( level <= RTMP_debuglevel ) {
61 if (neednl) {
62 putc('\n', fmsg);
63 neednl = 0;
64 }
65 fprintf(fmsg, "%s: %s\n", levels[level], str);
66 #ifdef _DEBUG
67 fflush(fmsg);
68 #endif
69 }
70 }
71
RTMP_LogSetOutput(FILE * file)72 void RTMP_LogSetOutput(FILE *file)
73 {
74 fmsg = file;
75 }
76
RTMP_LogSetLevel(RTMP_LogLevel level)77 void RTMP_LogSetLevel(RTMP_LogLevel level)
78 {
79 RTMP_debuglevel = level;
80 }
81
RTMP_LogSetCallback(RTMP_LogCallback * cbp)82 void RTMP_LogSetCallback(RTMP_LogCallback *cbp)
83 {
84 cb = cbp;
85 }
86
RTMP_LogGetLevel()87 RTMP_LogLevel RTMP_LogGetLevel()
88 {
89 return RTMP_debuglevel;
90 }
91
RTMP_Log(int level,const char * format,...)92 void RTMP_Log(int level, const char *format, ...)
93 {
94 va_list args;
95
96 if ( level > RTMP_debuglevel )
97 return;
98
99 va_start(args, format);
100 cb(level, format, args);
101 va_end(args);
102 }
103
104 static const char hexdig[] = "0123456789abcdef";
105
RTMP_LogHex(int level,const uint8_t * data,unsigned long len)106 void RTMP_LogHex(int level, const uint8_t *data, unsigned long len)
107 {
108 unsigned long i;
109 char line[50], *ptr;
110
111 if ( level > RTMP_debuglevel )
112 return;
113
114 ptr = line;
115
116 for(i=0; i<len; i++) {
117 *ptr++ = hexdig[0x0f & (data[i] >> 4)];
118 *ptr++ = hexdig[0x0f & data[i]];
119 if ((i & 0x0f) == 0x0f) {
120 *ptr = '\0';
121 ptr = line;
122 RTMP_Log(level, "%s", line);
123 } else {
124 *ptr++ = ' ';
125 }
126 }
127 if (i & 0x0f) {
128 *ptr = '\0';
129 RTMP_Log(level, "%s", line);
130 }
131 }
132
RTMP_LogHexString(int level,const uint8_t * data,unsigned long len)133 void RTMP_LogHexString(int level, const uint8_t *data, unsigned long len)
134 {
135 #define BP_OFFSET 9
136 #define BP_GRAPH 60
137 #define BP_LEN 80
138 char line[BP_LEN];
139 unsigned long i;
140
141 if ( !data || level > RTMP_debuglevel )
142 return;
143
144 /* in case len is zero */
145 line[0] = '\0';
146
147 for ( i = 0 ; i < len ; i++ ) {
148 int n = i % 16;
149 unsigned off;
150
151 if( !n ) {
152 if( i ) RTMP_Log( level, "%s", line );
153 memset( line, ' ', sizeof(line)-2 );
154 line[sizeof(line)-2] = '\0';
155
156 off = i % 0x0ffffU;
157
158 line[2] = hexdig[0x0f & (off >> 12)];
159 line[3] = hexdig[0x0f & (off >> 8)];
160 line[4] = hexdig[0x0f & (off >> 4)];
161 line[5] = hexdig[0x0f & off];
162 line[6] = ':';
163 }
164
165 off = BP_OFFSET + n*3 + ((n >= 8)?1:0);
166 line[off] = hexdig[0x0f & ( data[i] >> 4 )];
167 line[off+1] = hexdig[0x0f & data[i]];
168
169 off = BP_GRAPH + n + ((n >= 8)?1:0);
170
171 if ( isprint( data[i] )) {
172 line[BP_GRAPH + n] = data[i];
173 } else {
174 line[BP_GRAPH + n] = '.';
175 }
176 }
177
178 RTMP_Log( level, "%s", line );
179 }
180
181 /* These should only be used by apps, never by the library itself */
RTMP_LogPrintf(const char * format,...)182 void RTMP_LogPrintf(const char *format, ...)
183 {
184 char str[MAX_PRINT_LEN]="";
185 int len;
186 va_list args;
187 va_start(args, format);
188 len = vsnprintf(str, MAX_PRINT_LEN-1, format, args);
189 va_end(args);
190
191 if ( RTMP_debuglevel==RTMP_LOGCRIT )
192 return;
193
194 if ( !fmsg ) fmsg = stderr;
195
196 if (neednl) {
197 putc('\n', fmsg);
198 neednl = 0;
199 }
200
201 if (len > MAX_PRINT_LEN-1)
202 len = MAX_PRINT_LEN-1;
203 fprintf(fmsg, "%s", str);
204 if (str[len-1] == '\n')
205 fflush(fmsg);
206 }
207
RTMP_LogStatus(const char * format,...)208 void RTMP_LogStatus(const char *format, ...)
209 {
210 char str[MAX_PRINT_LEN]="";
211 va_list args;
212 va_start(args, format);
213 vsnprintf(str, MAX_PRINT_LEN-1, format, args);
214 va_end(args);
215
216 if ( RTMP_debuglevel==RTMP_LOGCRIT )
217 return;
218
219 if ( !fmsg ) fmsg = stderr;
220
221 fprintf(fmsg, "%s", str);
222 fflush(fmsg);
223 neednl = 1;
224 }
225