确认qt mingw 730 下openssl自带bug....

master
DESKTOP-4RNDQIC\29019 2020-06-03 00:43:23 +08:00
parent 8dc2bdc307
commit 7b2a2ef120
5 changed files with 7838 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,665 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/lgpl.html
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include "rtmp_sys.h"
#include "log.h"
#include "http.h"
#ifdef CRYPTO
#ifdef USE_POLARSSL
#include <polarssl/sha2.h>
#ifndef SHA256_DIGEST_LENGTH
#define SHA256_DIGEST_LENGTH 32
#endif
#define HMAC_CTX sha2_context
#define HMAC_setup(ctx, key, len) sha2_hmac_starts(&ctx, (unsigned char *)key, len, 0)
#define HMAC_crunch(ctx, buf, len) sha2_hmac_update(&ctx, buf, len)
#define HMAC_finish(ctx, dig, dlen) dlen = SHA256_DIGEST_LENGTH; sha2_hmac_finish(&ctx, dig)
#define HMAC_close(ctx)
#elif defined(USE_GNUTLS)
#include <nettle/hmac.h>
#ifndef SHA256_DIGEST_LENGTH
#define SHA256_DIGEST_LENGTH 32
#endif
#undef HMAC_CTX
#define HMAC_CTX struct hmac_sha256_ctx
#define HMAC_setup(ctx, key, len) hmac_sha256_set_key(&ctx, len, key)
#define HMAC_crunch(ctx, buf, len) hmac_sha256_update(&ctx, len, buf)
#define HMAC_finish(ctx, dig, dlen) dlen = SHA256_DIGEST_LENGTH; hmac_sha256_digest(&ctx, SHA256_DIGEST_LENGTH, dig)
#define HMAC_close(ctx)
#else /* USE_OPENSSL */
#include <openssl/ssl.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/rc4.h>
#define HMAC_setup(ctx, key, len) HMAC_CTX_init(&ctx); HMAC_Init_ex(&ctx, (unsigned char *)key, len, EVP_sha256(), 0)
#define HMAC_crunch(ctx, buf, len) HMAC_Update(&ctx, (unsigned char *)buf, len)
#define HMAC_finish(ctx, dig, dlen) HMAC_Final(&ctx, (unsigned char *)dig, &dlen);
#define HMAC_close(ctx) HMAC_CTX_cleanup(&ctx)
#endif
extern void RTMP_TLS_Init();
extern TLS_CTX RTMP_TLS_ctx;
#include <zlib.h>
#endif /* CRYPTO */
#define AGENT "Mozilla/5.0"
HTTPResult
HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb)
{
char *host, *path;
char *p1, *p2;
char hbuf[256];
int port = 80;
#ifdef CRYPTO
int ssl = 0;
#endif
int hlen, flen = 0;
int rc, i;
int len_known;
HTTPResult ret = HTTPRES_OK;
struct sockaddr_in sa;
RTMPSockBuf sb = {0};
http->status = -1;
memset(&sa, 0, sizeof(struct sockaddr_in));
sa.sin_family = AF_INET;
/* we only handle http here */
if (strncasecmp(url, "http", 4))
return HTTPRES_BAD_REQUEST;
if (url[4] == 's')
{
#ifdef CRYPTO
ssl = 1;
port = 443;
if (!RTMP_TLS_ctx)
RTMP_TLS_Init();
#else
return HTTPRES_BAD_REQUEST;
#endif
}
p1 = strchr(url + 4, ':');
if (!p1 || strncmp(p1, "://", 3))
return HTTPRES_BAD_REQUEST;
host = p1 + 3;
path = strchr(host, '/');
hlen = path - host;
strncpy(hbuf, host, hlen);
hbuf[hlen] = '\0';
host = hbuf;
p1 = strrchr(host, ':');
if (p1)
{
*p1++ = '\0';
port = atoi(p1);
}
sa.sin_addr.s_addr = inet_addr(host);
if (sa.sin_addr.s_addr == INADDR_NONE)
{
struct hostent *hp = gethostbyname(host);
if (!hp || !hp->h_addr)
return HTTPRES_LOST_CONNECTION;
sa.sin_addr = *(struct in_addr *)hp->h_addr;
}
sa.sin_port = htons(port);
sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sb.sb_socket == -1)
return HTTPRES_LOST_CONNECTION;
i =
sprintf(sb.sb_buf,
"GET %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s\r\nReferer: %.*s\r\n",
path, AGENT, host, (int)(path - url + 1), url);
if (http->date[0])
i += sprintf(sb.sb_buf + i, "If-Modified-Since: %s\r\n", http->date);
i += sprintf(sb.sb_buf + i, "\r\n");
if (connect
(sb.sb_socket, (struct sockaddr *)&sa, sizeof(struct sockaddr)) < 0)
{
ret = HTTPRES_LOST_CONNECTION;
goto leave;
}
#ifdef CRYPTO
if (ssl)
{
#ifdef NO_SSL
RTMP_Log(RTMP_LOGERROR, "%s, No SSL/TLS support", __FUNCTION__);
ret = HTTPRES_BAD_REQUEST;
goto leave;
#else
TLS_client(RTMP_TLS_ctx, sb.sb_ssl);
TLS_setfd(sb.sb_ssl, sb.sb_socket);
if (TLS_connect(sb.sb_ssl) < 0)
{
RTMP_Log(RTMP_LOGERROR, "%s, TLS_Connect failed", __FUNCTION__);
ret = HTTPRES_LOST_CONNECTION;
goto leave;
}
#endif
}
#endif
RTMPSockBuf_Send(&sb, sb.sb_buf, i);
/* set timeout */
#define HTTP_TIMEOUT 5
{
SET_RCVTIMEO(tv, HTTP_TIMEOUT);
if (setsockopt
(sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)))
{
RTMP_Log(RTMP_LOGERROR, "%s, Setting socket timeout to %ds failed!",
__FUNCTION__, HTTP_TIMEOUT);
}
}
sb.sb_size = 0;
sb.sb_timedout = FALSE;
if (RTMPSockBuf_Fill(&sb) < 1)
{
ret = HTTPRES_LOST_CONNECTION;
goto leave;
}
if (strncmp(sb.sb_buf, "HTTP/1", 6))
{
ret = HTTPRES_BAD_REQUEST;
goto leave;
}
p1 = strchr(sb.sb_buf, ' ');
rc = atoi(p1 + 1);
http->status = rc;
if (rc >= 300)
{
if (rc == 304)
{
ret = HTTPRES_OK_NOT_MODIFIED;
goto leave;
}
else if (rc == 404)
ret = HTTPRES_NOT_FOUND;
else if (rc >= 500)
ret = HTTPRES_SERVER_ERROR;
else if (rc >= 400)
ret = HTTPRES_BAD_REQUEST;
else
ret = HTTPRES_REDIRECTED;
}
p1 = memchr(sb.sb_buf, '\n', sb.sb_size);
if (!p1)
{
ret = HTTPRES_BAD_REQUEST;
goto leave;
}
sb.sb_start = p1 + 1;
sb.sb_size -= sb.sb_start - sb.sb_buf;
while ((p2 = memchr(sb.sb_start, '\r', sb.sb_size)))
{
if (*sb.sb_start == '\r')
{
sb.sb_start += 2;
sb.sb_size -= 2;
break;
}
else
if (!strncasecmp
(sb.sb_start, "Content-Length: ", sizeof("Content-Length: ") - 1))
{
flen = atoi(sb.sb_start + sizeof("Content-Length: ") - 1);
}
else
if (!strncasecmp
(sb.sb_start, "Last-Modified: ", sizeof("Last-Modified: ") - 1))
{
*p2 = '\0';
strcpy(http->date, sb.sb_start + sizeof("Last-Modified: ") - 1);
}
p2 += 2;
sb.sb_size -= p2 - sb.sb_start;
sb.sb_start = p2;
if (sb.sb_size < 1)
{
if (RTMPSockBuf_Fill(&sb) < 1)
{
ret = HTTPRES_LOST_CONNECTION;
goto leave;
}
}
}
len_known = flen > 0;
while ((!len_known || flen > 0) &&
(sb.sb_size > 0 || RTMPSockBuf_Fill(&sb) > 0))
{
cb(sb.sb_start, 1, sb.sb_size, http->data);
if (len_known)
flen -= sb.sb_size;
http->size += sb.sb_size;
sb.sb_size = 0;
}
if (flen > 0)
ret = HTTPRES_LOST_CONNECTION;
leave:
RTMPSockBuf_Close(&sb);
return ret;
}
#ifdef CRYPTO
#define CHUNK 16384
struct info
{
z_stream *zs;
HMAC_CTX ctx;
int first;
int zlib;
int size;
};
static size_t
swfcrunch(void *ptr, size_t size, size_t nmemb, void *stream)
{
struct info *i = stream;
char *p = ptr;
size_t len = size * nmemb;
if (i->first)
{
i->first = 0;
/* compressed? */
if (!strncmp(p, "CWS", 3))
{
*p = 'F';
i->zlib = 1;
}
HMAC_crunch(i->ctx, (unsigned char *)p, 8);
p += 8;
len -= 8;
i->size = 8;
}
if (i->zlib)
{
unsigned char out[CHUNK];
i->zs->next_in = (unsigned char *)p;
i->zs->avail_in = len;
do
{
i->zs->avail_out = CHUNK;
i->zs->next_out = out;
inflate(i->zs, Z_NO_FLUSH);
len = CHUNK - i->zs->avail_out;
i->size += len;
HMAC_crunch(i->ctx, out, len);
}
while (i->zs->avail_out == 0);
}
else
{
i->size += len;
HMAC_crunch(i->ctx, (unsigned char *)p, len);
}
return size * nmemb;
}
static int tzoff;
static int tzchecked;
#define JAN02_1980 318340800
static const char *monthtab[12] = { "Jan", "Feb", "Mar",
"Apr", "May", "Jun",
"Jul", "Aug", "Sep",
"Oct", "Nov", "Dec"
};
static const char *days[] =
{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
/* Parse an HTTP datestamp into Unix time */
static time_t
make_unix_time(char *s)
{
struct tm time;
int i, ysub = 1900, fmt = 0;
char *month;
char *n;
time_t res;
if (s[3] != ' ')
{
fmt = 1;
if (s[3] != ',')
ysub = 0;
}
for (n = s; *n; ++n)
if (*n == '-' || *n == ':')
*n = ' ';
time.tm_mon = 0;
n = strchr(s, ' ');
if (fmt)
{
/* Day, DD-MMM-YYYY HH:MM:SS GMT */
time.tm_mday = strtol(n + 1, &n, 0);
month = n + 1;
n = strchr(month, ' ');
time.tm_year = strtol(n + 1, &n, 0);
time.tm_hour = strtol(n + 1, &n, 0);
time.tm_min = strtol(n + 1, &n, 0);
time.tm_sec = strtol(n + 1, NULL, 0);
}
else
{
/* Unix ctime() format. Does not conform to HTTP spec. */
/* Day MMM DD HH:MM:SS YYYY */
month = n + 1;
n = strchr(month, ' ');
while (isspace(*n))
n++;
time.tm_mday = strtol(n, &n, 0);
time.tm_hour = strtol(n + 1, &n, 0);
time.tm_min = strtol(n + 1, &n, 0);
time.tm_sec = strtol(n + 1, &n, 0);
time.tm_year = strtol(n + 1, NULL, 0);
}
if (time.tm_year > 100)
time.tm_year -= ysub;
for (i = 0; i < 12; i++)
if (!strncasecmp(month, monthtab[i], 3))
{
time.tm_mon = i;
break;
}
time.tm_isdst = 0; /* daylight saving is never in effect in GMT */
/* this is normally the value of extern int timezone, but some
* braindead C libraries don't provide it.
*/
if (!tzchecked)
{
struct tm *tc;
time_t then = JAN02_1980;
tc = localtime(&then);
tzoff = (12 - tc->tm_hour) * 3600 + tc->tm_min * 60 + tc->tm_sec;
tzchecked = 1;
}
res = mktime(&time);
/* Unfortunately, mktime() assumes the input is in local time,
* not GMT, so we have to correct it here.
*/
if (res != -1)
res += tzoff;
return res;
}
/* Convert a Unix time to a network time string
* Weekday, DD-MMM-YYYY HH:MM:SS GMT
*/
static void
strtime(time_t * t, char *s)
{
struct tm *tm;
tm = gmtime((time_t *) t);
sprintf(s, "%s, %02d %s %d %02d:%02d:%02d GMT",
days[tm->tm_wday], tm->tm_mday, monthtab[tm->tm_mon],
tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec);
}
#define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf))
int
RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash,
int age)
{
FILE *f = NULL;
char *path, date[64], cctim[64];
long pos = 0;
time_t ctim = -1, cnow;
int i, got = 0, ret = 0;
unsigned int hlen;
struct info in = { 0 };
struct HTTP_ctx http = { 0 };
HTTPResult httpres;
z_stream zs = { 0 };
AVal home, hpre;
date[0] = '\0';
#ifdef _WIN32
#ifdef XBMC4XBOX
hpre.av_val = "Q:";
hpre.av_len = 2;
home.av_val = "\\UserData";
#else
hpre.av_val = getenv("HOMEDRIVE");
hpre.av_len = strlen(hpre.av_val);
home.av_val = getenv("HOMEPATH");
#endif
#define DIRSEP "\\"
#else /* !_WIN32 */
hpre.av_val = "";
hpre.av_len = 0;
home.av_val = getenv("HOME");
#define DIRSEP "/"
#endif
if (!home.av_val)
home.av_val = ".";
home.av_len = strlen(home.av_val);
/* SWF hash info is cached in a fixed-format file.
* url: <url of SWF file>
* ctim: HTTP datestamp of when we last checked it.
* date: HTTP datestamp of the SWF's last modification.
* size: SWF size in hex
* hash: SWF hash in hex
*
* These fields must be present in this order. All fields
* besides URL are fixed size.
*/
path = malloc(hpre.av_len + home.av_len + sizeof(DIRSEP ".swfinfo"));
sprintf(path, "%s%s" DIRSEP ".swfinfo", hpre.av_val, home.av_val);
f = fopen(path, "r+");
while (f)
{
char buf[4096], *file, *p;
file = strchr(url, '/');
if (!file)
break;
file += 2;
file = strchr(file, '/');
if (!file)
break;
file++;
hlen = file - url;
p = strrchr(file, '/');
if (p)
file = p;
else
file--;
while (fgets(buf, sizeof(buf), f))
{
char *r1;
got = 0;
if (strncmp(buf, "url: ", 5))
continue;
if (strncmp(buf + 5, url, hlen))
continue;
r1 = strrchr(buf, '/');
i = strlen(r1);
r1[--i] = '\0';
if (strncmp(r1, file, i))
continue;
pos = ftell(f);
while (got < 4 && fgets(buf, sizeof(buf), f))
{
if (!strncmp(buf, "size: ", 6))
{
*size = strtol(buf + 6, NULL, 16);
got++;
}
else if (!strncmp(buf, "hash: ", 6))
{
unsigned char *ptr = hash, *in = (unsigned char *)buf + 6;
int l = strlen((char *)in) - 1;
for (i = 0; i < l; i += 2)
*ptr++ = (HEX2BIN(in[i]) << 4) | HEX2BIN(in[i + 1]);
got++;
}
else if (!strncmp(buf, "date: ", 6))
{
buf[strlen(buf) - 1] = '\0';
strncpy(date, buf + 6, sizeof(date));
got++;
}
else if (!strncmp(buf, "ctim: ", 6))
{
buf[strlen(buf) - 1] = '\0';
ctim = make_unix_time(buf + 6);
got++;
}
else if (!strncmp(buf, "url: ", 5))
break;
}
break;
}
break;
}
cnow = time(NULL);
/* If we got a cache time, see if it's young enough to use directly */
if (age && ctim > 0)
{
ctim = cnow - ctim;
ctim /= 3600 * 24; /* seconds to days */
if (ctim < age) /* ok, it's new enough */
goto out;
}
in.first = 1;
HMAC_setup(in.ctx, "Genuine Adobe Flash Player 001", 30);
inflateInit(&zs);
in.zs = &zs;
http.date = date;
http.data = &in;
httpres = HTTP_get(&http, url, swfcrunch);
inflateEnd(&zs);
if (httpres != HTTPRES_OK && httpres != HTTPRES_OK_NOT_MODIFIED)
{
ret = -1;
if (httpres == HTTPRES_LOST_CONNECTION)
RTMP_Log(RTMP_LOGERROR, "%s: connection lost while downloading swfurl %s",
__FUNCTION__, url);
else if (httpres == HTTPRES_NOT_FOUND)
RTMP_Log(RTMP_LOGERROR, "%s: swfurl %s not found", __FUNCTION__, url);
else
RTMP_Log(RTMP_LOGERROR, "%s: couldn't contact swfurl %s (HTTP error %d)",
__FUNCTION__, url, http.status);
}
else
{
if (got && pos)
fseek(f, pos, SEEK_SET);
else
{
char *q;
if (!f)
f = fopen(path, "w");
if (!f)
{
int err = errno;
RTMP_Log(RTMP_LOGERROR,
"%s: couldn't open %s for writing, errno %d (%s)",
__FUNCTION__, path, err, strerror(err));
ret = -1;
goto out;
}
fseek(f, 0, SEEK_END);
q = strchr(url, '?');
if (q)
i = q - url;
else
i = strlen(url);
fprintf(f, "url: %.*s\n", i, url);
}
strtime(&cnow, cctim);
fprintf(f, "ctim: %s\n", cctim);
if (!in.first)
{
HMAC_finish(in.ctx, hash, hlen);
*size = in.size;
fprintf(f, "date: %s\n", date);
fprintf(f, "size: %08x\n", in.size);
fprintf(f, "hash: ");
for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
fprintf(f, "%02x", hash[i]);
fprintf(f, "\n");
}
}
HMAC_close(in.ctx);
out:
free(path);
if (f)
fclose(f);
return ret;
}
#else
int
RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash,
int age)
{
return -1;
}
#endif

