wfb-ng 开源代码之wfb_tx&wfb_rx

1. 源由

《wfb-ng 开源工程结构&代码框架简明介绍》中已经简单介绍了工程框架。

接下来,就针对代码的一些研读,以及基于源码的基本功能了解。

2. 目标

  • wfb_rx: src/rx.o src/radiotap.o src/fec.o src/wifibroadcast.o
  • wfb_tx: src/tx.o src/fec.o src/wifibroadcast.o
  • wfb_keygen: src/keygen.o
  • wfb_tx_cmd: src/tx_cmd.o
  • python tools
    • wfb-cli:执行 wfb_ng.cli 模块中的 main 函数
    • wfb-test-latency:执行 wfb_ng.latency_test 模块中的 main 函数
    • wfb-server:执行 wfb_ng.server 模块中的 main 函数
    • wfb-log-parser:执行 wfb_ng.log_parser 模块中的 main 函数

注:本章重点介绍c源代码生成的目标代码wfb_rxwfb_tx

3. wfb_rx

main(int argc, char* const *argv)
│
├── 初始化变量
│   ├── int opt
│   ├── uint8_t radio_port
│   ├── uint32_t link_id
│   ├── uint64_t epoch
│   ├── int log_interval
│   ├── int client_port
│   ├── int srv_port
│   ├── string client_addr
│   ├── rx_mode_t rx_mode
│   ├── int rcv_buf
│   └── string keypair
│
├── 处理命令行参数 (while getopt)
│   ├── case 'K': 设置 keypair
│   ├── case 'f': 设置 rx_mode 为 FORWARDER
│   ├── case 'a': 设置 rx_mode 为 AGGREGATOR 和 srv_port
│   ├── case 'c': 设置 client_addr
│   ├── case 'u': 设置 client_port
│   ├── case 'p': 设置 radio_port
│   ├── case 'R': 设置 rcv_buf
│   ├── case 'l': 设置 log_interval
│   ├── case 'i': 设置 link_id
│   ├── case 'e': 设置 epoch
│   └── default: 显示用法信息并退出
│
├── 检查系统熵池 (open "/dev/random")
│   └── 如果熵不足, 显示警告信息
│
├── 初始化 Libsodium 库 (sodium_init)
│   └── 如果初始化失败, 显示错误信息并退出
│
├── 主逻辑 (try-catch)
│   ├── 计算 channel_id
│   │
│   ├── 根据 rx_mode 分支逻辑
│   │   ├── if rx_mode == LOCAL or FORWARDER
│   │   │   ├── 检查命令行参数 (optind)
│   │   │   ├── 创建 Aggregator 或 Forwarder 实例
│   │   │   ├── 调用 radio_loop 处理接收逻辑
│   │   │
│   │   ├── else if rx_mode == AGGREGATOR
│   │   │   ├── 检查命令行参数 (optind)
│   │   │   ├── 创建 Aggregator 实例
│   │   │   ├── 调用 network_loop 处理网络通信
│   │   │
│   │   └── else
│   │       └── 抛出未知 rx_mode 异常
│   │
│   └── 捕获 runtime_error 异常并显示错误信息
│
└── return 0 表示程序正常结束

3.1 rx_mode(LOCAL)

通过wfb-ng物理RF网卡接收数据,加密解包,并绑定五元组[UDP, client_addr, client_port]

WiFi broadcast – secure line --> client[client_addr, client_port]

LOCAL
 ├──> Aggregator(client_addr, client_port, keypair, epoch, channel_id)
 └──> radio_loop(argc, argv, optind, channel_id, agg, log_interval)
     └──> Receiver::loop_iter
         └──> Aggregator::process_packet(pkt + sizeof(ieee80211_header), pktlen - sizeof(ieee80211_header), 
                                         wlan_idx, antenna, rssi, noise, freq, mcs_index, bandwidth, NULL)

3.2 rx_mode(FORWARDER)

通过wfb-ng物理RF网卡接收数据,并绑定五元组[UDP, client_addr, client_port]

WiFi broadcast – local udp --> client[client_addr, client_port]

