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