码迷,mamicode.com
首页 > 其他好文 > 详细

SRS之RTMP handshake

时间:2018-05-20 22:49:40      阅读:722      评论:0      收藏:0      [点我收藏+]

标签:eset   happy   when   try   base   tor   OLE   code   sse   

1. SrsRtmpServer::handshake

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;
}

2. complex handshake

2.1 相关类定义

2.1.1 SrsComplexHandshake 类定义

/**
 * 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。

2.1.2 SrsHandshakeBytes 类定义

/**
 * 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 过程数据包的方法。

2.1.3 ISrsProtocolReaderWriter 类定义

/**
 * 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;
};
ISrsProtocolReaderWriter 与其父类还有子类关系图

技术分享图片

2.2 SrsComplexHandshake::handshake_with_client

// 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;
}

2.3 SrsHandshakeBytes::read_c0c1

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;
}

recv: c0c1

技术分享图片

2.3.1 SrsStSocket::read_fully

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;
}

2.3.2 st_read_fully

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;
}

2.3.3 st_read_resid

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;
}

2.3.4 st_readv_resid

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;
}

2.4 decode c1: try schem0(key-digest sequence)

2.4.1 c1s1 类

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);
    };
    ...
}

2.4.2 c1s1_strategy 类

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);
    };
    
    ...
}

2.4.3 c1s1::parse

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);
}

2.4.5 SrsStream::initialize

/**
 * 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;
}

2.4.6 SrsStream::read_4bytes

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++;
}

2.4.7 c1s1_strategy_schema0::parse

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;
}

2.4.8 key_block::parse

/**
 * 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;
}

2.4.9 key_block::calc_valid_offset

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;
}

2.4.10 digest_block::parse

/**
 * 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;
}

2.5 c1s1::c1_validate_digest

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);
}

2.5.1 c1s1_strategy::c1_validate_digest

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;
}

2.5.2 c1s1_strategy::calc_c1_digest

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;
}

SRS之RTMP handshake

标签:eset   happy   when   try   base   tor   OLE   code   sse   

原文地址:https://www.cnblogs.com/jimodetiantang/p/9061380.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!