FORWARDER
 ├──> Forwarder(client_addr, client_port)
 └──> radio_loop(argc, argv, optind, channel_id, agg, log_interval)
     └──> Receiver::loop_iter
         └──> Forwarder::process_packet(pkt + sizeof(ieee80211_header), pktlen - sizeof(ieee80211_header), 
                                        wlan_idx, antenna, rssi, noise, freq, mcs_index, bandwidth, NULL)

3.3 rx_mode(AGGREGATOR)

本地启动UDP server[srv_port]监听报文,加密解包,并绑定五元组[UDP, client_addr, client_port]

  • Local ethernet udp – secure line --> client[client_addr, client_port]
AGGREGATOR
 ├──> Aggregator(client_addr, client_port, keypair, epoch, channel_id)
 └──> network_loop(srv_port, agg, log_interval, rcv_buf)
     └──> Aggregator::process_packet(buf, rsize - sizeof(wrxfwd_t),
                                     fwd_hdr.wlan_idx, fwd_hdr.antenna,
                                     fwd_hdr.rssi, fwd_hdr.noise, ntohs(fwd_hdr.freq),
                                     fwd_hdr.mcs_index, fwd_hdr.bandwidth, &sockaddr)

4. wfb_tx

main(int argc, char * const *argv)
│
├── 初始化变量
│   ├── int opt
│   ├── uint8_t k, n, radio_port
│   ├── uint32_t fec_delay, link_id
│   ├── uint64_t epoch
│   ├── int udp_port, control_port, log_interval
│   ├── int bandwidth, short_gi, stbc, ldpc, mcs_index, vht_nss, debug_port, fec_timeout, rcv_buf
│   ├── bool mirror, vht_mode
│   ├── string keypair
│   ├── uint8_t frame_type
│   ├── bool use_qdisc
│   └── uint32_t fwmark
│
├── 处理命令行参数 (while getopt)
│   ├── case 'K': 设置 keypair
│   ├── case 'k': 设置 k
│   ├── case 'n': 设置 n
│   ├── case 'u': 设置 udp_port
│   ├── case 'p': 设置 radio_port
│   ├── case 'F': 设置 fec_delay
│   ├── case 'R': 设置 rcv_buf
│   ├── case 'B': 设置 bandwidth (强制 VHT 模式如果 bandwidth >= 80)
│   ├── case 'G': 设置 short_gi
│   ├── case 'S': 设置 stbc
│   ├── case 'L': 设置 ldpc
│   ├── case 'M': 设置 mcs_index
│   ├── case 'N': 设置 vht_nss
│   ├── case 'D': 设置 debug_port
│   ├── case 'T': 设置 fec_timeout
│   ├── case 'l': 设置 log_interval
│   ├── case 'i': 设置 link_id
│   ├── case 'e': 设置 epoch
│   ├── case 'm': 启用 mirror 模式
│   ├── case 'V': 启用 VHT 模式
│   ├── case 'f': 设置 frame_type (data 或 rts)
│   ├── case 'Q': 启用 use_qdisc
│   ├── case 'P': 设置 fwmark
│   ├── case 'C': 设置 control_port
│   └── default: 显示使用信息并退出
│
├── 检查系统熵池 (open "/dev/random")
│   └── 如果熵不足, 显示警告信息
│
├── 初始化 Libsodium 库 (sodium_init)
│   └── 如果初始化失败, 显示错误信息并退出
│
├── 主逻辑 (try-catch)
│   ├── 初始化 radiotap_header
│   │
│   ├── 初始化控制端口 (open_udp_socket_for_rx)
│   │   └── 如果 control_port 为 0, 获取实际绑定的端口号
│   │
│   ├── 处理每个网络接口 (for loop over interfaces)
│   │   ├── 创建 UDP 接收套接字 (open_udp_socket_for_rx)
│   │   ├── 记录绑定的端口号和接口名称
│   │   └── 添加到 rx_fd 和 wlans 列表
│   │
│   ├── 初始化 Transmitter 对象
│   │   ├── 如果启用 debug_port, 使用 UdpTransmitter
│   │   └── 否则, 使用 RawSocketTransmitter
│   │
│   └── 启动数据源处理 (data_source)
│       └── 传递 Transmitter 对象和相关参数
│
├── 捕获 runtime_error 异常并显示错误信息
│
└── return 0 表示程序正常结束

4.1 debug

