parent
f122a5b972
commit
10618041aa
Binary file not shown.
Binary file not shown.
@ -0,0 +1,16 @@ |
||||
|
||||
|
||||
cmake_minimum_required(VERSION 3.4.1) |
||||
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_CRYPTO") |
||||
|
||||
add_library(rtmp |
||||
|
||||
STATIC |
||||
|
||||
amf.c |
||||
hashswf.c |
||||
log.c |
||||
parseurl.c |
||||
rtmp.c) |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,91 @@ |
||||
/*
|
||||
* Copyright (C) 2005-2008 Team XBMC |
||||
* http://www.xbmc.org
|
||||
* 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
|
||||
*/ |
||||
|
||||
#ifndef __BYTES_H__ |
||||
#define __BYTES_H__ |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#ifdef _WIN32 |
||||
/* Windows is little endian only */ |
||||
#define __LITTLE_ENDIAN 1234 |
||||
#define __BIG_ENDIAN 4321 |
||||
#define __BYTE_ORDER __LITTLE_ENDIAN |
||||
#define __FLOAT_WORD_ORDER __BYTE_ORDER |
||||
|
||||
typedef unsigned char uint8_t; |
||||
|
||||
#else /* !_WIN32 */ |
||||
|
||||
#include <sys/param.h> |
||||
|
||||
#if defined(BYTE_ORDER) && !defined(__BYTE_ORDER) |
||||
#define __BYTE_ORDER BYTE_ORDER |
||||
#endif |
||||
|
||||
#if defined(BIG_ENDIAN) && !defined(__BIG_ENDIAN) |
||||
#define __BIG_ENDIAN BIG_ENDIAN |
||||
#endif |
||||
|
||||
#if defined(LITTLE_ENDIAN) && !defined(__LITTLE_ENDIAN) |
||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN |
||||
#endif |
||||
|
||||
#endif /* !_WIN32 */ |
||||
|
||||
/* define default endianness */ |
||||
#ifndef __LITTLE_ENDIAN |
||||
#define __LITTLE_ENDIAN 1234 |
||||
#endif |
||||
|
||||
#ifndef __BIG_ENDIAN |
||||
#define __BIG_ENDIAN 4321 |
||||
#endif |
||||
|
||||
#ifndef __BYTE_ORDER |
||||
#warning "Byte order not defined on your system, assuming little endian!" |
||||
#define __BYTE_ORDER __LITTLE_ENDIAN |
||||
#endif |
||||
|
||||
/* ok, we assume to have the same float word order and byte order if float word order is not defined */ |
||||
#ifndef __FLOAT_WORD_ORDER |
||||
#warning "Float word order not defined, assuming the same as byte order!" |
||||
#define __FLOAT_WORD_ORDER __BYTE_ORDER |
||||
#endif |
||||
|
||||
#if !defined(__BYTE_ORDER) || !defined(__FLOAT_WORD_ORDER) |
||||
#error "Undefined byte or float word order!" |
||||
#endif |
||||
|
||||
#if __FLOAT_WORD_ORDER != __BIG_ENDIAN && __FLOAT_WORD_ORDER != __LITTLE_ENDIAN |
||||
#error "Unknown/unsupported float word order!" |
||||
#endif |
||||
|
||||
#if __BYTE_ORDER != __BIG_ENDIAN && __BYTE_ORDER != __LITTLE_ENDIAN |
||||
#error "Unknown/unsupported byte order!" |
||||
#endif |
||||
|
||||
#endif |
||||
|
@ -0,0 +1,334 @@ |
||||
/* RTMPDump - Diffie-Hellmann Key Exchange
|
||||
* 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 <stdint.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <assert.h> |
||||
#include <limits.h> |
||||
|
||||
#ifdef USE_POLARSSL |
||||
#include <polarssl/dhm.h> |
||||
typedef mpi * MP_t; |
||||
#define MP_new(m) m = malloc(sizeof(mpi)); mpi_init(m, NULL) |
||||
#define MP_set_w(mpi, w) mpi_lset(mpi, w) |
||||
#define MP_cmp(u, v) mpi_cmp_mpi(u, v) |
||||
#define MP_set(u, v) mpi_copy(u, v) |
||||
#define MP_sub_w(mpi, w) mpi_sub_int(mpi, mpi, w) |
||||
#define MP_cmp_1(mpi) mpi_cmp_int(mpi, 1) |
||||
#define MP_modexp(r, y, q, p) mpi_exp_mod(r, y, q, p, NULL) |
||||
#define MP_free(mpi) mpi_free(mpi, NULL); free(mpi) |
||||
#define MP_gethex(u, hex, res) MP_new(u); res = mpi_read_string(u, 16, hex) == 0 |
||||
#define MP_bytes(u) mpi_size(u) |
||||
#define MP_setbin(u,buf,len) mpi_write_binary(u,buf,len) |
||||
#define MP_getbin(u,buf,len) MP_new(u); mpi_read_binary(u,buf,len) |
||||
|
||||
typedef struct MDH { |
||||
MP_t p; |
||||
MP_t g; |
||||
MP_t pub_key; |
||||
MP_t priv_key; |
||||
long length; |
||||
dhm_context ctx; |
||||
} MDH; |
||||
|
||||
#define MDH_new() calloc(1,sizeof(MDH)) |
||||
#define MDH_free(vp) {MDH *dh = vp; dhm_free(&dh->ctx); MP_free(dh->p); MP_free(dh->g); MP_free(dh->pub_key); MP_free(dh->priv_key); free(dh);} |
||||
|
||||
static int MDH_generate_key(MDH *dh) |
||||
{ |
||||
unsigned char out[2]; |
||||
MP_set(&dh->ctx.P, dh->p); |
||||
MP_set(&dh->ctx.G, dh->g); |
||||
dh->ctx.len = 128; |
||||
dhm_make_public(&dh->ctx, 1024, out, 1, havege_rand, &RTMP_TLS_ctx->hs); |
||||
MP_new(dh->pub_key); |
||||
MP_new(dh->priv_key); |
||||
MP_set(dh->pub_key, &dh->ctx.GX); |
||||
MP_set(dh->priv_key, &dh->ctx.X); |
||||
return 1; |
||||
} |
||||
|
||||
static int MDH_compute_key(uint8_t *secret, size_t len, MP_t pub, MDH *dh) |
||||
{ |
||||
int n = len; |
||||
MP_set(&dh->ctx.GY, pub); |
||||
dhm_calc_secret(&dh->ctx, secret, &n); |
||||
return 0; |
||||
} |
||||
|
||||
#elif defined(USE_GNUTLS) |
||||
#include <gcrypt.h> |
||||
typedef gcry_mpi_t MP_t; |
||||
#define MP_new(m) m = gcry_mpi_new(1) |
||||
#define MP_set_w(mpi, w) gcry_mpi_set_ui(mpi, w) |
||||
#define MP_cmp(u, v) gcry_mpi_cmp(u, v) |
||||
#define MP_set(u, v) gcry_mpi_set(u, v) |
||||
#define MP_sub_w(mpi, w) gcry_mpi_sub_ui(mpi, mpi, w) |
||||
#define MP_cmp_1(mpi) gcry_mpi_cmp_ui(mpi, 1) |
||||
#define MP_modexp(r, y, q, p) gcry_mpi_powm(r, y, q, p) |
||||
#define MP_free(mpi) gcry_mpi_release(mpi) |
||||
#define MP_gethex(u, hex, res) res = (gcry_mpi_scan(&u, GCRYMPI_FMT_HEX, hex, 0, 0) == 0) |
||||
#define MP_bytes(u) (gcry_mpi_get_nbits(u) + 7) / 8 |
||||
#define MP_setbin(u,buf,len) gcry_mpi_print(GCRYMPI_FMT_USG,buf,len,NULL,u) |
||||
#define MP_getbin(u,buf,len) gcry_mpi_scan(&u,GCRYMPI_FMT_USG,buf,len,NULL) |
||||
|
||||
typedef struct MDH { |
||||
MP_t p; |
||||
MP_t g; |
||||
MP_t pub_key; |
||||
MP_t priv_key; |
||||
long length; |
||||
} MDH; |
||||
|
||||
#define MDH_new() calloc(1,sizeof(MDH)) |
||||
#define MDH_free(dh) do {MP_free(((MDH*)(dh))->p); MP_free(((MDH*)(dh))->g); MP_free(((MDH*)(dh))->pub_key); MP_free(((MDH*)(dh))->priv_key); free(dh);} while(0) |
||||
|
||||
extern MP_t gnutls_calc_dh_secret(MP_t *priv, MP_t g, MP_t p); |
||||
extern MP_t gnutls_calc_dh_key(MP_t y, MP_t x, MP_t p); |
||||
|
||||
#define MDH_generate_key(dh) (dh->pub_key = gnutls_calc_dh_secret(&dh->priv_key, dh->g, dh->p)) |
||||
static int MDH_compute_key(uint8_t *secret, size_t len, MP_t pub, MDH *dh) |
||||
{ |
||||
MP_t sec = gnutls_calc_dh_key(pub, dh->priv_key, dh->p); |
||||
if (sec) |
||||
{ |
||||
MP_setbin(sec, secret, len); |
||||
MP_free(sec); |
||||
return 0; |
||||
} |
||||
else |
||||
return -1; |
||||
} |
||||
|
||||
#else /* USE_OPENSSL */ |
||||
#include <openssl/bn.h> |
||||
#include <openssl/dh.h> |
||||
|
||||
typedef BIGNUM * MP_t; |
||||
#define MP_new(m) m = BN_new() |
||||
#define MP_set_w(mpi, w) BN_set_word(mpi, w) |
||||
#define MP_cmp(u, v) BN_cmp(u, v) |
||||
#define MP_set(u, v) BN_copy(u, v) |
||||
#define MP_sub_w(mpi, w) BN_sub_word(mpi, w) |
||||
#define MP_cmp_1(mpi) BN_cmp(mpi, BN_value_one()) |
||||
#define MP_modexp(r, y, q, p) do {BN_CTX *ctx = BN_CTX_new(); BN_mod_exp(r, y, q, p, ctx); BN_CTX_free(ctx);} while(0) |
||||
#define MP_free(mpi) BN_free(mpi) |
||||
#define MP_gethex(u, hex, res) res = BN_hex2bn(&u, hex) |
||||
#define MP_bytes(u) BN_num_bytes(u) |
||||
#define MP_setbin(u,buf,len) BN_bn2bin(u,buf) |
||||
#define MP_getbin(u,buf,len) u = BN_bin2bn(buf,len,0) |
||||
|
||||
#define MDH DH |
||||
#define MDH_new() DH_new() |
||||
#define MDH_free(dh) DH_free(dh) |
||||
#define MDH_generate_key(dh) DH_generate_key(dh) |
||||
#define MDH_compute_key(secret, seclen, pub, dh) DH_compute_key(secret, pub, dh) |
||||
|
||||
#endif |
||||
|
||||
#include "log.h" |
||||
#include "dhgroups.h" |
||||
|
||||
/* RFC 2631, Section 2.1.5, http://www.ietf.org/rfc/rfc2631.txt */ |
||||
static int |
||||
isValidPublicKey(MP_t y, MP_t p, MP_t q) |
||||
{ |
||||
int ret = TRUE; |
||||
MP_t bn; |
||||
assert(y); |
||||
|
||||
MP_new(bn); |
||||
assert(bn); |
||||
|
||||
/* y must lie in [2,p-1] */ |
||||
MP_set_w(bn, 1); |
||||
if (MP_cmp(y, bn) < 0) |
||||
{ |
||||
RTMP_Log(RTMP_LOGERROR, "DH public key must be at least 2"); |
||||
ret = FALSE; |
||||
goto failed; |
||||
} |
||||
|
||||
/* bn = p-2 */ |
||||
MP_set(bn, p); |
||||
MP_sub_w(bn, 1); |
||||
if (MP_cmp(y, bn) > 0) |
||||
{ |
||||
RTMP_Log(RTMP_LOGERROR, "DH public key must be at most p-2"); |
||||
ret = FALSE; |
||||
goto failed; |
||||
} |
||||
|
||||
/* Verify with Sophie-Germain prime
|
||||
* |
||||
* This is a nice test to make sure the public key position is calculated |
||||
* correctly. This test will fail in about 50% of the cases if applied to |
||||
* random data. |
||||
*/ |
||||
if (q) |
||||
{ |
||||
/* y must fulfill y^q mod p = 1 */ |
||||
MP_modexp(bn, y, q, p); |
||||
|
||||
if (MP_cmp_1(bn) != 0) |
||||
{ |
||||
RTMP_Log(RTMP_LOGWARNING, "DH public key does not fulfill y^q mod p = 1"); |
||||
} |
||||
} |
||||
|
||||
failed: |
||||
MP_free(bn); |
||||
return ret; |
||||
} |
||||
|
||||
static MDH * |
||||
DHInit(int nKeyBits) |
||||
{ |
||||
size_t res; |
||||
MDH *dh = MDH_new(); |
||||
|
||||
if (!dh) |
||||
goto failed; |
||||
|
||||
MP_new(dh->g); |
||||
|
||||
if (!dh->g) |
||||
goto failed; |
||||
|
||||
MP_gethex(dh->p, P1024, res); /* prime P1024, see dhgroups.h */ |
||||
if (!res) |
||||
{ |
||||
goto failed; |
||||
} |
||||
|
||||
MP_set_w(dh->g, 2); /* base 2 */ |
||||
|
||||
dh->length = nKeyBits; |
||||
return dh; |
||||
|
||||
failed: |
||||
if (dh) |
||||
MDH_free(dh); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int |
||||
DHGenerateKey(MDH *dh) |
||||
{ |
||||
size_t res = 0; |
||||
if (!dh) |
||||
return 0; |
||||
|
||||
while (!res) |
||||
{ |
||||
MP_t q1 = NULL; |
||||
|
||||
if (!MDH_generate_key(dh)) |
||||
return 0; |
||||
|
||||
MP_gethex(q1, Q1024, res); |
||||
assert(res); |
||||
|
||||
res = isValidPublicKey(dh->pub_key, dh->p, q1); |
||||
if (!res) |
||||
{ |
||||
MP_free(dh->pub_key); |
||||
MP_free(dh->priv_key); |
||||
dh->pub_key = dh->priv_key = 0; |
||||
} |
||||
|
||||
MP_free(q1); |
||||
} |
||||
return 1; |
||||
} |
||||
|
||||
/* fill pubkey with the public key in BIG ENDIAN order
|
||||
* 00 00 00 00 00 x1 x2 x3 ..... |
||||
*/ |
||||
|
||||
static int |
||||
DHGetPublicKey(MDH *dh, uint8_t *pubkey, size_t nPubkeyLen) |
||||
{ |
||||
int len; |
||||
if (!dh || !dh->pub_key) |
||||
return 0; |
||||
|
||||
len = MP_bytes(dh->pub_key); |
||||
if (len <= 0 || len > (int) nPubkeyLen) |
||||
return 0; |
||||
|
||||
memset(pubkey, 0, nPubkeyLen); |
||||
MP_setbin(dh->pub_key, pubkey + (nPubkeyLen - len), len); |
||||
return 1; |
||||
} |
||||
|
||||
#if 0 /* unused */
|
||||
static int |
||||
DHGetPrivateKey(MDH *dh, uint8_t *privkey, size_t nPrivkeyLen) |
||||
{ |
||||
if (!dh || !dh->priv_key) |
||||
return 0; |
||||
|
||||
int len = MP_bytes(dh->priv_key); |
||||
if (len <= 0 || len > (int) nPrivkeyLen) |
||||
return 0; |
||||
|
||||
memset(privkey, 0, nPrivkeyLen); |
||||
MP_setbin(dh->priv_key, privkey + (nPrivkeyLen - len), len); |
||||
return 1; |
||||
} |
||||
#endif |
||||
|
||||
/* computes the shared secret key from the private MDH value and the
|
||||
* other party's public key (pubkey) |
||||
*/ |
||||
static int |
||||
DHComputeSharedSecretKey(MDH *dh, uint8_t *pubkey, size_t nPubkeyLen, |
||||
uint8_t *secret) |
||||
{ |
||||
MP_t q1 = NULL, pubkeyBn = NULL; |
||||
size_t len; |
||||
int res; |
||||
|
||||
if (!dh || !secret || nPubkeyLen >= INT_MAX) |
||||
return -1; |
||||
|
||||
MP_getbin(pubkeyBn, pubkey, nPubkeyLen); |
||||
if (!pubkeyBn) |
||||
return -1; |
||||
|
||||
MP_gethex(q1, Q1024, len); |
||||
assert(len); |
||||
|
||||
if (isValidPublicKey(pubkeyBn, dh->p, q1)) |
||||
res = MDH_compute_key(secret, nPubkeyLen, pubkeyBn, dh); |
||||
else |
||||
res = -1; |
||||
|
||||
MP_free(q1); |
||||
MP_free(pubkeyBn); |
||||
|
||||
return res; |
||||
} |
@ -0,0 +1,199 @@ |
||||
/* librtmp - Diffie-Hellmann Key Exchange
|
||||
* Copyright (C) 2009 Andrej Stepanchuk |
||||
* |
||||
* 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
|
||||
*/ |
||||
|
||||
/* from RFC 3526, see http://www.ietf.org/rfc/rfc3526.txt */ |
||||
|
||||
/* 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 } */ |
||||
#define P768 \ |
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
|
||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
|
||||
"E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF" |
||||
|
||||
/* 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } */ |
||||
#define P1024 \ |
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
|
||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
|
||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
|
||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \
|
||||
"FFFFFFFFFFFFFFFF" |
||||
|
||||
/* Group morder largest prime factor: */ |
||||
#define Q1024 \ |
||||
"7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68" \
|
||||
"948127044533E63A0105DF531D89CD9128A5043CC71A026E" \
|
||||
"F7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122" \
|
||||
"F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6" \
|
||||
"F71C35FDAD44CFD2D74F9208BE258FF324943328F67329C0" \
|
||||
"FFFFFFFFFFFFFFFF" |
||||
|
||||
/* 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 } */ |
||||
#define P1536 \ |
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
|
||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
|
||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
|
||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
|
||||
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
|
||||
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
|
||||
"670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF" |
||||
|
||||
/* 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 } */ |
||||
#define P2048 \ |
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
|
||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
|
||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
|
||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
|
||||
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
|
||||
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
|
||||
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \
|
||||
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \
|
||||
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \
|
||||
"15728E5A8AACAA68FFFFFFFFFFFFFFFF" |
||||
|
||||
/* 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 } */ |
||||
#define P3072 \ |
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
|
||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
|
||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
|
||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
|
||||
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
|
||||
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
|
||||
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \
|
||||
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \
|
||||
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \
|
||||
"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \
|
||||
"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \
|
||||
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \
|
||||
"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \
|
||||
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \
|
||||
"43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF" |
||||
|
||||
/* 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 } */ |
||||
#define P4096 \ |
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
|
||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
|
||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
|
||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
|
||||
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
|
||||
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
|
||||
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \
|
||||
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \
|
||||
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \
|
||||
"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \
|
||||
"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \
|
||||
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \
|
||||
"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \
|
||||
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \
|
||||
"43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \
|
||||
"88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \
|
||||
"2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \
|
||||
"287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \
|
||||
"1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \
|
||||
"93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" \
|
||||
"FFFFFFFFFFFFFFFF" |
||||
|
||||
/* 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 } */ |
||||
#define P6144 \ |
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
|
||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
|
||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
|
||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
|
||||
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
|
||||
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
|
||||
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \
|
||||
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \
|
||||
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \
|
||||
"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \
|
||||
"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \
|
||||
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \
|
||||
"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \
|
||||
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \
|
||||
"43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \
|
||||
"88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \
|
||||
"2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \
|
||||
"287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \
|
||||
"1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \
|
||||
"93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" \
|
||||
"36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" \
|
||||
"F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" \
|
||||
"179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" \
|
||||
"DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" \
|
||||
"5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" \
|
||||
"D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" \
|
||||
"23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" \
|
||||
"CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" \
|
||||
"06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" \
|
||||
"DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" \
|
||||
"12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF" |
||||
|
||||
/* 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 } */ |
||||
#define P8192 \ |
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
|
||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
|
||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
|
||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
|
||||
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
|
||||
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
|
||||
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \
|
||||
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \
|
||||
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \
|
||||
"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \
|
||||
"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \
|
||||
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \
|
||||
"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \
|
||||
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \
|
||||
"43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \
|
||||
"88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \
|
||||
"2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \
|
||||
"287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \
|
||||
"1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \
|
||||
"93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" \
|
||||
"36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" \
|
||||
"F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" \
|
||||
"179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" \
|
||||
"DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" \
|
||||
"5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" \
|
||||
"D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" \
|
||||
"23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" \
|
||||
"CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" \
|
||||
"06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" \
|
||||
"DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" \
|
||||
"12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" \
|
||||
"38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" \
|
||||
"741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" \
|
||||
"3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" \
|
||||
"22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" \
|
||||
"4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" \
|
||||
"062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" \
|
||||
"4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" \
|
||||
"B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" \
|
||||
"4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" \
|
||||
"9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" \
|
||||
"60C980DD98EDD3DFFFFFFFFFFFFFFFFF" |
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 <gnutls/gnutls.h> |
||||
#include <gcrypt.h> |
||||
#ifndef SHA256_DIGEST_LENGTH |
||||
#define SHA256_DIGEST_LENGTH 32 |
||||
#endif |
||||
#define HMAC_CTX gcry_md_hd_t |
||||
#define HMAC_setup(ctx, key, len) gcry_md_open(&ctx, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); gcry_md_setkey(ctx, key, len) |
||||
#define HMAC_crunch(ctx, buf, len) gcry_md_write(ctx, buf, len) |
||||
#define HMAC_finish(ctx, dig, dlen) dlen = SHA256_DIGEST_LENGTH; memcpy(dig, gcry_md_read(ctx, 0), dlen) |
||||
#define HMAC_close(ctx) gcry_md_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; |
||||
|
||||
#endif /* CRYPTO */ |
||||
|
||||
#include <zlib.h> |
||||
|
||||
#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\nReferrer: %.*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 ((i = 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 |
||||
*/ |
||||
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 _XBOX |
||||
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 = ∈ |
||||
|
||||
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 |
@ -0,0 +1,220 @@ |
||||
/*
|
||||
* 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; |
||||
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; |
||||
} |
@ -0,0 +1,285 @@ |
||||
/*
|
||||
* 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; |
||||
int applen, appnamelen; |
||||
|
||||
slash2 = strchr(p, '/'); |
||||
if(slash2) |
||||
slash3 = strchr(slash2+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(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
@ -0,0 +1,112 @@ |
||||
#ifndef __RTMP_SYS_H__ |
||||
#define __RTMP_SYS_H__ |
||||
/*
|
||||
* Copyright (C) 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
|
||||
*/ |
||||
|
||||
#ifdef _WIN32 |
||||
|
||||
#ifdef _XBOX |
||||
#include <xtl.h> |
||||
#include <winsockx.h> |
||||
#define snprintf _snprintf |
||||
#define strcasecmp stricmp |
||||
#define strncasecmp strnicmp |
||||
#define vsnprintf _vsnprintf |
||||
|
||||
#else /* !_XBOX */ |
||||
#include <winsock2.h> |
||||
#include <ws2tcpip.h> |
||||
#endif |
||||
|
||||
#define GetSockError() WSAGetLastError() |
||||
#define SetSockError(e) WSASetLastError(e) |
||||
#define setsockopt(a,b,c,d,e) (setsockopt)(a,b,c,(const char *)d,(int)e) |
||||
#define EWOULDBLOCK WSAETIMEDOUT /* we don't use nonblocking, but we do use timeouts */ |
||||
#define sleep(n) Sleep(n*1000) |
||||
#define msleep(n) Sleep(n) |
||||
#define SET_RCVTIMEO(tv,s) int tv = s*1000 |
||||
#else /* !_WIN32 */ |
||||
#include <sys/types.h> |
||||
#include <sys/socket.h> |
||||
#include <sys/times.h> |
||||
#include <netdb.h> |
||||
#include <arpa/inet.h> |
||||
#include <unistd.h> |
||||
#include <netinet/in.h> |
||||
#include <netinet/tcp.h> |
||||
#define GetSockError() errno |
||||
#define SetSockError(e) errno = e |
||||
#undef closesocket |
||||
#define closesocket(s) close(s) |
||||
#define msleep(n) usleep(n*1000) |
||||
#define SET_RCVTIMEO(tv,s) struct timeval tv = {s,0} |
||||
#endif |
||||
|
||||
#include "rtmp.h" |
||||
|
||||
#ifdef USE_POLARSSL |
||||
#include <polarssl/net.h> |
||||
#include <polarssl/ssl.h> |
||||
#include <polarssl/havege.h> |
||||
typedef struct tls_ctx { |
||||
havege_state hs; |
||||
ssl_session ssn; |
||||
} tls_ctx; |
||||
#define TLS_CTX tls_ctx * |
||||
#define TLS_client(ctx,s) s = malloc(sizeof(ssl_context)); ssl_init(s);\ |
||||
ssl_set_endpoint(s, SSL_IS_CLIENT); ssl_set_authmode(s, SSL_VERIFY_NONE);\
|
||||
ssl_set_rng(s, havege_rand, &ctx->hs); ssl_set_ciphers(s, ssl_default_ciphers);\
|
||||
ssl_set_session(s, 1, 600, &ctx->ssn) |
||||
#define TLS_setfd(s,fd) ssl_set_bio(s, net_recv, &fd, net_send, &fd) |
||||
#define TLS_connect(s) ssl_handshake(s) |
||||
#define TLS_read(s,b,l) ssl_read(s,(unsigned char *)b,l) |
||||
#define TLS_write(s,b,l) ssl_write(s,(unsigned char *)b,l) |
||||
#define TLS_shutdown(s) ssl_close_notify(s) |
||||
#define TLS_close(s) ssl_free(s); free(s) |
||||
|
||||
#elif defined(USE_GNUTLS) |
||||
#include <gnutls/gnutls.h> |
||||
typedef struct tls_ctx { |
||||
gnutls_certificate_credentials_t cred; |
||||
gnutls_priority_t prios; |
||||
} tls_ctx; |
||||
#define TLS_CTX tls_ctx * |
||||
#define TLS_client(ctx,s) gnutls_init((gnutls_session_t *)(&s), GNUTLS_CLIENT); gnutls_priority_set(s, ctx->prios); gnutls_credentials_set(s, GNUTLS_CRD_CERTIFICATE, ctx->cred) |
||||
#define TLS_setfd(s,fd) gnutls_transport_set_ptr(s, (gnutls_transport_ptr_t)(long)fd) |
||||
#define TLS_connect(s) gnutls_handshake(s) |
||||
#define TLS_read(s,b,l) gnutls_record_recv(s,b,l) |
||||
#define TLS_write(s,b,l) gnutls_record_send(s,b,l) |
||||
#define TLS_shutdown(s) gnutls_bye(s, GNUTLS_SHUT_RDWR) |
||||
#define TLS_close(s) gnutls_deinit(s) |
||||
|
||||
#else /* USE_OPENSSL */ |
||||
#define TLS_CTX SSL_CTX * |
||||
#define TLS_client(ctx,s) s = SSL_new(ctx) |
||||
#define TLS_setfd(s,fd) SSL_set_fd(s,fd) |
||||
#define TLS_connect(s) SSL_connect(s) |
||||
#define TLS_read(s,b,l) SSL_read(s,b,l) |
||||
#define TLS_write(s,b,l) SSL_write(s,b,l) |
||||
#define TLS_shutdown(s) SSL_shutdown(s) |
||||
#define TLS_close(s) SSL_free(s) |
||||
|
||||
#endif |
||||
#endif |
Loading…
Reference in new issue