| /* |
| * Copyright (C) 2008-2009 Andrej Stepanchuk |
| * Copyright (C) 2009-2010 Howard Chu |
| * |
| * This file is part of librtmp. |
| * |
| * librtmp is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU Lesser General Public License as |
| * published by the Free Software Foundation; either version 2.1, |
| * or (at your option) any later version. |
| * |
| * librtmp is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public License |
| * along with librtmp see the file COPYING. If not, write to |
| * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
| * http://www.gnu.org/copyleft/lgpl.html |
| */ |
| |
| #include <stdio.h> |
| #include <stdarg.h> |
| #include <string.h> |
| #include <assert.h> |
| #include <ctype.h> |
| |
| #include "rtmp_sys.h" |
| #include "log.h" |
| |
| #define MAX_PRINT_LEN 2048 |
| |
| RTMP_LogLevel RTMP_debuglevel = RTMP_LOGERROR; |
| |
| static int neednl; |
| |
| static FILE *fmsg; |
| |
| static RTMP_LogCallback rtmp_log_default, *cb = rtmp_log_default; |
| |
| static const char *levels[] = { |
| "CRIT", "ERROR", "WARNING", "INFO", |
| "DEBUG", "DEBUG2" |
| }; |
| |
| static void |
| rtmp_log_default (int level, const char *format, va_list vl) |
| { |
| char str[MAX_PRINT_LEN] = ""; |
| |
| vsnprintf (str, MAX_PRINT_LEN - 1, format, vl); |
| |
| /* Filter out 'no-name' */ |
| if (RTMP_debuglevel < RTMP_LOGALL && strstr (str, "no-name") != NULL) |
| return; |
| |
| if (!fmsg) |
| fmsg = stderr; |
| |
| if (level <= RTMP_debuglevel) { |
| if (neednl) { |
| putc ('\n', fmsg); |
| neednl = 0; |
| } |
| fprintf (fmsg, "%s: %s\n", levels[level], str); |
| #ifdef _DEBUG |
| fflush (fmsg); |
| #endif |
| } |
| } |
| |
| void |
| RTMP_LogSetOutput (FILE * file) |
| { |
| fmsg = file; |
| } |
| |
| void |
| RTMP_LogSetLevel (RTMP_LogLevel level) |
| { |
| RTMP_debuglevel = level; |
| } |
| |
| void |
| RTMP_LogSetCallback (RTMP_LogCallback * cbp) |
| { |
| cb = cbp; |
| } |
| |
| RTMP_LogLevel |
| RTMP_LogGetLevel (void) |
| { |
| return RTMP_debuglevel; |
| } |
| |
| void |
| RTMP_Log (int level, const char *format, ...) |
| { |
| va_list args; |
| va_start (args, format); |
| cb (level, format, args); |
| va_end (args); |
| } |
| |
| static const char hexdig[] = "0123456789abcdef"; |
| |
| void |
| RTMP_LogHex (int level, const uint8_t * data, unsigned long len) |
| { |
| unsigned long i; |
| char line[50], *ptr; |
| |
| if (level > RTMP_debuglevel) |
| return; |
| |
| ptr = line; |
| |
| for (i = 0; i < len; i++) { |
| *ptr++ = hexdig[0x0f & (data[i] >> 4)]; |
| *ptr++ = hexdig[0x0f & data[i]]; |
| if ((i & 0x0f) == 0x0f) { |
| *ptr = '\0'; |
| ptr = line; |
| RTMP_Log (level, "%s", line); |
| } else { |
| *ptr++ = ' '; |
| } |
| } |
| if (i & 0x0f) { |
| *ptr = '\0'; |
| RTMP_Log (level, "%s", line); |
| } |
| } |
| |
| void |
| RTMP_LogHexString (int level, const uint8_t * data, unsigned long len) |
| { |
| #define BP_OFFSET 9 |
| #define BP_GRAPH 60 |
| #define BP_LEN 80 |
| char line[BP_LEN]; |
| unsigned long i; |
| |
| if (!data || level > RTMP_debuglevel) |
| return; |
| |
| /* in case len is zero */ |
| line[0] = '\0'; |
| |
| for (i = 0; i < len; i++) { |
| int n = i % 16; |
| unsigned off; |
| |
| if (!n) { |
| if (i) |
| RTMP_Log (level, "%s", line); |
| memset (line, ' ', sizeof (line) - 2); |
| line[sizeof (line) - 2] = '\0'; |
| |
| off = i % 0x0ffffU; |
| |
| line[2] = hexdig[0x0f & (off >> 12)]; |
| line[3] = hexdig[0x0f & (off >> 8)]; |
| line[4] = hexdig[0x0f & (off >> 4)]; |
| line[5] = hexdig[0x0f & off]; |
| line[6] = ':'; |
| } |
| |
| off = BP_OFFSET + n * 3 + ((n >= 8) ? 1 : 0); |
| line[off] = hexdig[0x0f & (data[i] >> 4)]; |
| line[off + 1] = hexdig[0x0f & data[i]]; |
| |
| off = BP_GRAPH + n + ((n >= 8) ? 1 : 0); |
| |
| if (isprint (data[i])) { |
| line[BP_GRAPH + n] = data[i]; |
| } else { |
| line[BP_GRAPH + n] = '.'; |
| } |
| } |
| |
| RTMP_Log (level, "%s", line); |
| } |
| |
| /* These should only be used by apps, never by the library itself */ |
| void |
| RTMP_LogPrintf (const char *format, ...) |
| { |
| char str[MAX_PRINT_LEN] = ""; |
| int len; |
| va_list args; |
| va_start (args, format); |
| len = vsnprintf (str, MAX_PRINT_LEN - 1, format, args); |
| va_end (args); |
| |
| if (RTMP_debuglevel == RTMP_LOGCRIT) |
| return; |
| |
| if (!fmsg) |
| fmsg = stderr; |
| |
| if (neednl) { |
| putc ('\n', fmsg); |
| neednl = 0; |
| } |
| |
| if (len > MAX_PRINT_LEN - 1) |
| len = MAX_PRINT_LEN - 1; |
| fprintf (fmsg, "%s", str); |
| if (str[len - 1] == '\n') |
| fflush (fmsg); |
| } |
| |
| void |
| RTMP_LogStatus (const char *format, ...) |
| { |
| char str[MAX_PRINT_LEN] = ""; |
| va_list args; |
| va_start (args, format); |
| vsnprintf (str, MAX_PRINT_LEN - 1, format, args); |
| va_end (args); |
| |
| if (RTMP_debuglevel == RTMP_LOGCRIT) |
| return; |
| |
| if (!fmsg) |
| fmsg = stderr; |
| |
| fprintf (fmsg, "%s", str); |
| fflush (fmsg); |
| neednl = 1; |
| } |