接收本地UDP报文,加密转发到[“127.0.0.1”, debug_port]

Local UDP port[“127.0.0.1”, control_port] – secure line --> Local debug port[“127.0.0.1”, debug_port]

main
 └──> UdpTransmitter(k, n, keypair, "127.0.0.1", debug_port, epoch, channel_id,
     │               fec_delay, tags, use_qdisc, fwmark)
     └──> data_source(t, rx_fd, control_fd, fec_timeout, mirror, log_interval)
         └──> Transmitter::send_packet
             └──> Transmitter::send_block_fragment
                 └──> UdpTransmitter::inject_packet

4.2 WiFi RF

接收本地UDP报文,加密,通过wfb-ng物理RF网卡发送数据

Local UDP port[“127.0.0.1”, control_port] – secure line --> WiFi broadcast

main
 └──> RawSocketTransmitter(k, n, keypair, epoch, channel_id, fec_delay, tags,
     │                     wlans, radiotap_header, frame_type, use_qdisc, fwmark)
     └──> data_source(t, rx_fd, control_fd, fec_timeout, mirror, log_interval)
         └──> Transmitter::send_packet
             └──> Transmitter::send_block_fragment
                 └──> RawSocketTransmitter::inject_packet

5. 重要例程

5.1 radio_loop

检查所有用于wfb-ng的物理网卡接口,如果有事件发生则进行处理。

radio_loop(int argc, char* const *argv, int optind, uint32_t channel_id, shared_ptr<BaseAggregator> agg, int log_interval)
│
├──  初始化变量
│   ├──  int nfds = argc - optind
│   ├──  uint64_t log_send_ts = 0
│   ├──  struct pollfd fds[MAX_RX_INTERFACES]
│   └──  Receiver* rx[MAX_RX_INTERFACES]
│
├──  检查接口数量 (nfds)
│   └──  如果 nfds > MAX_RX_INTERFACES, 抛出异常
│
├──  初始化 fds 和 rx 数组
│   └──  for 循环 (int i = 0; i < nfds; i++)
│       ├──  初始化 rx[i] (new Receiver)
│       └──  设置 fds[i].fd 和 fds[i].events
│
└──  主循环 (无限循环 for(;;))
    ├──  获取当前时间戳 cur_ts = get_time_ms()
    ├──  调用 poll 函数
    │   └──  处理 poll 错误 (rc < 0)
    │       ├──  如果错误类型为 EINTR 或 EAGAIN, 则继续循环
    │       └──  否则抛出异常
    │
    ├──  更新当前时间戳 cur_ts
    ├──  如果达到 log_send_ts 时间, 打印统计数据并更新 log_send_ts
    │
    ├──  如果 poll 超时 (rc == 0), 继续下一次循环
    │
    └──  遍历所有接口 (for 循环)
        ├──  检查接口上的错误事件 (POLLERR 或 POLLNVAL)
        │   ├──  如果有错误事件, 抛出异常
        │
        └──  处理可读事件 (POLLIN)
            ├──  调用 rx[i]->loop_iter()
            └──  减少剩余可处理事件数 rc -= 1

5.2 Receiver::loop_iter

接收ppcap报文,并进行逻辑处理,所有报文头处理以后就是数据包内容。

Receiver::loop_iter
├── 初始化变量和数组
└── 无限循环
    ├── 使用 pcap_next 获取数据包
    ├── 初始化 Radiotap 迭代器
    ├── 迭代 Radiotap 字段
    │   ├── 处理天线索引
    │   ├── 提取频率
    │   ├── 获取 RSSI
    │   ├── 获取噪声水平
    │   ├── 存储标志
    │   ├── 检查自我注入
    │   ├── 提取 MCS 索引和带宽
    │   └── 提取 VHT 参数
    ├── 处理错误
    │   ├── 短数据包
    │   ├── 自我注入
    │   ├── 错误的 FCS
    │   └── Radiotap 头部错误
    └── 处理数据包数据
        └── 调用 agg->process_packet

5.3 network_loop

检查所有用于wfb-ng的网络接口,如果有事件发生则进行处理。

