微操征霸
351.42M · 2026-02-04
RTSPS(RTSP over TLS/SSL)本质就是:把明文的 RTSP 协议,套上一层 TLS/SSL 的加密隧道传输。所有 RTSP 的核心业务逻辑完全不需要改, 只需要改「传输层」的配置,不改「应用层」的 RTSP 协议逻辑
| 项 | RTSP(明文) | RTSPs (加密) |
|---|---|---|
| 本质 | 明文RTSP协议 | RTSP + TLS/SSL 加密隧道 |
| 默认端口 | TCP/UDP 554 | 仅 TCP 322 (标准端口) |
| 传输协议 | 支持 TCP / UDP | 强制只能用 TCP |
| 数据传输 | 所有报文明文传输 | 所有报文 TLS 加密传输 |
| URL | 前缀 rtsp:// | rtsps:// |
| 安全性 | 低(易抓包 / 篡改) | 高(加密防窃听 / 篡改) |
Transport: RTP/AVP/TCP;unicast;interleaved=%d-%d
SSL_write()/SSL_read() 替代原有的 send()/recv() 收发 RTSP 报文由于socket是非阻塞的, 使用epoll的事件连接状态,所以SSL_connect也需要设置为非阻塞的,并且需要放到epoll的socket连接成功后调用, 封装:
#ifndef CRYPTO_SSL_SOCKET_H_
#define CRYPTO_SSL_SOCKET_H_
#include <unordered_map>
#include "openssl/ssl.h"
#include <memory>
#include "Singleton.h"
#include <mutex>
#include <atomic>
#include "openssl/ssl.h"
#include "openssl/err.h"
// SSL连接状态
typedef enum {
SSL_STATE_NOT_STARTED = 0, // SSL未开始
SSL_STATE_CONNECTING = 1, // SSL连接进行中
SSL_STATE_CONNECTED = 2, // SSL连接已建立
SSL_STATE_FAILED = -1, // SSL连接失败
} SSLConnectionState;
// SSL配置参数
typedef struct {
bool verify_peer = false; // 是否验证对端证书
const char* ca_cert_path = nullptr; // CA证书路径
const char* cipher_list = nullptr; // 密码套件列表
} SSLConfig;
// SSL连接上下文
struct SSLConnection {
std::atomic<int> socket_fd{-1}; // Socket文件描述符
std::recursive_mutex ssl_mutex;
SSL* ssl = nullptr; // SSL对象
SSL_CTX* ssl_ctx = nullptr; // SSL上下文
std::atomic<SSLConnectionState> state{SSL_STATE_NOT_STARTED}; // 当前状态
SSLConfig config; // SSL配置
};
class SSLSocket
{
friend class CSingleton<SSLSocket>;
public:
bool startAsyncConnect(int socket_fd);
void closeConnection(int socket_fd);
bool isSupportSSL(int socket_fd);
// 主动推进SSL握手
bool connect(int socket_fd);
int recvData(int socket_fd, void* buffer, size_t length);
int sendData(int socket_fd, const void* data, size_t length);
int getConnectState(int socket_fd);
private:
SSLSocket();
~SSLSocket();
SSLSocket(const SSLSocket&) = delete;
SSLSocket& operator=(const SSLSocket&) = delete;
bool createSSLContext(std::shared_ptr<SSLConnection> conn); // 创建ssl上下文
bool setupSSLConnection(std::shared_ptr<SSLConnection> conn); // 设置异步ssl连接
bool performHandshakeStep(std::shared_ptr<SSLConnection> conn); // 握手
void cleanupConnection(std::shared_ptr<SSLConnection> conn);
private:
mutable std::recursive_mutex m_mutexSSLConnect;
std::unordered_map<int, std::shared_ptr<SSLConnection>> m_sslConnectMap;
};
#endif /* CRYPTO_SSL_SOCKET_H_ */
#include "SSLSocket.h"
#include <iostream>
#include <sstream>
#include <string.h>
void logSSLInfo(std::shared_ptr<SSLConnection> conn,const char* message) {
std::stringstream ss;
if (conn) {
ss << "[SSL FD=" << conn->socket_fd << "] ";
}
ss << message;
// 这里可以替换为你的日志系统
std::cout << "INFO: " << ss.str() << std::endl;
}
void logSSLErr(const char* message,std::shared_ptr<SSLConnection> conn=nullptr) {
std::stringstream ss;
if (conn) {
ss << "[SSL FD=" << conn->socket_fd << "] ";
}
ss << message;
// 这里可以替换为你的日志系统
std::cout << "ERROR: " << ss.str() << std::endl;
}
SSLSocket::SSLSocket()
{
ERR_load_CRYPTO_strings();
SSL_load_error_strings();
std::string verison = "OpenSSL Version=" + std::string(OPENSSL_VERSION_TEXT);
logSSLInfo(nullptr,verison.c_str());
}
SSLSocket::~SSLSocket()
{
std::lock_guard<std::recursive_mutex> lock(m_mutexSSLConnect);
// 清理所有连接
for (auto& pair : m_sslConnectMap) {
cleanupConnection(pair.second);
}
m_sslConnectMap.clear();
}
bool SSLSocket::startAsyncConnect(int socket_fd)
{
if (socket_fd < 0) {
logSSLErr("Invalid socket file descriptor");
return false;
}
// 创建连接上下文
auto conn = std::make_shared<SSLConnection>();
conn->socket_fd = socket_fd;
conn->state = SSL_STATE_NOT_STARTED;
{
std::lock_guard<std::recursive_mutex> lock(conn->ssl_mutex);
// 创建SSL上下文
if (!createSSLContext(conn)) {
logSSLErr("Failed to create SSL context");
return false;
}
// 设置SSL连接
if (!setupSSLConnection(conn)) {
// 释放SSL上下文
if (conn->ssl_ctx) {
SSL_CTX_free(conn->ssl_ctx);
conn->ssl_ctx = nullptr;
}
logSSLErr("Failed to setup SSL connection");
return false;
}
}
// 保存连接
{
std::lock_guard<std::recursive_mutex> lock(m_mutexSSLConnect);
auto it = m_sslConnectMap.find(socket_fd);
if( it != m_sslConnectMap.end())
{
cleanupConnection(it->second);
}
m_sslConnectMap[socket_fd] = conn;
}
logSSLInfo(conn, "SSL async connection started");
return true;
}
void SSLSocket::closeConnection(int socket_fd)
{
std::lock_guard<std::recursive_mutex> lock(m_mutexSSLConnect);
auto it = m_sslConnectMap.find(socket_fd);
if (it != m_sslConnectMap.end()) {
cleanupConnection(it->second);
}
}
bool SSLSocket::isSupportSSL(int socket_fd)
{
std::lock_guard<std::recursive_mutex> lock(m_mutexSSLConnect);
auto it = m_sslConnectMap.find(socket_fd);
if (it != m_sslConnectMap.end()) {
return true;
}
return false;
}
bool SSLSocket::createSSLContext(std::shared_ptr<SSLConnection> conn)
{
// 使用兼容性最好的方法
const SSL_METHOD* method = TLS_client_method();
if (!method) {
logSSLErr("Failed to create TLS client method");
return false;
}
conn->ssl_ctx = SSL_CTX_new(method);
if (!conn->ssl_ctx) {
logSSLErr("Failed to create SSL_CTX");
return false;
}
// 配置SSL上下文
SSL_CTX_set_verify(conn->ssl_ctx, SSL_VERIFY_NONE, NULL); // 不验证证书
SSL_CTX_set_verify_depth(conn->ssl_ctx, 0);
// 设置密码套件
if (conn->config.cipher_list && strlen(conn->config.cipher_list) > 0) {
if (!SSL_CTX_set_cipher_list(conn->ssl_ctx, conn->config.cipher_list)) {
logSSLErr("Failed to set cipher list, using default",conn);
}
}
// 设置CA证书(如果提供)
if (conn->config.verify_peer && conn->config.ca_cert_path) {
if (!SSL_CTX_load_verify_locations(conn->ssl_ctx,
conn->config.ca_cert_path,
NULL)) {
logSSLErr("Failed to load CA certificates",conn);
}
}
return true;
}
bool SSLSocket::setupSSLConnection(std::shared_ptr<SSLConnection> conn)
{
conn->ssl = SSL_new(conn->ssl_ctx);
if (!conn->ssl) {
logSSLErr("Failed to create SSL object");
return false;
}
// 关联socket
if (SSL_set_fd(conn->ssl, conn->socket_fd) != 1) {
logSSLErr("Failed to set SSL fd");
SSL_free(conn->ssl);
conn->ssl = nullptr;
return false;
}
// 设置非阻塞模式
SSL_set_mode(conn->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
return true;
}
void SSLSocket::cleanupConnection(std::shared_ptr<SSLConnection> conn)
{
if (!conn) return;
{
std::lock_guard<std::recursive_mutex> lock(conn->ssl_mutex);
// 关闭SSL连接
if (conn->ssl) {
SSL_shutdown(conn->ssl);
SSL_free(conn->ssl);
conn->ssl = nullptr;
}
// 释放SSL上下文
if (conn->ssl_ctx) {
SSL_CTX_free(conn->ssl_ctx);
conn->ssl_ctx = nullptr;
}
}
// 从连接表中移除
if (conn->socket_fd > 0) {
std::lock_guard<std::recursive_mutex> lock(m_mutexSSLConnect);
m_sslConnectMap.erase(conn->socket_fd);
}
}
bool SSLSocket::connect(int socket_fd)
{
std::shared_ptr<SSLConnection> conn = nullptr;
{
std::lock_guard<std::recursive_mutex> lock(m_mutexSSLConnect);
auto it = m_sslConnectMap.find(socket_fd);
if (it == m_sslConnectMap.end()) {
logSSLErr(std::string("Connection not found for fd: " + std::to_string(socket_fd)).c_str());
return false;
}
conn = it->second;
}
switch (conn->state) {
case SSL_STATE_NOT_STARTED:
// 首次握手尝试
conn->state = SSL_STATE_CONNECTING;
logSSLInfo(conn, "Starting SSL handshake");
// 继续执行握手
case SSL_STATE_CONNECTING:
// 执行握手步骤
return performHandshakeStep(conn);
case SSL_STATE_CONNECTED:
// 连接已建立,处理正常数据
return true;
default:
logSSLErr(std::string("Invalid SSL state: " + std::to_string(conn->state)).c_str());
return false;
}
return false;
}
bool SSLSocket::performHandshakeStep(std::shared_ptr<SSLConnection> conn)
{
std::lock_guard<std::recursive_mutex> lock(conn->ssl_mutex);
if (!conn || !conn->ssl) {
logSSLErr("Invalid SSL connection or SSL object is null");
return false;
}
if(conn->state == SSL_STATE_CONNECTED)
{
return true;
}
int ret = SSL_connect(conn->ssl);
if (ret == 1) {
// 握手成功
conn->state = SSL_STATE_CONNECTED;
std::stringstream ss;
ss << "Connect Succesed version: " << SSL_get_version(conn->ssl);
ss << " Cipher: " << SSL_get_cipher(conn->ssl);
logSSLInfo(conn, ss.str().c_str());
return true;
} else {
// 握手需要更多步骤
int ssl_error = SSL_get_error(conn->ssl, ret);
switch (ssl_error) {
case SSL_ERROR_WANT_READ:
logSSLInfo(conn, "SSL handshake needs more data to read");
break;
case SSL_ERROR_WANT_WRITE:
logSSLInfo(conn, "SSL handshake needs to write more data");
break;
case SSL_ERROR_SYSCALL:
if (ERR_peek_error() == 0) {
if (ret == 0) {
logSSLErr("SSL connection closed by peer");
} else {
logSSLErr(std::string("SSL syscall error: " + std::string(strerror(errno))).c_str());
}
} else {
logSSLErr("SSL syscall error",conn);
}
conn->state = SSL_STATE_FAILED;
break;
case SSL_ERROR_SSL:
logSSLErr("SSL protocol error",conn);
conn->state = SSL_STATE_FAILED;
break;
default:
logSSLErr(std::string("Unknown SSL error: " + std::to_string(ssl_error)).c_str());
conn->state = SSL_STATE_FAILED;
break;
}
}
// 握手仍在进行中
return false;
}
int SSLSocket::recvData(int socket_fd, void* buffer, size_t length)
{
std::shared_ptr<SSLConnection> conn = nullptr;
{
std::lock_guard<std::recursive_mutex> lock(m_mutexSSLConnect);
auto it = m_sslConnectMap.find(socket_fd);
if (it == m_sslConnectMap.end() || it->second->state != SSL_STATE_CONNECTED) {
logSSLErr("SSL connection not ready for receiving");
return -1;
}
conn = it->second;
}
{
std::lock_guard<std::recursive_mutex> lock(conn->ssl_mutex);
if(!conn->ssl)
{
return -1;
}
return SSL_read(conn->ssl, buffer, length);
}
}
int SSLSocket::sendData(int socket_fd, const void* data, size_t length)
{
std::shared_ptr<SSLConnection> conn = nullptr;
{
std::lock_guard<std::recursive_mutex> lock(m_mutexSSLConnect);
auto it = m_sslConnectMap.find(socket_fd);
if (it == m_sslConnectMap.end() || it->second->state != SSL_STATE_CONNECTED) {
logSSLErr("SSL connection not ready for sending");
return -1;
}
conn = it->second;
}
{
std::lock_guard<std::recursive_mutex> lock(conn->ssl_mutex);
if(!conn->ssl)
{
return -1;
}
return SSL_write(conn->ssl, data, length);
}
}
int SSLSocket::getConnectState(int socket_fd)
{
std::lock_guard<std::recursive_mutex> lock(m_mutexSSLConnect);
auto it = m_sslConnectMap.find(socket_fd);
if (it == m_sslConnectMap.end()) {
return -1;
}
return it->second->state;
}