文章目录
一. 安装
1.1. 下载
- git
git clone https://github.com/coturn/coturn.git
- 压缩包安装
wget https://github.com/coturn/coturn/archive/4.5.0.8.tar.gz
1.2. 安装
cd coturn ./configure make sudo make install
注: 如果编译出错,记得安装相关依赖。
二. 配置
我这里在 /etc 下单独建立了个 turnserver 的目录,将 coturn 配置文件 turnserver.conf 拷贝过来。
sudo mkdir /etc/turnserver sudo cp coturn/examples/etc/turnserver.conf /etc/turnserver/ sudo cp coturn/examples/etc/turn_server_*.pem /etc/turnserver/
配置 /etc/turnserver/turnserver.conf
# TURN 的监听端口,默认 3478 listening-port=3478 # 监听 relay server 的地址 listening-ip=192.168.110.146 # 可以和 listening IP 一样 relay-ip=192.168.110.146 # 同上 external-ip=192.168.110.146 # 输出详细过程 verbose # TURN 消息中可使用 FINGERPRINT fingerprint # 开启长期证书机制 lt-cred-mech # 设置静态账户 user=test:test # realm=mytest # 关闭 TLS 和 DTLS 监听 no-tls no-dtls # 连接的生命周期,默认 10min stale-nonce=600 # 证书和私钥文件 cert=/etc/turnserver/turn_server_cert.pem pkey=/etc/turnserver/turn_server_pkey.pem # 屏蔽 loopback, multicast IP 地址 no-loopback-peers no-multicast-peers # 支持移动 ICE mobility no-cli
三. 启动 & 测试
3.1. Server
turnserver -v -L 192.168.110.146 -a -f -r mytest -c /etc/turnserver/turnserver.conf
- -L 指定 relay 的监听 IP
- -a 使用 long-term credential
- -f fingerprints
- -r 指定 realm
- -c 指定配置文件
3.2. Client
turnutils_uclient -u test -w test -v -y 192.168.110.146
- -u 指定用户名
- -w 指定密码
- -v 详细输出
- -y 使用 client-to-client 连接
看到如下提示则为成功:
0: success: 0x4690 0: Total connect time is 0 1: start_mclient: msz=4, tot_send_msgs=0, tot_recv_msgs=0, tot_send_bytes ~ 0, tot_recv_bytes ~ 0 2: start_mclient: msz=4, tot_send_msgs=0, tot_recv_msgs=0, tot_send_bytes ~ 0, tot_recv_bytes ~ 0 3: start_mclient: msz=4, tot_send_msgs=1, tot_recv_msgs=1, tot_send_bytes ~ 100, tot_recv_bytes ~ 100 4: start_mclient: msz=4, tot_send_msgs=10, tot_recv_msgs=10, tot_send_bytes ~ 1000, tot_recv_bytes ~ 1000 5: start_mclient: msz=4, tot_send_msgs=15, tot_recv_msgs=15, tot_send_bytes ~ 1500, tot_recv_bytes ~ 1500 5: done, connection 0x1fcd600 closed. 5: done, connection 0x7f40c0d10010 closed. 5: done, connection 0x7f40c0b9a010 closed. 5: done, connection 0x7f40c0bbb010 closed. 5: start_mclient: tot_send_msgs=20, tot_recv_msgs=20 5: start_mclient: tot_send_bytes ~ 2000, tot_recv_bytes ~ 2000 5: Total transmit time is 5 5: Total lost packets 0 (0.000000%), total send dropped 0 (0.000000%) 5: Average round trip delay 0.000000 ms; min = 0 ms, max = 0 ms 5: Average jitter 0. ms; min = 0 ms, max = 2 ms
四. 代码流程
注: 基于 coturn-4.5.0.8 版本
4.1. 大体框架涉及的函数
...各种初始化 read_config_file() // 读取配置文件 setup_server() // 设置 -> setup_listener() -> turnipports_create() // 设置 turn 端口范围 -> turn_event_base_new() // event -> allocate_relay_addrs_ports() // relay 地址 -> setup_listener() -> setup_general_relay_servers() // 设置 relay -> setup_auth_server() // 认证相关
4.2. 设置 relay 相关
setup_general_relay_servers() -> setup_relay_server() -> relay_receive_message() -> handle_relay_message() // 读取 event 发往 relay 的消息 -> open_client_connection_session() -> client_input_handler() -> read_client_connection() -> handle_turn_command() // 处理 TURN 协议的各种请求或数据发送与接收 -> write_client_connection() // 返回数据给 Client
- 设置 event 的回调函数 relay_receive_message()
- relay_receive_message() 循环从 event buffer 中读取数据交给 handle_relay_message()
4.3. 处理请求或数据
handle_turn_command(server, ss, in_buffer, nbh, &resp_constructed, can_resume);
handle_turn_command() -> stun_is_request_str() // 判断 method 是否是请求 -> handle_turn_allocate() // 处理 Allocate Request -> handle_turn_create_permission() // 处理 CreatePermission Request -> handle_turn_refresh() // 处理 Refresh Request -> handle_turn_channel_bind() // 处理 ChannelBind Request -> stun_is_indication_str() // 判断 method 是否是数据 -> handle_turn_send() // 处理 Send Request
- nbh 是从 server 的 ioa_engine_handle 结构的 bufs 中创建并传入进来的
- 处理结束后,将
resp_constructed的值赋为 1。
struct _ioa_engine {
super_memory_t *sm; struct event_base *event_base; int deallocate_eb; int verbose; turnipports* tp; rtcp_map *map_rtcp; stun_buffer_list bufs; // ... }
typedef struct _stun_buffer_list {
stun_buffer_list_elem *head; size_t tsz; } stun_buffer_list;
4.4. 分析请求并构造返回数据
拿 handle_turn_allocate() 举例来说:
handle_turn_allocate(server, ss, &tid, resp_constructed, &err_code, &reason, unknown_attrs, &ua_num, in_buffer, nbh);
handle_turn_allocate() -> stun_attr_get_first_str() // 获取第一个属性 -> stun_attr_get_type() // 依次获取其他属性 -> stun_attr_get_len() // 获取属性长度 -> stun_attr_get_value() // 获取属性 value -> stun_set_allocate_response_str() // 创建返回数据 -> stun_attr_add_addr_str() // 添加各种属性
- 读取 in_buffer 中的 nbh 结构
- 将 nbh 强转为
stun_buffer_list_elem结构,其中 next 是链表的指针,buf 承载属性等信息,根据 len 和 offset 来获取属性信息 - 填充 nbh 结构,用于返回数据
typedef struct _stun_buffer_list_elem {
struct _stun_buffer_list_elem *next; stun_buffer buf; } stun_buffer_list_elem;
typedef struct _stun_buffer {
u08bits channel[STUN_CHANNEL_HEADER_LENGTH]; u08bits buf[STUN_BUFFER_SIZE]; size_t len; u16bits offset; u08bits coffset; } stun_buffer;
4.5. 真正的返回数据
write_client_connection(server, ss, nbh, TTL_IGNORE, TOS_IGNORE);
write_client_connection() -> send_data_from_ioa_socket_nbh() -> udp_send() -> sendto()
- 参数中的 nbh 就是前面构造出来的
- udp_send() 使用的 fd 是参数 server 的 client_socket 字段中的 fd
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/205140.html原文链接:https://javaforall.net