network_loop(int srv_port, Aggregator &agg, int log_interval, int rcv_buf_size)
│
├──  初始化变量
│   ├──  wrxfwd_t fwd_hdr
│   ├──  struct sockaddr_in sockaddr
│   ├──  uint8_t buf[MAX_FORWARDER_PACKET_SIZE]
│   ├──  uint64_t log_send_ts = 0
│   ├──  struct pollfd fds[1]
│   └──  int fd = open_udp_socket_for_rx(srv_port, rcv_buf_size)
│
├──  初始化 fds 数组
│   ├──  memset(fds, '\0', sizeof(fds))
│   └──  设置 fds[0].fd 和 fds[0].events (POLLIN)
│
└──  主循环 (无限循环 for(;;))
    ├──  获取当前时间戳 cur_ts = get_time_ms()
    ├──  调用 poll 函数
    │   └──  处理 poll 错误 (rc < 0)
    │       ├──  如果错误类型为 EINTR 或 EAGAIN, 则继续循环
    │       └──  否则抛出异常
    │
    ├──  更新当前时间戳 cur_ts
    ├──  如果达到 log_send_ts 时间, 打印统计数据并更新 log_send_ts
    │
    ├──  如果 poll 超时 (rc == 0), 继续下一次循环
    │
    └──  检查 poll 事件
        ├──  检查错误事件 (POLLERR 或 POLLNVAL)
        │   ├──  如果有错误事件, 抛出异常
        │
        └──  处理可读事件 (POLLIN)
            ├──  内部循环 (for(;;) 处理挂起的接收数据)
            │   ├──  初始化 sockaddr 和 iov 数组
            │   ├──  初始化 msghdr 结构体
            │   ├──  调用 recvmsg 函数接收数据
            │   │   ├──  如果接收失败 (rsize < 0), 退出内部循环
            │   │   └──  如果接收数据长度不足 (rsize < sizeof(wrxfwd_t)), 输出错误信息并继续内部循环
            │   └──  调用 agg.process_packet 处理接收到的数据包
            └──  处理非阻塞接收错误 (如果 errno 不是 EWOULDBLOCK, 抛出异常)

5.4 data_source

检查数据链路发送数据包,将数据加密后发送到debug端口或者wfb-ng的网络接口

data_source
│
├── 1. 初始化变量
│   ├── 初始化 pollfd 结构体数组 `fds`
│   ├── 初始化统计变量 `count_p_fec_timeouts`, `count_p_incoming`, 等等
│   └── 初始化时间变量 `session_key_announce_ts`, `log_send_ts`, `fec_close_ts`
│
└── 2. 无限循环 for(;;) 处理数据源
    ├── 更新当前时间 `cur_ts`
    ├── 计算 `poll_timeout`
    ├── 调用 `poll` 等待事件
    │   └── 如果 `poll` 返回错误,抛出异常
    │
    ├── 3. 日志超时处理
    │   ├── 如果日志超时,调用 `t->dump_stats` 输出统计数据
    │   ├── 重置统计变量
    │   └── 更新下次日志时间 `log_send_ts`
    │
    ├── 4. 控制 socket 处理
    │   ├── 检查控制 socket 是否有错误
    │   └── 处理控制 socket 的 POLLIN 事件
    │       ├── 循环接收命令请求并处理
    │       ├── 根据不同命令类型(`CMD_SET_FEC`, `CMD_SET_RADIO`, `CMD_GET_FEC`, `CMD_GET_RADIO`)处理
    │       └── 向请求方发送命令响应
    │
    ├── 5. FEC 超时处理
    │   └── 如果 FEC 超时,发送空数据包关闭 FEC 块
    │
    ├── 6. 处理接收到的数据包
    │   ├── 根据上次处理的 fd 索引 `start_fd_idx` 处理数据包
    │   └── 处理每个 fd 的 POLLIN 事件
    │       ├── 接收数据包 `recvmsg`
    │       ├── 更新统计数据 `count_p_incoming`, `count_b_incoming`, 等等
    │       ├── 处理数据包,调用 `t->send_packet`
    │       └── 如果有 FEC 超时,重置超时时间 `fec_close_ts`
    │   
    └── 7. 结束循环,继续下一次事件处理

6. 参考资料

【1】Ardupilot & OpenIPC & 基于WFB-NG构架分析和数据链路思考
【2】wfb-ng 开源工程结构&代码框架简明介绍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值