cpp
复制代码
/**
* @file testRemoteP2pCross.cpp
* @brief P2P文件传输程序
* @details 实现基于ICE和SSL的P2P安全文件传输功能
*/
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <thread>
#include <nice/agent.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <glib.h>
class P2PFileTransfer {
private:
NiceAgent* agent;
GMainLoop* loop;
guint stream_id;
SSL_CTX* ssl_ctx;
SSL* ssl;
std::string remote_credentials;
bool is_sender;
// 文件传输缓冲区大小
static const int BUFFER_SIZE = 8192;
public:
P2PFileTransfer(bool sender) : is_sender(sender) {
// 初始化 GLib
g_networking_init();
loop = g_main_loop_new(NULL, FALSE);
// 初始化 ICE agent
agent = nice_agent_new(g_main_loop_get_context(loop),
NICE_COMPATIBILITY_RFC5245);
// 配置 STUN 服务器
g_object_set(G_OBJECT(agent),
"stun-server", "stun.l.google.com",
"stun-server-port", 19302,
NULL);
// 初始化 SSL
initializeSSL();
}
~P2PFileTransfer() {
g_object_unref(agent);
g_main_loop_unref(loop);
SSL_free(ssl);
SSL_CTX_free(ssl_ctx);
}
private:
void initializeSSL() {
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ssl_ctx = SSL_CTX_new(TLS_method());
if (!ssl_ctx) {
throw std::runtime_error("SSL context creation failed");
}
// 配置 SSL 证书和私钥
if (SSL_CTX_use_certificate_file(ssl_ctx, "cert.pem", SSL_FILETYPE_PEM) <= 0) {
throw std::runtime_error("Certificate loading failed");
}
if (SSL_CTX_use_PrivateKey_file(ssl_ctx, "key.pem", SSL_FILETYPE_PEM) <= 0) {
throw std::runtime_error("Private key loading failed");
}
}
static void candidateGatheringDone(NiceAgent* agent, guint stream_id, gpointer data) {
P2PFileTransfer* p2p = static_cast<P2PFileTransfer*>(data);
gchar* local_sdp = nice_agent_generate_local_sdp(agent);
std::cout << "Local SDP:\n" << local_sdp << std::endl;
g_free(local_sdp);
}
static void componentStateChanged(NiceAgent* agent, guint stream_id,
guint component_id, guint state,
gpointer data) {
if (state == NICE_COMPONENT_STATE_READY) {
std::cout << "ICE connection established!" << std::endl;
P2PFileTransfer* p2p = static_cast<P2PFileTransfer*>(data);
p2p->startTransfer();
}
}
public:
void setupConnection() {
// 添加媒体流
stream_id = nice_agent_add_stream(agent, 1);
// 设置回调函数
g_signal_connect(G_OBJECT(agent), "candidate-gathering-done",
G_CALLBACK(candidateGatheringDone), this);
g_signal_connect(G_OBJECT(agent), "component-state-changed",
G_CALLBACK(componentStateChanged), this);
// 开始收集候选者
nice_agent_gather_candidates(agent, stream_id);
// 运行主循环
std::thread loop_thread([this]() {
g_main_loop_run(this->loop);
});
loop_thread.detach();
}
void sendFile(const std::string& filename) {
if (!is_sender) {
throw std::runtime_error("This instance is not configured as sender");
}
std::ifstream file(filename, std::ios::binary);
if (!file) {
throw std::runtime_error("Cannot open file: " + filename);
}
// 首先发送文件名和大小
file.seekg(0, std::ios::end);
size_t filesize = file.tellg();
file.seekg(0, std::ios::beg);
// 发送文件信息
std::string file_info = filename + ":" + std::to_string(filesize);
SSL_write(ssl, file_info.c_str(), file_info.length());
// 发送文件内容
std::vector<char> buffer(BUFFER_SIZE);
while (!file.eof()) {
file.read(buffer.data(), BUFFER_SIZE);
std::streamsize bytes_read = file.gcount();
if (bytes_read > 0) {
SSL_write(ssl, buffer.data(), bytes_read);
}
}
file.close();
}
void receiveFile() {
if (is_sender) {
throw std::runtime_error("This instance is not configured as receiver");
}
// 接收文件信息
char info_buffer[1024];
int bytes = SSL_read(ssl, info_buffer, sizeof(info_buffer));
std::string file_info(info_buffer, bytes);
// 解析文件名和大小
size_t pos = file_info.find(':');
std::string filename = file_info.substr(0, pos);
size_t filesize = std::stoull(file_info.substr(pos + 1));
// 接收文件内容
std::ofstream file(filename, std::ios::binary);
std::vector<char> buffer(BUFFER_SIZE);
size_t total_received = 0;
while (total_received < filesize) {
int bytes = SSL_read(ssl, buffer.data(), BUFFER_SIZE);
if (bytes > 0) {
file.write(buffer.data(), bytes);
total_received += bytes;
}
}
file.close();
}
private:
void startTransfer() {
// 创建 SSL 连接
ssl = SSL_new(ssl_ctx);
// 设置 SSL 为服务器或客户端模式
if (is_sender) {
SSL_set_connect_state(ssl);
} else {
SSL_set_accept_state(ssl);
}
// 开始文件传输
if (is_sender) {
sendFile("example.txt");
} else {
receiveFile();
}
}
};
// 使用示例
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " [send|receive]" << std::endl;
return 1;
}
try {
bool is_sender = std::string(argv[1]) == "send";
P2PFileTransfer p2p(is_sender);
p2p.setupConnection();
// 等待用户输入远程端的连接信息
std::cout << "Enter remote SDP: " << std::endl;
std::string remote_sdp;
std::getline(std::cin, remote_sdp);
// 这里应该处理远程 SDP 并建立连接
// ...
// 保持程序运行
std::string input;
std::getline(std::cin, input);
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}