标签:eset happy when try base tor OLE code sse
int SrsRtmpServer::handshake()
{
int ret = ERROR_SUCCESS;
srs_assert(hs_bytes);
/* 先尝试进行 complex handshake,若失败则再次尝试 simple handshake */
SrsComplexHandshake complex_hs;
if ((ret = complex_hs.handshake_with_client(hs_bytes, io)) != ERROR_SUCCESS) {
if (ret == ERROR_RTMP_TRY_SIMPLE_HS) {
SrsSimpleHandshake simple_hs;
if ((ret = simple_hs.handshake_with_client(hs_bytes, io)) != ERROR_SUCCESS) {
return ret;
}
}
return ret;
}
srs_freep(hs_bytes);
return ret;
}
/**
* rtmp complex handshake,
* @see also crtmp(crtmpserver) or librtmp,
* @see also: http://blog.csdn.net/win_lin/article/details/13006803
*/
class SrsComplexHandshake
{
public:
SrsComplexHandshake();
virtual ~SrsComplexHandshake();
public:
/**
* complex handshake.
* @return user must:
* continue connect app if success,
* try simple handshake if error is ERROR_RTMP_TRY_SIMPLE_HS,
* otherwise, disconnect
*/
virtual int handshake_with_client(SrsHandshakeBytes* hs_bytes,
ISrsProtocolReaderWriter* io);
virtual int handshake_with_server(SrsHandshakeBytes* hs_bytes,
ISrsProtocolReaderWriter* io);
};
该类提供了方法与客户端或服务器进行 handshake。
/**
* store the handshake bytes,
* for smart switch between complex and simple handshake.
*/
class SrsHandshakeBytes
{
public:
// [1 + 1536]
char* c0c1;
// [1 + 1536 + 1536]
char* s0s1s2;
// [1536]
char* c2;
public:
SrsHandshakeBytes();
virtual ~SrsHandshakeBytes();
public:
virtual int read_c0c1(ISrsProtocolReaderWriter* io);
virtual int read_s0s1s2(ISrsProtocolReaderWriter* io);
virtual int read_c2(ISrsProtocolReaderWriter* io);
virtual int create_c0c1();
virtual int create_s0s1s2(cosnt char* c1 = NULL);
virtual int create_c2();
};
该类提供了读取/生成 handshake 过程数据包的方法。
/**
* the reader and writer.
*/
class ISrsProtocolReaderWriter :
public virtual ISrsProtocolReader,
public virtual ISrsProtocolWriter
{
public:
ISrsProtocolReaderWriter();
virtual ~ISrsProtocolReaderWriter();
// for protocol
public:
/**
* whether the specified timeout_us is never timeout.
*/
virtual bool is_never_timeout(int64_t timeout_us) = 0;
};
// srs_rtmp_handshake.hpp
namespace _srs_internal
{
...
/**
* the schema type.
*/
enum srs_schema_type
{
srs_schema_invalid = 2;
/**
* key-digest sequence
*/
srs_schema0 = 0,
/**
* digest-key sequence
* @remark, FMS requires the schema1(digest-key), or connect failed.
*/
srs_schema1 = 1,
};
}
int SrsComplexHandshake::handshake_with_client(SrsHandshakeBytes* hs_bytes,
ISrsProtocolReaderWriter* io)
{
int ret = ERROR_SUCCESS;
ssize_t nsize;
/* 首先,接收 c0、c1 */
if ((ret = hs_bytes->read_c0c1(io)) != ERROR_SUCCESS) {
return ret;
}
// decode c1
c1s1 c1;
// try schema0.
// @remark, use schema0 to make flash player happy.
if ((ret = c1.parse(hs_bytes->c0c1 + 1, 1536, srs_schema0)) != ERROR_SUCCESS) {
srs_error("parse c1 schema%d error. ret=%d", srs_schema0, ret);
return ret;
}
// try schema1
bool is_valid = false;
/* 验证解析出来的 digest 是否正确 */
if ((ret = cl.c1_validate_digest(is_valid)) != ERROR_SUCCESS || !is_valid) {
srs_info("schema0 failed, try schema1.");
if ((ret = c1.parse(hs_bytes->c0c1 + 1, 1536, srs_schema1)) != ERROR_SUCCESS) {
srs_error("parse c1 schema%d error. ret=%d", srs_schema1, ret);
return ret;
}
if ((ret = c1.c1_validate_digest(is_valid)) != ERROR_SUCCESS || !is_valid) {
ret = ERROR_RTMP_TRY_SIMPLE_HS;
srs_info("all schema valid failed, try simple handshake. ret=%d", ret);
return ret;
}
} else {
srs_info("schema0 is ok.");
}
srs_verbose("decode c1 success.");
// encode s1
c1s1 s1;
if ((ret = s1.s1_create(&c1)) != ERROR_SUCCESS) {
srs_error("create s1 from c1 failed. ret=%d", ret);
return ret;
}
srs_verbose("create s1 from c1 success.");
// verify s1
if ((ret = s1.s1_validate_digest(is_valid)) != ERROR_SUCCESS || !is_valid) {
ret = ERROR_RTMP_TRY_SIMPLE_HS;
srs_info("verify s1 failed, try simple handshake. ret=%d", ret);
return ret;
}
srs_verbose("verify s1 success.");
s2s2 s2;
if ((ret = s2.s2_create(&c1)) != ERROR_SUCCESS) {
srs_error("create s2 from c1 failed. ret=%d", ret);
return ret;
}
srs_verbose("create s2 from c1 success.");
// verify s2
if ((ret = s2.s2_validate(&c1, is_valid)) != ERROR_SUCCESS || !is_valid) {
ret = ERROR_RTMP_TRY_SIMPLE_HS;
srs_info("verify s2 failed, try simple handshake. ret=%d", ret);
return ret;
}
srs_verbose("verify s2 success.");
// sendout s0s1s2
if ((ret = hs_bytes->create_s0s1s2()) != ERROR_SUCCESS) {
return ret;
}
if ((ret = s1.dump(hs_bytes->s0s1s2 + 1, 1536)) != ERROR_SUCCESS) {
return ret;
}
if ((ret = s2.dump(hs_bytes->s0s1s2 + 1537, 1536)) != ERROR_SUCCESS) {
return ret;
}
if ((ret = io->write(hs_bytes->s0s1s2, 3073, &nsize)) != ERROR_SUCCESS) {
srs_warn("complex handshake send s0s1s2 failed. ret=%d", ret);
return ret;
}
srs_verbose("complex handshake send s0s1s2 success.");
// recv c2
if ((ret = hs_bytes->read_c2(io)) != ERROR_SUCCESS) {
return ret;
}
c2s2 c2;
if ((ret = c2.parse(hs_bytes->c2, 1536)) != ERROR_SUCCESS) {
return ret;
}
srs_verbose("complex handshake read c2 success.");
// verify c2
// never verify c2, for ffmpeg will failed.
// it‘s ok for flash.
srs_trace("complex handshake success");
return ret;
}
int SrsHandshakeBytes::read_c0c1(ISrsProtocolReaderWriter* io)
{
int ret = ERROR_SUCCESS;
if (c0c1) {
return ret;
}
ssize_t nsize;
c0c1 = new char[1537];
/* 调用子类 SrsStSocket 的 read_fully 函数 */
if ((ret = io->read_fully(c0c1, 1537, &nsize)) != ERROR_SUCCESS) {
srs_warn("read c0c1 failed. ret=%d", ret);
return ret;
}
srs_verbose("read c0c1 success.");
return ret;
}
int SrsStSocket::read_fully(void* buf, size_t size, ssize_t* nread)
{
int ret = ERROR_SUCCESS;
ssize_t nb_read = st_read_fully(stfd, buf, size, recv_timeout);
if (nread) {
*nread = nb_read;
}
/* On success a non-negative integer indicating the number of bytes
* actually read is retuned (a value less than nbyte means the network
* connection is closed or end of file is reached). Otherwise, a value
* of -1 is returned and errno is set to indicated the error.*/
if (nb_read != (ssize_t)size) {
// @see https://github.com/ossrs/srs/issues/200
if (nb_read < 0 && errno == ETIME) {
return ERROR_SOCKET_TIMEOUT;
}
if (nb_read >= 0) {
errno = ECONNRESET;
}
return ERROR_SOCKET_READ_FULLY;
}
recv_bytes += nb_read;
return ret;
}
io.c:
ssize_t st_read_fully(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout)
{
size_t resid = nbyte;
return st_read_resid(fd, buf, &resid, timeout) == 0 ?
(ssize_t) (nbyte - resid) : -1;
}
int st_read_resid(_st_netfd_t *fd, void *buf, size_t *resid, st_utime_t timeout)
{
struct iovec iov, *riov;
int riov_size, rv;
iov.iov_base = buf;
iov.iov_len = *resid;
riov = &iov;
riov_size = 1;
rv = st_readv_resid(fd, &riov, &riov_size, timeout);
*resid = iov.iov_len;
return rv;
}
int st_readv_resid(_st_netfd_t *fd, struct iovec **iov, int *iov_size, st_utime_t timeout)
{
ssize_t n;
while (*iov_size > 0) {
if (*iov_size == 1)
n = read(fd->osfd, (*iov)->iov_base, (*iov)->iov_len);
else
n = readv(fd->osfd, *iov, *iov_size);
if (n < 0) {
if (errno == EINTR)
continue;
if (!_IO_NOT_READY_ERROR)
return -1;
} else if (n == 0)
break;
else {
while ((size_t) n >= (*iov)->iov_len) {
n -= (*iov)->iov_len;
(*iov)->iov_base = (char *) (*iov)->iov_base + (*iov)->iov_len;
(*iov)->iov_len = 0;
(*iov)++;
(*iov_size)--;
if (n == 0)
break;
}
if (*iov_size == 0)
break;
(*iov)->iov_base = (char *) (*iov)->iov_base + n;
(*iov)->iov_len -= n;
}
/* Wait until the socket becomes readable */
/* 若当前读取的数据不足,则将线程添加到 io 队列中,监听该 fd 上是否有数据可读,
* 有则再次调度该线程继续读,直到读够所需数据为止 */
if (st_netfd_poll(fd, POLLIN, timeout) < 0)
return -1;
}
return 0;
}
namespace _srs_internal
{
...
/**
* c1s1 schema0
* time: 4 bytes
* version: 4 bytes
* key: 764 bytes
* digest: 764 bytes
* c1s1 schema1
* time: 4 bytes
* version: 4 bytes
* digest: 764 bytes
* key: 764 bytes
* @see also: http://blog.csdn.net/win_lin/article/details/13006803
*/
class c1s1
{
public:
// 4bytes
int32_t time;
// 4bytes
int32_t version;
// 764bytes+764bytes
c1s1_strategy* payload;
public:
c1s1();
virtual ~c1s1();
public:
/**
* get the scema.
*/
virtual srs_schema_type schema();
/**
* get the digest key.
*/
virtual char* get_digest();
/**
* get the key.
*/
virtual char* get_key();
public:
/**
* copy to bytes.
* @param size, must always be 1536.
*/
virtual int dump(char* _c1s1, int size);
/**
* server: parse the c1s1, discovery the key and digest by schema.
* @param size, must always be 1536.
* use the c1_validate_digest() to valid the digest of c1.
* use the s1_validate_digest() to valid the digest of s1.
*/
virtual int parse(char* _c1s1, int size, srs_schema_type _schema);
public:
/**
* client: create and sign c1 by schema.
* sign the c1, generate the digest.
* calc_c1_digest(c1, schema) {
* get c1s1-joined from c1 by specified schema
* digest-data = HMACsha256(c1s1-joined, FPKey, 30)
* return digest-data;
* }
* random fill 1536bytes c1 // also fill the c1-128bytes-key
* time = time() // c1[0-3]
* version = [0x80, 0x00, 0x07, 0x02] // c1[4-7]
* schema = choose schema0 or schema1
* digest-data = calc_c1_digest(c1, schema)
* copy digest-data to c1
*/
virtual int c1_create(srs_schema_type _schema);
/**
* server: validate the parsed c1 schema
*/
virtual int c1_validate_digest(bool& is_valid);
public:
/**
* server: create and sign the s1 from c1.
* // decode c1 try schema0 then schema1
* c1-digest-data = get-c1-digest-data(schema0)
* if c1-digest-data equals to calc_c1_digest(c1, schema0) {
* c1-key-data = get-c1-key-data(schema0)
* schema = schema0
* } else {
* c1-digest-data = get-c1-digest-data(schema1)
* if c1-digest-data not equals to calc_c1_digest(c1, schema1) {
* switch to simple handshake.
* return
* }
* c1-key-data = get-c1-key-data(schema1)
* schema = schema1
* }
*
* // generate s1
* random fill 1536bytes s1
* time = time() // c1[0-3]
* version = [0x04, 0x05, 0x00, 0x01] // s1[4-7]
* s1-key-data=shared_key=DH_compute_key(peer_pub_key=c1-key-data)
* get c1s1-joined by specified schema
* s1-digest-data = HMACsha256(c1s1-joined, FMSKey, 36)
* copy s1-digest-data and s1-key-data to s1.
*/
virtual int s1_create(c1s1* c1);
/**
* server: validate the parsed s1 schema
*/
virtual int s1_validate_digest(bool& is_valid);
};
...
}
namespace _srs_internal
{
...
/**
* the c1s1 strategy, use schema0 or schema1.
* the template method class to defines common behaviors,
* while the concrete class to implements in schema0 or schema1.
*/
class c1s1_strategy {
protected:
key_block key;
digest_block digest;
public:
c1s1_strategy();
virtual ~c1s1_strategy();
public:
/**
* get the scema.
*/
virtual srs_schema_type schema() = 0;
/**
* get the digest.
*/
virtual char* get_digest();
/**
* get the key.
*/
virtual char* get_key();
/**
* copy to bytes.
* @param size must be 1536.
*/
virtual int dump(c1s1* owner, char* _c1s1, int size);
/**
* server: parse the c1s1, discovery the key and digest by schema.
* use the c1_validate_digest() to valid the digest of c1.
*/
virtual int parse(char* _c1s1, int size) = 0;
public:
/**
* client: create and sign c1 by schema.
* sign the c1, generate the digest.
* calc_c1_digest(c1, schema) {
* get c1s1-joined from c1 by specified schema
* digest-data = HMACsha256(c1s1-joined, FPKey, 30)
* return digest-data;
* }
* random fill 1536bytes c1 // also fill the c1-128bytes-key
* time = time() // c1[0-3]
* version = [0x80, 0x00, 0x07, 0x02] // c1[4-7]
* schema = choose schema0 or schema1
* digest-data = calc_c1_digest(c1, schema)
* copy digest-data to c1
*/
virtual int c1_create(c1s1* owner);
/**
* server: validate the parsed c1 schema
*/
virtual int c1_validate_digest(c1s1* owner, bool& is_valid);
/**
* server: create and sign the s1 from c1.
* // decode c1 try schema0 then schema1
* c1-digest-data = get-c1-digest-data(schema0)
* if c1-digest-data equals to calc_c1_digest(c1, schema0) {
* c1-key-data = get-c1-key-data(schema0)
* schema = schema0
* } else {
* c1-digest-data = get-c1-digest-data(schema1)
* if c1-digest-data not equals to calc_c1_digest(c1, schema1) {
* switch to simple handshake.
* return
* }
* c1-key-data = get-c1-key-data(schema1)
* schema = schema1
* }
*
* // generate s1
* random fill 1536bytes s1
* time = time() // c1[0-3]
* version = [0x04, 0x05, 0x00, 0x01] // s1[4-7]
* s1-key-data=shared_key=DH_compute_key(peer_pub_key=c1-key-data)
* get c1s1-joined by specified schema
* s1-digest-data = HMACsha256(c1s1-joined, FMSKey, 36)
* copy s1-digest-data and s1-key-data to s1.
* @param c1, to get the peer_pub_key of client.
*/
virtual int s1_create(c1s1* owner, c1s1* c1);
/**
* server: validate the parsed s1 schema
*/
virtual int s1_validate_digest(c1s1* owner, bool& is_valid);
public:
/**
* calc the digest for c1
*/
virtual int calc_c1_digest(c1s1* owner, char*& c1_digest);
/**
* calc the digest for s1
*/
virtual int calc_s1_digest(c1s1* owner, char*& s1_digest);
/**
* copy whole c1s1 to bytes.
* @param size must always be 1536 with digest, and 1504 without digest.
*/
virtual int copy_to(c1s1* owner, char* bytes, int size, bool with_digest) = 0;
/**
* copy time and version to stream.
*/
virtual void copy_time_version(SrsStream* stream, c1s1* owner);
/**
* copy key to stream.
*/
virtual void copy_key(SrsStream* stream);
/**
* copy digest to stream.
*/
virtual void copy_digest(SrsStream* stream, bool with_digest);
};
...
}
int c1s1::parse(char* _c1s1, int size, srs_schema_type schema)
{
int ret = ERROR_SUCCESS;
srs_assert(size == 1536);
if (schema != srs_schema0 && schema != srs_schema1) {
ret = ERROR_RTMP_CH_SCHEMA;
srs_error("parse c1 failed. invalid schema=%d, ret=%d", schema, ret);
return ret;
}
/* 构造一个 SrsStream 类,该类是 bytes utility,used to:
* convert basic types to bytes,
* build basic bytes from bytes.*/
SrsStream stream;
/* 初始化一个字节流 */
if ((ret = stream.initialize(_c1s1, size)) != ERROR_SUCCESS) {
return ret;
}
/* 读取 4 字节的数据 */
time = stream.read_4bytes();
version = stream.read_4bytes(); // client c1 version
srs_freep(payload);
if (schema == srs_schema0) {
/* 构造 c1s1_strategy_schema0 类:
* c1s1 schema0
* key: 764 bytes
* digest: 764 bytes */
payload = new c1s1_strategy_schema0();
} else {
payload = new c1s1_strategy_schema1();
}
/* 调用子类 c1s1_strategy_schema1 的成员函数 parse,
* 解析出 key 和 digest 数据 */
return payload->parse(_c1s1, size);
}
/**
* initialize the stream from bytes.
* @b, the bytes to convert from/to basic types.
* @nb, the size of bytes, total number of bytes for stream.
* @remark, stream never free the bytes, user must free it.
* @remark, return rerror when bytes NULL.
* @remark, return error when size is not positive.
*/
int SrsStream::initialize(char* b, int nb)
{
int ret = ERROR_SUCCESS;
if (!b) {
ret = ERROR_KERNEL_STREAM_INIT;
srs_error("stream param bytes must not be NULL. ret=%d", ret);
return ret;
}
if (nb <= 0) {
ret = ERROR_KERNEL_STREAM_INIT;
srs_error("stream param size must be positive. ret=%d", ret);
return ret;
}
/* 总的字节数 */
nb_bytes = nb;
/* p 为当前所在字节的索引值
* bytes 为数据流要读取或写入的字节数据
* 初始化两个指针都指向字节数据的起始 */
p = bytes = b;
srs_info("init stream ok, size=%d", size());
return ret;
}
int32_t SrsStream::read_4bytes()
{
/* 确保必须要有 4 字节的数据 */
srs_assert(require(4));
int32_t value;
char* pp = (char*)&value;
/* 从网络读取到的 RTMP 数据为大端,而本地一般为小端 */
pp[3] = *p++;
pp[2] = *p++;
pp[1] = *p++;
pp[0] = *p++;
}
int c1s1_strategy_schema0::parse(char* _c1s1, int size)
{
int ret = ERROR_SUCCESS;
srs_assert(size == 1536);
/* 构造一个字节流 */
SrsStream stream;
if ((ret = stream.initialize(_c1s1 + 8, 764)) != ERROR_SUCCESS) {
return ret;
}
if ((ret = key.parse(&stream)) != ERROR_SUCCESS) {
srs_error("parse the c1 key failed. ret=%d", ret);
return ret;
}
if ((ret = stream.initialize(_c1s1 + 8 + 764, 764)) != ERROR_SUCCESS) {
return ret;
}
if ((ret = digest.parse(&stream)) != ERROR_SUCCESS) {
srs_error("parse the c1 digest failed. ret=%d", ret);
return ret;
}
srs_verbose("parse c1 key-digest success");
return ret;
}
/**
* 764 bytes key 结构:
* - random-data: (offset) bytes
* - key-data: 128 bytes
* - random-data: (764 - offset - 128 - 4) bytes
* - offset: 4 bytes
*/
int key_block::parse(SrsStream* stream)
{
int ret = ERROR_SUCCESS;
// the key must be 764 bytes
srs_assert(stream->require(764));
/* 读取 key 结构中的 4 字节 offset 值 */
// read the last offset first, 760-763
stream->skip(764 - sizeof(int32_t));
offset = stream->read_4bytes();
// reset stream to read others.
stream->skip(-764);
/* 计算 offset 值 */
int valid_offset = calc_valid_offset();
srs_assert(valid_offset >= 0);
random0_size = valid_offset;
if (random0_size > 0) {
srs_freepa(random0);
random0 = new char[random0_size];
stream->read_bytes(random0, random0_size);
}
/* 读取 128 字节的 key */
stream->read_bytes(key, 128);
random1_size = 764 - valid_offset - 128 - 4;
if (random1_size > 0) {
srs_freepa(random1);
random1 = new char[random1_size];
stream->read_bytes(random1, random1_size);
}
return ret;
}
int key_block::calc_valid_offset()
{
int max_offset_size = 764 - 128 - 4;
int valid_offset = 0;
u_int8_t* pp = (u_int8_t*)&offset;
valid_offset += *pp++;
valid_offset += *pp++;
valid_offset += *pp++;
valid_offset += *pp++;
return valid_offset % max_offset_size;
}
/**
* 764 bytes digest结构:
* - offset: 4 bytes
* - random-data: (offset) bytes
* - digest-data: 32 bytes
* - random-data: (764 - 4 - offset - 32) bytes
*/
int digest_block::parse(SrsStream* stream)
{
int ret = ERROR_SUCCESS;
// the digest must be 764 bytes.
srs_assert(stream->require(764));
offset = stream->read_4bytes();
int valid_offset = calc_valid_offset();
srs_assert(valid_offset >= 0);
random0_size = valid_offset;
if (random0_size > 0) {
srs_freepa(random0);
random0 = new char[random0_size];
stream->read_bytes(random0, random0_size);
}
/* 读取 32 字节的 digest */
stream->read_bytes(digest, 32);
random1_size = 764 - 4 - valid_offset - 32;
if (random1_size > 0) {
srs_freepa(random1);
random1 = new char[random1_size];
stream->read_bytes(random1, random1_size);
}
return ret;
}
int c1s1::c1_validate_digest(bool& is_valid)
{
is_valid = false;
srs_assert(payload);
/* 由于子类 c1s1_strategy_schema0/c1s1_strategy_schema1 没有实现
* c1_validate_digest,因此调用父类 c1s1_strategy 的 c1_validate_digest*/
return payload->c1_validate_digest(this, is_valid);
}
int c1s1_strategy::c1_validate_digest(c1s1* owner, bool& is_valid)
{
int ret = ERROR_SUCCESS;
char* c1_digest = NULL;
if ((ret = calc_c1_digest(owner, c1_digest)) != ERROR_SUCCESS) {
srs_error("validate c1 error, failed to calc digest. ret=%d", ret);
return ret;
}
srs_assert(c1_digest != NULL);
SrsAutoFreeA(char, c1_digest);
/* 比较两个 digest 是否一致 */
is_valie = srs_bytes_equals(digest.digest, c1_digest, 32);
return ret;
}
int c1s1_strategy::calc_c1_digest(c1s1* owner, char*& c1_digest)
{
int ret = ERROR_SUCCESS;
/**
* c1s1 is splited by digest:
* c1s1-part1: n bytes (time, version, key and digest-part1).
* digest-data: 32 bytes
* c1s1-part2: (1536 - n - 32) bytes (digest-part2)
* @return a new allocated bytes, user must free it.
*/
char* c1s1_joined_bytes = new char[1536 - 32];
/* 构造自动释放内存的类,当该函数返回时,自动释放 c1s1_joined_bytes 的资源 */
SrsAutoFreeA(char, c1s1_joined_bytes);
if ((ret = copy_to(owner, c1s1_joined_bytes, 1536 - 32, false)) != ERROR_SUCCESS) {
return ret;
}
c1_digest = new char[SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(SrsGenuineFPKey, 30, c1s1_joined_bytes,
1536 - 32, c1_digest))
!= ERROR_SUCCESS) {
srs_freepa(c1_digest);
srs_error("calc digest for c1 failed. ret=%d", ret);
return ret;
}
srs_verbose("digest calculated for c1");
return ret;
}
标签:eset happy when try base tor OLE code sse
原文地址:https://www.cnblogs.com/jimodetiantang/p/9061380.html