View File

@ -0,0 +1,224 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, 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()
{
return RTMP_debuglevel;
}
void RTMP_Log(int level, const char *format, ...)
{
va_list args;
if ( level > RTMP_debuglevel )
return;
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;
}

View File

@ -0,0 +1,289 @@
/*
* Copyright (C) 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, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/lgpl.html
*/
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include "rtmp_sys.h"
#include "log.h"
int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port,
AVal *playpath, AVal *app)
{
char *p, *end, *col, *ques, *slash;
RTMP_Log(RTMP_LOGDEBUG, "Parsing...");
*protocol = RTMP_PROTOCOL_RTMP;
*port = 0;
playpath->av_len = 0;
playpath->av_val = NULL;
app->av_len = 0;
app->av_val = NULL;
/* Old School Parsing */
/* look for usual :// pattern */
p = strstr(url, "://");
if(!p) {
RTMP_Log(RTMP_LOGERROR, "RTMP URL: No :// in url!");
return FALSE;
}
{
int len = (int)(p-url);
if(len == 4 && strncasecmp(url, "rtmp", 4)==0)
*protocol = RTMP_PROTOCOL_RTMP;
else if(len == 5 && strncasecmp(url, "rtmpt", 5)==0)
*protocol = RTMP_PROTOCOL_RTMPT;
else if(len == 5 && strncasecmp(url, "rtmps", 5)==0)
*protocol = RTMP_PROTOCOL_RTMPS;
else if(len == 5 && strncasecmp(url, "rtmpe", 5)==0)
*protocol = RTMP_PROTOCOL_RTMPE;
else if(len == 5 && strncasecmp(url, "rtmfp", 5)==0)
*protocol = RTMP_PROTOCOL_RTMFP;
else if(len == 6 && strncasecmp(url, "rtmpte", 6)==0)
*protocol = RTMP_PROTOCOL_RTMPTE;
else if(len == 6 && strncasecmp(url, "rtmpts", 6)==0)
*protocol = RTMP_PROTOCOL_RTMPTS;
else {
RTMP_Log(RTMP_LOGWARNING, "Unknown protocol!\n");
goto parsehost;
}
}
RTMP_Log(RTMP_LOGDEBUG, "Parsed protocol: %d", *protocol);
parsehost:
/* let's get the hostname */
p+=3;
/* check for sudden death */
if(*p==0) {
RTMP_Log(RTMP_LOGWARNING, "No hostname in URL!");
return FALSE;
}
end = p + strlen(p);
col = strchr(p, ':');
ques = strchr(p, '?');
slash = strchr(p, '/');
{
int hostlen;
if(slash)
hostlen = slash - p;
else
hostlen = end - p;
if(col && col -p < hostlen)
hostlen = col - p;
if(hostlen < 256) {
host->av_val = p;
host->av_len = hostlen;
RTMP_Log(RTMP_LOGDEBUG, "Parsed host : %.*s", hostlen, host->av_val);
} else {
RTMP_Log(RTMP_LOGWARNING, "Hostname exceeds 255 characters!");
}
p+=hostlen;
}
/* get the port number if available */
if(*p == ':') {
unsigned int p2;
p++;
p2 = atoi(p);
if(p2 > 65535) {
RTMP_Log(RTMP_LOGWARNING, "Invalid port number!");
} else {
*port = p2;
}
}
if(!slash) {
RTMP_Log(RTMP_LOGWARNING, "No application or playpath in URL!");
return TRUE;
}
p = slash+1;
{
/* parse application
*
* rtmp://host[:port]/app[/appinstance][/...]
* application = app[/appinstance]
*/
char *slash2, *slash3 = NULL, *slash4 = NULL;
int applen, appnamelen;
slash2 = strchr(p, '/');
if(slash2)
slash3 = strchr(slash2+1, '/');
if(slash3)
slash4 = strchr(slash3+1, '/');
applen = end-p; /* ondemand, pass all parameters as app */
appnamelen = applen; /* ondemand length */
if(ques && strstr(p, "slist=")) { /* whatever it is, the '?' and slist= means we need to use everything as app and parse plapath from slist= */
appnamelen = ques-p;
}
else if(strncmp(p, "ondemand/", 9)==0) {
/* app = ondemand/foobar, only pass app=ondemand */
applen = 8;
appnamelen = 8;
}
else { /* app!=ondemand, so app is app[/appinstance] */
if(slash4)
appnamelen = slash4-p;
else if(slash3)
appnamelen = slash3-p;
else if(slash2)
appnamelen = slash2-p;
applen = appnamelen;
}
app->av_val = p;
app->av_len = applen;
RTMP_Log(RTMP_LOGDEBUG, "Parsed app : %.*s", applen, p);
p += appnamelen;
}
if (*p == '/')
p++;
if (end-p) {
AVal av = {p, end-p};
RTMP_ParsePlaypath(&av, playpath);
}
return TRUE;
}
/*
* Extracts playpath from RTMP URL. playpath is the file part of the
* URL, i.e. the part that comes after rtmp://host:port/app/
*
* Returns the stream name in a format understood by FMS. The name is
* the playpath part of the URL with formatting depending on the stream
* type:
*
* mp4 streams: prepend "mp4:", remove extension
* mp3 streams: prepend "mp3:", remove extension
* flv streams: remove extension
*/
void RTMP_ParsePlaypath(AVal *in, AVal *out) {
int addMP4 = 0;
int addMP3 = 0;
int subExt = 0;
const char *playpath = in->av_val;
const char *temp, *q, *ext = NULL;
const char *ppstart = playpath;
char *streamname, *destptr, *p;
int pplen = in->av_len;
out->av_val = NULL;
out->av_len = 0;
if ((*ppstart == '?') &&
(temp=strstr(ppstart, "slist=")) != 0) {
ppstart = temp+6;
pplen = strlen(ppstart);
temp = strchr(ppstart, '&');
if (temp) {
pplen = temp-ppstart;
}
}
q = strchr(ppstart, '?');
if (pplen >= 4) {
if (q)
ext = q-4;
else
ext = &ppstart[pplen-4];
if ((strncmp(ext, ".f4v", 4) == 0) ||
(strncmp(ext, ".mp4", 4) == 0)) {
addMP4 = 1;
subExt = 1;
/* Only remove .flv from rtmp URL, not slist params */
} else if ((ppstart == playpath) &&
(strncmp(ext, ".flv", 4) == 0)) {
subExt = 1;
} else if (strncmp(ext, ".mp3", 4) == 0) {
addMP3 = 1;
subExt = 1;
}
}
streamname = (char *)malloc((pplen+4+1)*sizeof(char));
if (!streamname)
return;
destptr = streamname;
if (addMP4) {
if (strncmp(ppstart, "mp4:", 4)) {
strcpy(destptr, "mp4:");
destptr += 4;
} else {
subExt = 0;
}
} else if (addMP3) {
if (strncmp(ppstart, "mp3:", 4)) {
strcpy(destptr, "mp3:");
destptr += 4;
} else {
subExt = 0;
}
}
for (p=(char *)ppstart; pplen >0;) {
/* skip extension */
if (subExt && p == ext) {
p += 4;
pplen -= 4;
continue;
}
if (*p == '%') {
unsigned int c;
sscanf(p+1, "%02x", &c);
*destptr++ = c;
pplen -= 3;
p += 3;
} else {
*destptr++ = *p++;
pplen--;
}
}
*destptr = '\0';
out->av_val = streamname;
out->av_len = destptr - streamname;
}

File diff suppressed because it is too large Load Diff