├── .clang-format
├── .gitmodules
├── CMakeLists.txt
├── ISSUE_TEMPLATE.md
├── LICENSE.md
├── README.md
├── doc
└── README.zh-cn.md
├── images
├── FEC.PNG
├── en
│ ├── init
│ ├── ping_compare.PNG
│ ├── ping_compare2.PNG
│ ├── rs.png
│ ├── scp_compare.PNG
│ └── scp_compare2.PNG
├── init
├── peformance.PNG
├── performance2.PNG
├── restriction.PNG
├── tinyFecVPN.PNG
├── tinyFecVPN2.PNG
├── tinyFecVPN3.PNG
├── tinyFecVPNcn.PNG
└── tinyFecVPNcn2.PNG
├── main.cpp
├── makefile
├── tun_dev.cpp
├── tun_dev.h
├── tun_dev_client.cpp
└── tun_dev_server.cpp
/.clang-format:
--------------------------------------------------------------------------------
1 | SortIncludes: false
2 | BasedOnStyle: Google
3 | ColumnLimit: 0
4 | IndentWidth: 4
5 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "UDPspeeder"]
2 | path = UDPspeeder
3 | url = https://github.com/wangyu-/UDPspeeder.git
4 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | #note: experimental
2 | # currently only used for generating `compile_commands.json` for clangd
3 | # to build this project, it's suggested to use `makefile` instead
4 |
5 | cmake_minimum_required(VERSION 3.7)
6 | project(tinyvpn)
7 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
8 |
9 | set(CMAKE_CXX_STANDARD 11)
10 |
11 | set(SOURCE_FILES
12 | UDPspeeder/log.cpp
13 | UDPspeeder/common.cpp
14 | UDPspeeder/lib/fec.cpp
15 | UDPspeeder/lib/rs.cpp
16 | UDPspeeder/packet.cpp
17 | UDPspeeder/delay_manager.cpp
18 | UDPspeeder/fd_manager.cpp
19 | UDPspeeder/connection.cpp
20 | UDPspeeder/fec_manager.cpp
21 | UDPspeeder/misc.cpp
22 | UDPspeeder/my_ev.cpp
23 | main.cpp
24 | tun_dev_client.cpp
25 | tun_dev_server.cpp
26 | tun_dev.cpp
27 | )
28 | set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-variable -Wno-unused-parameter -Wno-missing-field-initializers -O2 -g -fsanitize=address,undefined")
29 |
30 | #target_include_directories(speederv2 PRIVATE .)
31 | #set(CMAKE_LINK_LIBRARY_FLAG "-lrt")
32 | add_executable(tinyvpn ${SOURCE_FILES})
33 | target_link_libraries(tinyvpn rt)
34 | target_link_libraries(tinyvpn pthread)
35 | include_directories(SYSTEM "UDPspeeder/libev")
36 | include_directories("UDPspeeder")
37 | include_directories(".")
38 |
--------------------------------------------------------------------------------
/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | English Only.
2 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Yu Wang (wangyucn at gmail.com)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # tinyfecVPN
2 |
3 | A Lightweight VPN with Build-in Forward Error Correction Support(or A Network Improving Tool which works at VPN mode). Improves your Network Quality on a High-latency Lossy Link.
4 |
5 | 
6 |
7 | tinyfecVPN uses Forward Error Correction(Reed-Solomon code) to reduce packet loss rate, at the cost of additional bandwidth usage.
8 |
9 | Assume your local network to your server is lossy. Just establish a VPN connection to your server with tinyfecVPN, access your server via this VPN connection, then your connection quality will be significantly improved. With well-tuned parameters , you can easily reduce IP or UDP/ICMP packet-loss-rate to less than 0.01% . Besides reducing packet-loss-rate, tinyfecVPN can also significantly improve your TCP latency and TCP single-thread download speed.
10 |
11 | tinyfecVPN uses same lib as [UDPspeeder](https://github.com/wangyu-/UDPspeeder), supports all FEC features of UDPspeeder. tinyfecVPN works at VPN mode,while UDPspeeder works at UDP tunnel mode.
12 |
13 | [tinyfecVPN wiki](https://github.com/wangyu-/tinyfecVPN/wiki)
14 |
15 | [简体中文](/doc/README.zh-cn.md)
16 |
17 | ##### Note
18 | UDPspeeder's repo:
19 |
20 | https://github.com/wangyu-/UDPspeeder
21 |
22 | # Efficacy
23 | Tested on a link with 100ms roundtrip and 10% packet loss at both direction. You can easily reproduce the test result by yourself.
24 |
25 | ### Ping Packet Loss
26 | 
27 |
28 | ### SCP Copy Speed
29 | 
30 |
31 | # Supported Platforms
32 | Linux host (including desktop Linux,Android phone/tablet, OpenWRT router, or Raspberry PI).Binaries for `amd64` `x86` `mips_be` `mips_le` `arm` are provided.
33 |
34 | For Windows and MacOS, You can run tinyfecVPN inside [this](https://github.com/wangyu-/udp2raw-tunnel/releases/download/20171108.0/lede-17.01.2-x86_virtual_machine_image.zip) 7.5mb virtual machine image.
35 |
36 | Need root or at least CAP_NET_ADMIN permission to run, for creating tun device.
37 |
38 | # How does it work
39 |
40 | tinyfecVPN uses FEC(Forward Error Correction) to reduce packet loss rate, at the cost of additional bandwidth usage. The algorithm for FEC is called Reed-Solomon.
41 |
42 | 
43 |
44 | ### Reed-Solomon
45 |
46 | `
47 | In coding theory, the Reed–Solomon code belongs to the class of non-binary cyclic error-correcting codes. The Reed–Solomon code is based on univariate polynomials over finite fields.
48 | `
49 |
50 | `
51 | It is able to detect and correct multiple symbol errors. By adding t check symbols to the data, a Reed–Solomon code can detect any combination of up to t erroneous symbols, or correct up to ⌊t/2⌋ symbols. As an erasure code, it can correct up to t known erasures, or it can detect and correct combinations of errors and erasures. Reed–Solomon codes are also suitable as multiple-burst bit-error correcting codes, since a sequence of b + 1 consecutive bit errors can affect at most two symbols of size b. The choice of t is up to the designer of the code, and may be selected within wide limits.
52 | `
53 |
54 | 
55 |
56 | Check wikipedia for more info, https://en.wikipedia.org/wiki/Reed–Solomon_error_correction
57 |
58 |
59 | # Getting Started
60 |
61 | ### Installing
62 |
63 | Download binary release from https://github.com/wangyu-/tinyfecVPN/releases
64 |
65 | ### Running
66 |
67 | Assume your server ip is `44.55.66.77`, you have a service listening on udp/tcp port `0.0.0.0:7777`.
68 |
69 | ```
70 | # Run at server side:
71 | ./tinyvpn -s -l0.0.0.0:4096 -f20:10 -k "passwd" --sub-net 10.22.22.0
72 |
73 | # Run at client side
74 | ./tinyvpn -c -r44.55.66.77:4096 -f20:10 -k "passwd" --sub-net 10.22.22.0
75 | ```
76 |
77 | Now, use `10.22.22.1:7777` to connect to your service,all traffic will be improved by FEC. If you ping `10.22.22.1`, you will get ping reply.
78 |
79 | ##### Note
80 |
81 | `-f20:10` means sending 10 redundant packets for every 20 original packets.
82 |
83 | `-k` enables simple XOR encryption
84 |
85 | To create tun device, you need root or cap_net_admin permission. Its suggested to run tinyfecVPN as non-root, check [this link](https://github.com/wangyu-/tinyfecVPN/wiki/run-tinyfecVPN-as-non-root) for more info.
86 |
87 | Currently one server supports only one client. For multiple clients, start multiple servers.
88 |
89 | ##### Note2
90 |
91 | You can use udp2raw with tinyfecVPN together to get better speed on some ISP with UDP QoS(UDP throttling).
92 |
93 | udp2raw's repo:
94 |
95 | https://github.com/wangyu-/udp2raw-tunnel
96 |
97 | # Advanced Topic
98 |
99 | ### Usage
100 | ```
101 | tinyfecVPN
102 | git version: b03df1b586 build date: Oct 31 2017 19:46:50
103 | repository: https://github.com/wangyu-/tinyfecVPN/
104 |
105 | usage:
106 | run as client: ./this_program -c -r server_ip:server_port [options]
107 | run as server: ./this_program -s -l server_listen_ip:server_port [options]
108 |
109 | common options, must be same on both sides:
110 | -k,--key key for simple xor encryption. if not set, xor is disabled
111 | main options:
112 | --sub-net specify sub-net, for example: 192.168.1.0 , default: 10.22.22.0
113 | --tun-dev sepcify tun device name, for example: tun10, default: a random name such as tun987
114 | -f,--fec x:y forward error correction, send y redundant packets for every x packets
115 | --timeout how long could a packet be held in queue before doing fec, unit: ms, default: 8ms
116 | --mode fec-mode,available values: 0, 1; 0 cost less bandwidth, 1 cost less latency;default: 0)
117 | --report turn on send/recv report, and set a period for reporting, unit: s
118 | --keep-reconnect re-connect after lost connection,only for client.
119 | advanced options:
120 | --mtu mtu. for mode 0, the program will split packet to segment smaller than mtu_value.
121 | for mode 1, no packet will be split, the program just check if the mtu is exceed.
122 | default value: 1250
123 | -j,--jitter simulated jitter. randomly delay first packet for 0~ ms, default value: 0.
124 | do not use if you dont know what it means.
125 | -i,--interval scatter each fec group to a interval of ms, to protect burst packet loss.
126 | default value: 0. do not use if you dont know what it means.
127 | --random-drop simulate packet loss, unit: 0.01%. default value: 0
128 | --disable-obscure disable obscure, to save a bit bandwidth and cpu
129 | developer options:
130 | --tun-mtu mtu of the tun interface,most time you shouldnt change this
131 | --disable-mssfix disable mssfix for tcp connection
132 | --fifo use a fifo(named pipe) for sending commands to the running program, so that you
133 | can change fec encode parameters dynamically, check readme.md in repository for
134 | supported commands.
135 | -j ,--jitter jmin:jmax similiar to -j above, but create jitter randomly between jmin and jmax
136 | -i,--interval imin:imax similiar to -i above, but scatter randomly between imin and imax
137 | -q,--queue-len max fec queue len, only for mode 0
138 | --decode-buf size of buffer of fec decoder,u nit: packet, default: 2000
139 | --fix-latency try to stabilize latency, only for mode 0
140 | --delay-capacity max number of delayed packets
141 | --disable-fec completely disable fec, turn the program into a normal udp tunnel
142 | --sock-buf buf size for socket, >=10 and <=10240, unit: kbyte, default: 1024
143 | log and help options:
144 | --log-level 0: never 1: fatal 2: error 3: warn
145 | 4: info (default) 5: debug 6: trace
146 | --log-position enable file name, function name, line number in log
147 | --disable-color disable log color
148 | -h,--help print this help message
149 |
150 | ```
151 | ### FEC Options
152 |
153 | The program supports all options of UDPspeeder,check UDPspeeder repo for details:
154 |
155 | https://github.com/wangyu-/UDPspeeder
156 |
157 | ### Addtional Options
158 |
159 | ##### `--tun-dev`
160 |
161 | Specify a tun device name to use. Example: `--tun-dev tun100`.
162 |
163 | If not set,tinyfecVPN will randomly chose a name,such as `tun987`.
164 |
165 | ##### `--sub-net`
166 |
167 | Specify the sub-net of VPN. Example: `--sub-net 10.10.10.0`, in this way,server IP will be `10.10.10.1`,client IP will be `10.10.10.2`.
168 |
169 | The last number of option should be zero, for exmaple `10.10.10.123` is invalild, and will be corrected automatically to `10.10.10.0`.
170 |
171 | ##### `--keep-reconnect`
172 |
173 | Only works at client side.
174 |
175 | tinyfecVPN server only handles one client at same time,the connection of a new client will kick old client,after being kicked,old client will just exit by default.
176 |
177 | If `--keep-reconnect` is enabled , client will try to get connection back after lost connection or being kicked.
178 |
179 | # Performance Test(throughput)
180 |
181 | Server is a Vulr VPS in japan,CPU: single core 2.4GHz,ram: 512mb. Client is a Bandwagonhost VPS in USA,CPU: single core 2.0GHZ,ram: 96mb. To put pressure on the FEC algorithm, an additional 10% packet-loss rate was introduced at both direction.
182 |
183 | ### Test command
184 |
185 | ```
186 | Server side:
187 | ./tinyvpn_amd64 -s -l 0.0.0.0:5533 --mode 0 -f20:10
188 | iperf3 -s
189 |
190 | Client side:
191 | ./tinyvpn_amd64 -c -r 44.55.66.77:5533 --mode 0 -f20:10
192 | iperf3 -c 10.22.22.1 -P10
193 | ```
194 |
195 | ### Test result
196 |
197 | 
198 |
199 | Note: the performance is mainly limited by the RS code lib.
200 |
201 | # Other
202 |
203 | As a VPN software may contradict with local regulations, I had to introduce an intended restriction in the pre-released binaries: you can only use tinyfecVPN to access your own server.
204 |
205 | You can easily get rid of this restriction by compiling the source code by yourself (take a look at the makefile). This restriction exits only at server side, only the server side binary needs to be compiled by yourself.
206 |
207 | (If you want to compile by yourself, use `git clone --recursive` instead of `git clone`, otherwise the submodule wont be cloned)
208 |
--------------------------------------------------------------------------------
/doc/README.zh-cn.md:
--------------------------------------------------------------------------------
1 | # tinyfecVPN
2 |
3 | 工作在VPN方式的双边网络加速工具,可以加速全流量(TCP/UDP/ICMP)。
4 |
5 | 
6 |
7 | 假设你的本地主机到某个服务器的丢包很高,你只需要用tinyfecVPN建立一条VPN连接,然后透过此VPN来访问server,你的网路质量会得到显著改善。通过合理设置参数,可以轻易把网络丢包率降低到万分之一以下。除了可以降低丢包,还可以显著改善TCP的响应速度,提高TCP的单线程传输速度。
8 |
9 | tinyfecVPN使用了和UDPSpeeder相同的lib,功能和UDPspeeder类似,只不过tinyfecVPN工作方式是VPN,UDPspeeder工作方式是UDP tunnel.
10 |
11 | tinyfecVPN是无状态的点对点VPN, 收到包即连接建立成功;即使VPN断线重连,上层承载的连接不掉线。
12 |
13 | ##### 提示
14 |
15 | UDPspeeder的repo:
16 |
17 | https://github.com/wangyu-/UDPspeeder
18 |
19 | #### 效果
20 | 测试环境是一个有100ms RTT 和双向10%丢包的网络。
21 |
22 | 
23 |
24 | 
25 |
26 | #### 关键词
27 | 双边加速、全流量加速、开源加速器、游戏加速、网游加速器
28 |
29 | # 原理简介
30 |
31 | 主要原理是通过冗余数据来对抗网络的丢包,发送冗余数据的方式支持FEC(Forward Error Correction)和多倍发包,其中FEC算法是Reed-Solomon。
32 |
33 | 原理图:
34 |
35 | 
36 |
37 | 细节请看UDPspeeder的repo,这里不再重复:
38 |
39 | https://github.com/wangyu-/UDPspeeder/
40 |
41 |
42 | # 简明操作说明
43 |
44 | ### 环境要求
45 |
46 | Linux主机,可以是桌面版,可以是android手机/平板,可以是openwrt路由器,也可以是树莓派。(android暂时有问题)
47 |
48 | 在windows和mac上配合虚拟机可以稳定使用(tinyfecVPN跑在Linux里,其他应用照常跑在window里,桥接模式测试可用),可以使用[这个](https://github.com/wangyu-/udp2raw-tunnel/releases/download/20171108.0/lede-17.01.2-x86_virtual_machine_image.zip)虚拟机镜像,大小只有7.5mb,免去在虚拟机里装系统的麻烦;虚拟机自带ssh server,可以scp拷贝文件,可以ssh进去,可以复制粘贴,root密码123456。
49 |
50 | android需要通过terminal运行。
51 |
52 | 需要root或者cap_net_admin权限(因为需要创建tun设备)。
53 |
54 | ###### 注意
55 | 在使用虚拟机时,建议手动指定桥接到哪个网卡,不要设置成自动。否则可能会桥接到错误的网卡。
56 |
57 | # 简明操作说明
58 |
59 | ### 安装
60 |
61 | 下载编译好的二进制文件,解压到本地和服务器的任意目录。
62 |
63 | https://github.com/wangyu-/tinyfecVPN/releases
64 |
65 | ### 运行
66 |
67 | 假设你有一个server,ip为44.55.66.77,有一个服务监听tcp/udp 0.0.0.0:7777。
68 |
69 | ```
70 | # 在server端运行:
71 | ./tinyvpn -s -l0.0.0.0:4096 -f20:10 -k "passwd" --sub-net 10.22.22.0
72 |
73 | # 在client端运行:
74 | ./tinyvpn -c -r44.55.66.77:4096 -f20:10 -k "passwd" --sub-net 10.22.22.0
75 |
76 | ```
77 |
78 | 现在,只要在客户端使用10.22.22.1:7777就可以连上你的服务了,来回的流量都会被加速。执行ping 10.22.22.1也会得到回复。
79 |
80 | ###### 备注:
81 |
82 | `-f20:10`表示对每20个原始数据发送10个冗余包。`-f20:10` 和`-f 20:10`都是可以的,空格可以省略,对于所有的单字节option都是如此。对于双字节option,例如后面会提到的`--mode 0`,空格不可以省略。
83 |
84 | `-k` 指定一个字符串,开启简单的异或加密
85 |
86 | 目前一个server只能支持一个client,如果需要同时运行多个client,需要启动多个server。
87 |
88 | ##### 提示
89 |
90 | 对于某些运营商,tinyfecVPN跟udp2raw配合可以达到更好的速度,udp2raw负责把UDP伪装成TCP,来绕过运营商的UDP限速。
91 |
92 | udp2raw的repo:
93 |
94 | https://github.com/wangyu-/udp2raw-tunnel
95 |
96 | # 进阶操作说明
97 |
98 | ### 命令选项
99 | ```
100 | tinyfecVPN
101 | git version: b03df1b586 build date: Oct 31 2017 19:46:50
102 | repository: https://github.com/wangyu-/tinyfecVPN/
103 |
104 | usage:
105 | run as client: ./this_program -c -r server_ip:server_port [options]
106 | run as server: ./this_program -s -l server_listen_ip:server_port [options]
107 |
108 | common options, must be same on both sides:
109 | -k,--key key for simple xor encryption. if not set, xor is disabled
110 | main options:
111 | --sub-net specify sub-net, for example: 192.168.1.0 , default: 10.22.22.0
112 | --tun-dev sepcify tun device name, for example: tun10, default: a random name such as tun987
113 | -f,--fec x:y forward error correction, send y redundant packets for every x packets
114 | --timeout how long could a packet be held in queue before doing fec, unit: ms, default: 8ms
115 | --mode fec-mode,available values: 0, 1; 0 cost less bandwidth, 1 cost less latency;default: 0)
116 | --report turn on send/recv report, and set a period for reporting, unit: s
117 | --keep-reconnect re-connect after lost connection,only for client.
118 | advanced options:
119 | --mtu mtu. for mode 0, the program will split packet to segment smaller than mtu_value.
120 | for mode 1, no packet will be split, the program just check if the mtu is exceed.
121 | default value: 1250
122 | -j,--jitter simulated jitter. randomly delay first packet for 0~ ms, default value: 0.
123 | do not use if you dont know what it means.
124 | -i,--interval scatter each fec group to a interval of ms, to protect burst packet loss.
125 | default value: 0. do not use if you dont know what it means.
126 | --random-drop simulate packet loss, unit: 0.01%. default value: 0
127 | --disable-obscure disable obscure, to save a bit bandwidth and cpu
128 | developer options:
129 | --tun-mtu mtu of the tun interface,most time you shouldnt change this
130 | --disable-mssfix disable mssfix for tcp connection
131 | --fifo use a fifo(named pipe) for sending commands to the running program, so that you
132 | can change fec encode parameters dynamically, check readme.md in repository for
133 | supported commands.
134 | -j ,--jitter jmin:jmax similiar to -j above, but create jitter randomly between jmin and jmax
135 | -i,--interval imin:imax similiar to -i above, but scatter randomly between imin and imax
136 | -q,--queue-len max fec queue len, only for mode 0
137 | --decode-buf size of buffer of fec decoder,u nit: packet, default: 2000
138 | --fix-latency try to stabilize latency, only for mode 0
139 | --delay-capacity max number of delayed packets
140 | --disable-fec completely disable fec, turn the program into a normal udp tunnel
141 | --sock-buf buf size for socket, >=10 and <=10240, unit: kbyte, default: 1024
142 | log and help options:
143 | --log-level 0: never 1: fatal 2: error 3: warn
144 | 4: info (default) 5: debug 6: trace
145 | --log-position enable file name, function name, line number in log
146 | --disable-color disable log color
147 | -h,--help print this help message
148 |
149 | ```
150 | ### 跟UDPspeeder共用的选项
151 |
152 | tinyfecVPN支持UDPspeeder的所有选项,具体请看UDPspeeder的repo:
153 |
154 | https://github.com/wangyu-/UDPspeeder/blob/master/doc/README.zh-cn.md#命令选项
155 |
156 | ### tinyfecVPN的新增选项
157 |
158 | ##### `--tun-dev`
159 |
160 | 指定tun设备的名字. 例如: --tun-dev tun100.
161 |
162 | 如果不指定,tinyfecVPN会创建一个随机名字的tun设备,比如tun987.
163 |
164 | ##### `--sub-net`
165 |
166 | 指定VPN的子网,格式为xxx.xxx.xxx.0。 例如: 对于--sub-net 10.10.10.0, server的IP会被设置成10.10.10.1,client的IP会被设置成10.10.10.2 .
167 |
168 | 子网中的最后一个数字应该是0, 比如10.10.10.123是不符合规范的, 会被程序自动纠正成10.10.10.0.
169 |
170 | ##### `--keep-reconnect`
171 |
172 | 只对client有效
173 |
174 | tinyfecVPN server只接受一个client的连接,后连接的client会把新的挤掉。
175 |
176 | 如果开启了--keep-reconnect,client在连接断开或者被挤掉以后会尝试重新获得连接。
177 |
178 | # 使用经验
179 |
180 | https://github.com/wangyu-/tinyfecVPN/wiki/使用经验
181 |
182 | # 性能测试(侧重吞吐量)
183 |
184 | server 在 vulr 日本,CPU2.4GHz,内存 512mb。client 在搬瓦工美国,CPU 2.0GHZ,内存 96mb。在网路间额外模拟了10%的丢包,用于加重FEC的负担。
185 |
186 | ### 测试命令
187 |
188 | ```
189 | 在server端:
190 | ./tinyvpn_amd64 -s -l 0.0.0.0:5533 --mode 0
191 | iperf3 -s
192 | 在client端:
193 | ./tinyvpn_amd64 -c -r 44.55.66.77:5533 --mode 0
194 | iperf3 -c 10.22.22.1 -P10
195 | ```
196 |
197 | ### 测试结果
198 |
199 | 
200 |
201 | # Wiki
202 |
203 | Wiki上有更丰富的内容:
204 |
205 | https://github.com/wangyu-/tinyfecVPN/wiki
206 |
207 | # 限制
208 |
209 | 考虑到国内的实情,为了降低风险,[releases](https://github.com/wangyu-/tinyfecVPN/releases)中的binaries存在一点人为限制:只允许透过tinyfecVPN访问server上的服务,不能(直接)访问第三方服务器;也就是只能当加速器用,不能(直接)用来科学上网。
210 |
211 | 即使开启了ipforward和MASQUERADE也不行,代码里有额外处理,直接透过tinyfecVPN访问第三方服务器的包会被丢掉,效果如图:
212 |
213 | 
214 |
215 | 如果你需要去掉这个限制,可以自己编译(makefile里有相应的target)。 只需要自己编译server端,因为限制只存在于server端。
216 |
217 | (自己编译请用` git clone --recursive`而不是仅`git clone`,否则submodule不会被正常clone)
218 |
--------------------------------------------------------------------------------
/images/FEC.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/FEC.PNG
--------------------------------------------------------------------------------
/images/en/init:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/images/en/ping_compare.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/en/ping_compare.PNG
--------------------------------------------------------------------------------
/images/en/ping_compare2.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/en/ping_compare2.PNG
--------------------------------------------------------------------------------
/images/en/rs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/en/rs.png
--------------------------------------------------------------------------------
/images/en/scp_compare.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/en/scp_compare.PNG
--------------------------------------------------------------------------------
/images/en/scp_compare2.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/en/scp_compare2.PNG
--------------------------------------------------------------------------------
/images/init:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/images/peformance.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/peformance.PNG
--------------------------------------------------------------------------------
/images/performance2.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/performance2.PNG
--------------------------------------------------------------------------------
/images/restriction.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/restriction.PNG
--------------------------------------------------------------------------------
/images/tinyFecVPN.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/tinyFecVPN.PNG
--------------------------------------------------------------------------------
/images/tinyFecVPN2.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/tinyFecVPN2.PNG
--------------------------------------------------------------------------------
/images/tinyFecVPN3.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/tinyFecVPN3.PNG
--------------------------------------------------------------------------------
/images/tinyFecVPNcn.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/tinyFecVPNcn.PNG
--------------------------------------------------------------------------------
/images/tinyFecVPNcn2.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/tinyFecVPNcn2.PNG
--------------------------------------------------------------------------------
/main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * tun.cpp
3 | *
4 | * Created on: Oct 26, 2017
5 | * Author: root
6 | */
7 |
8 | #include "common.h"
9 | #include "log.h"
10 | #include "misc.h"
11 | #include "tun_dev.h"
12 | #include "git_version.h"
13 | using namespace std;
14 |
15 | static void print_help() {
16 | char git_version_buf[100] = {0};
17 | strncpy(git_version_buf, gitversion, 10);
18 |
19 | printf("tinyFecVPN\n");
20 | printf("git version: %s ", git_version_buf);
21 | printf("build date: %s %s\n", __DATE__, __TIME__);
22 | printf("repository: https://github.com/wangyu-/tinyFecVPN/\n");
23 | printf("\n");
24 | printf("usage:\n");
25 | printf(" run as client: ./this_program -c -r server_ip:server_port [options]\n");
26 | printf(" run as server: ./this_program -s -l server_listen_ip:server_port [options]\n");
27 | printf("\n");
28 | printf("common options, must be same on both sides:\n");
29 | printf(" -k,--key key for simple xor encryption. if not set, xor is disabled\n");
30 |
31 | printf("main options:\n");
32 | printf(" --sub-net specify sub-net, for example: 192.168.1.0 , default: 10.22.22.0\n");
33 | printf(" --tun-dev sepcify tun device name, for example: tun10, default: a random name such as tun987\n");
34 | printf(" -f,--fec x:y forward error correction, send y redundant packets for every x packets\n");
35 | printf(" --timeout how long could a packet be held in queue before doing fec, unit: ms, default: 8ms\n");
36 | printf(" --report turn on send/recv report, and set a period for reporting, unit: s\n");
37 | printf(" --keep-reconnect re-connect after lost connection,only for client. \n");
38 |
39 | printf("advanced options:\n");
40 | printf(" --mode fec-mode,available values: 0,1; mode 0(default) costs less bandwidth,no mtu problem.\n");
41 | printf(" mode 1 usually introduces less latency, but you have to care about mtu.\n");
42 | printf(" --mtu mtu for fec. for mode 0, the program will split packet to segment smaller than mtu.\n");
43 | printf(" for mode 1, no packet will be split, the program just check if the mtu is exceed.\n");
44 | printf(" default value: 1250\n");
45 | printf(" -j,--jitter simulated jitter. randomly delay first packet for 0~ ms, default value: 0.\n");
46 | printf(" do not use if you dont know what it means.\n");
47 | printf(" -i,--interval scatter each fec group to a interval of ms, to defend burst packet loss.\n");
48 | printf(" default value: 0. do not use if you dont know what it means.\n");
49 | printf(" -f,--fec x1:y1,x2:y2,.. similiar to -f/--fec above,fine-grained fec parameters,may help save bandwidth.\n");
50 | printf(" example: \"-f 1:3,2:4,10:6,20:10\". check repo for details\n");
51 | printf(" --random-drop simulate packet loss, unit: 0.01%%. default value: 0\n");
52 | printf(" --disable-obscure disable obscure, to save a bit bandwidth and cpu\n");
53 | printf(" --disable-checksum disable checksum to save a bit bandwdith and cpu\n");
54 | // printf(" --disable-xor disable xor\n");
55 | printf(" --persist-tun make the tun device persistent, so that it wont be deleted after exited.\n");
56 | printf(" --mssfix do mssfix for tcp connection, use 0 to disable. default value: 1250\n");
57 |
58 | printf("developer options:\n");
59 | printf(" --tun-mtu mtu of the tun interface,most time you shouldnt change this\n");
60 | printf(" --manual-set-tun tell tinyfecvpn to not setup the tun device automatically(e.g. assign ip address),\n");
61 | printf(" so that you can do it manually later\n");
62 | printf(" --fifo use a fifo(named pipe) for sending commands to the running program, so that you\n");
63 | printf(" can change fec encode parameters dynamically, check readme.md in repository for\n");
64 | printf(" supported commands.\n");
65 | printf(" -j ,--jitter jmin:jmax similiar to -j above, but create jitter randomly between jmin and jmax\n");
66 | printf(" -i,--interval imin:imax similiar to -i above, but scatter randomly between imin and imax\n");
67 | printf(" -q,--queue-len fec queue len, only for mode 0, fec will be performed immediately after queue is full.\n");
68 | printf(" default value: 200. \n");
69 | printf(" --decode-buf size of buffer of fec decoder,u nit: packet, default: 2000\n");
70 | // printf(" --fix-latency try to stabilize latency, only for mode 0\n");
71 | printf(" --delay-capacity max number of delayed packets, 0 means unlimited, default: 0\n");
72 | printf(" --disable-fec completely disable fec, turn the program into a normal udp tunnel\n");
73 | printf(" --sock-buf buf size for socket, >=10 and <=10240, unit: kbyte, default: 1024\n");
74 | printf(" --out-addr ip:port force all output packets of '-r' end to go through this address, port 0 for random port.\n");
75 | printf(" --out-interface force all output packets of '-r' end to go through this interface.\n");
76 |
77 | printf("log and help options:\n");
78 | printf(" --log-level 0: never 1: fatal 2: error 3: warn \n");
79 | printf(" 4: info (default) 5: debug 6: trace\n");
80 | printf(" --log-position enable file name, function name, line number in log\n");
81 | printf(" --disable-color disable log color\n");
82 | printf(" -h,--help print this help message\n");
83 |
84 | // printf("common options,these options must be same on both side\n");
85 | }
86 |
87 | void sigpipe_cb(struct ev_loop *l, ev_signal *w, int revents) {
88 | mylog(log_info, "got sigpipe, ignored");
89 | }
90 |
91 | void sigterm_cb(struct ev_loop *l, ev_signal *w, int revents) {
92 | mylog(log_info, "got sigterm, exit");
93 | myexit(0);
94 | }
95 |
96 | void sigint_cb(struct ev_loop *l, ev_signal *w, int revents) {
97 | mylog(log_info, "got sigint, exit");
98 | myexit(0);
99 | }
100 |
101 | int main(int argc, char *argv[]) {
102 | working_mode = tun_dev_mode;
103 | struct ev_loop *loop = ev_default_loop(0);
104 | #if !defined(__MINGW32__)
105 | ev_signal signal_watcher_sigpipe;
106 | ev_signal_init(&signal_watcher_sigpipe, sigpipe_cb, SIGPIPE);
107 | ev_signal_start(loop, &signal_watcher_sigpipe);
108 | #else
109 | enable_log_color = 0;
110 | #endif
111 |
112 | ev_signal signal_watcher_sigterm;
113 | ev_signal_init(&signal_watcher_sigterm, sigterm_cb, SIGTERM);
114 | ev_signal_start(loop, &signal_watcher_sigterm);
115 |
116 | ev_signal signal_watcher_sigint;
117 | ev_signal_init(&signal_watcher_sigint, sigint_cb, SIGINT);
118 | ev_signal_start(loop, &signal_watcher_sigint);
119 |
120 | assert(sizeof(u64_t) == 8);
121 | assert(sizeof(i64_t) == 8);
122 | assert(sizeof(u32_t) == 4);
123 | assert(sizeof(i32_t) == 4);
124 | assert(sizeof(u16_t) == 2);
125 | assert(sizeof(i16_t) == 2);
126 | dup2(1, 2); // redirect stderr to stdout
127 | int i, j, k;
128 | if (argc == 1) {
129 | print_help();
130 | myexit(-1);
131 | }
132 | for (i = 0; i < argc; i++) {
133 | if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
134 | print_help();
135 | myexit(0);
136 | }
137 | }
138 |
139 | // g_fec_mode=0;
140 |
141 | process_arg(argc, argv);
142 |
143 | delay_manager.set_capacity(delay_capacity);
144 | // local_ip_uint32=inet_addr(local_ip);
145 | // remote_ip_uint32=inet_addr(remote_ip);
146 | sub_net_uint32 = inet_addr(sub_net);
147 |
148 | if (strlen(tun_dev) == 0) {
149 | sprintf(tun_dev, "tun%u", get_fake_random_number() % 1000);
150 | }
151 | mylog(log_info, "using interface %s\n", tun_dev);
152 | /*if(tun_mtu==0)
153 | {
154 | tun_mtu=g_fec_mtu;
155 | }*/
156 | if (program_mode == client_mode) {
157 | tun_dev_client_event_loop();
158 | } else {
159 | tun_dev_server_event_loop();
160 | }
161 |
162 | return 0;
163 | }
164 |
--------------------------------------------------------------------------------
/makefile:
--------------------------------------------------------------------------------
1 | cc_cross=/toolchains/tmp/OpenWrt-SDK-15.05.1-ar71xx-generic_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-g++ -s
2 | cc_local=g++
3 | #cc_mips34kc=/toolchains/OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-g++
4 | cc_mips24kc_be=/toolchains/lede-sdk-17.01.2-ar71xx-generic_gcc-5.4.0_musl-1.1.16.Linux-x86_64/staging_dir/toolchain-mips_24kc_gcc-5.4.0_musl-1.1.16/bin/mips-openwrt-linux-musl-g++
5 | cc_mips24kc_le=/toolchains/lede-sdk-17.01.2-ramips-mt7621_gcc-5.4.0_musl-1.1.16.Linux-x86_64/staging_dir/toolchain-mipsel_24kc_gcc-5.4.0_musl-1.1.16/bin/mipsel-openwrt-linux-musl-g++
6 | #cc_arm= /toolchains/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi/bin/arm-linux-gnueabi-g++ -march=armv6 -marm
7 | cc_arm= /toolchains/arm-2014.05/bin/arm-none-linux-gnueabi-g++
8 | #cc_bcm2708=/home/wangyu/raspberry/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-g++
9 | FLAGS= -std=c++11 -Wall -Wextra -Wno-unused-variable -Wno-unused-parameter -Wno-missing-field-initializers -ggdb -I. -IUDPspeeder -isystem UDPspeeder/libev ${OPT}
10 |
11 | SOURCES=`ls UDPspeeder/*.cpp UDPspeeder/lib/*.cpp|grep -v main.cpp|grep -v tunnel.cpp` main.cpp tun_dev.cpp tun_dev_client.cpp tun_dev_server.cpp
12 |
13 | #INCLUDE= -I. -IUDPspeeder
14 |
15 | NAME=tinyvpn
16 |
17 | TARGETS=amd64 arm mips24kc_be x86 mips24kc_le
18 |
19 | TAR=${NAME}_binaries.tar.gz `echo ${TARGETS}|sed -r 's/([^ ]+)/tinyvpn_\1/g'` version.txt
20 |
21 | export STAGING_DIR=/tmp/ #just for supress warning of staging_dir not define
22 |
23 | all:git_version
24 | rm -f ${NAME}
25 | ${cc_local} -o ${NAME} ${INCLUDE} ${SOURCES} ${FLAGS} -lrt -ggdb -static -O2
26 |
27 | debug: git_version
28 | rm -f ${NAME}
29 | ${cc_local} -o ${NAME} -I. ${SOURCES} ${FLAGS} -lrt -Wformat-nonliteral -D MY_DEBUG
30 | debug2: git_version
31 | rm -f ${NAME}
32 | ${cc_local} -o ${NAME} -I. ${SOURCES} ${FLAGS} -lrt -Wformat-nonliteral -ggdb
33 |
34 | init:
35 | git submodule init
36 | git submodule update
37 |
38 | mips24kc_be: git_version
39 | ${cc_mips24kc_be} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -lgcc_eh -static -O3
40 |
41 | mips24kc_be_debug: git_version
42 | ${cc_mips24kc_be} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -lgcc_eh -static -ggdb
43 |
44 | mips24kc_le: git_version
45 | ${cc_mips24kc_le} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -lgcc_eh -static -O3
46 |
47 | amd64:git_version
48 | ${cc_local} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O3
49 | amd64_debug:git_version
50 | ${cc_local} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -ggdb
51 | x86:git_version
52 | ${cc_local} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O3 -m32
53 | arm:git_version
54 | ${cc_arm} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O3
55 |
56 | arm_debug:git_version
57 | ${cc_arm} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -ggdb
58 |
59 | cross:git_version
60 | ${cc_cross} -o ${NAME}_cross -I. ${SOURCES} ${FLAGS} -lrt -O3
61 |
62 | cross2:git_version
63 | ${cc_cross} -o ${NAME}_cross -I. ${SOURCES} ${FLAGS} -lrt -static -lgcc_eh -O3
64 |
65 | cross3:git_version
66 | ${cc_cross} -o ${NAME}_cross -I. ${SOURCES} ${FLAGS} -lrt -static -O3
67 |
68 | release: ${TARGETS}
69 | cp git_version.h version.txt
70 | tar -zcvf ${TAR}
71 |
72 | clean:
73 | rm -f ${TAR}
74 | rm -f speeder speeder_cross
75 | rm -f git_version.h
76 |
77 | git_version:
78 | echo "const char * const gitversion = \"$(shell git rev-parse HEAD)\";" > git_version.h
79 |
80 |
81 | # targets without restrictions:
82 | nolimit:
83 | make OPT=-DNOLIMIT
84 | nolimit_all:
85 | make OPT=-DNOLIMIT
86 | nolimit_cross:
87 | make cross OPT=-DNOLIMIT
88 | nolimit_cross2:
89 | make cross2 OPT=-DNOLIMIT
90 | nolimit_cross3:
91 | make cross3 OPT=-DNOLIMIT
92 | nolimit_release:
93 | make release OPT=-DNOLIMIT
94 |
--------------------------------------------------------------------------------
/tun_dev.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * tun.cpp
3 | *
4 | * Created on: Oct 26, 2017
5 | * Author: root
6 | */
7 |
8 | #include "tun_dev.h"
9 |
10 | my_time_t last_keep_alive_time = 0;
11 |
12 | int get_tun_fd(char *dev_name) {
13 | int tun_fd = open("/dev/net/tun", O_RDWR);
14 |
15 | if (tun_fd < 0) {
16 | mylog(log_fatal, "open /dev/net/tun failed");
17 | myexit(-1);
18 | }
19 | struct ifreq ifr;
20 | memset(&ifr, 0, sizeof(ifr));
21 | ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
22 |
23 | strncpy(ifr.ifr_name, dev_name, IFNAMSIZ);
24 |
25 | if (ioctl(tun_fd, TUNSETIFF, (void *)&ifr) != 0) {
26 | mylog(log_fatal, "open /dev/net/tun failed");
27 | myexit(-1);
28 | }
29 |
30 | if (persist_tun == 1) {
31 | if (ioctl(tun_fd, TUNSETPERSIST, 1) != 0) {
32 | mylog(log_warn, "failed to set tun persistent");
33 | }
34 | }
35 | return tun_fd;
36 | }
37 |
38 | int set_tun(char *if_name, u32_t local_ip, u32_t remote_ip, int mtu) {
39 | if (manual_set_tun) return 0;
40 |
41 | // printf("i m here1\n");
42 | struct ifreq ifr;
43 | struct sockaddr_in sai;
44 | memset(&ifr, 0, sizeof(ifr));
45 | memset(&sai, 0, sizeof(struct sockaddr));
46 |
47 | int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
48 | strncpy(ifr.ifr_name, if_name, IFNAMSIZ);
49 |
50 | sai.sin_family = AF_INET;
51 | sai.sin_port = 0;
52 |
53 | sai.sin_addr.s_addr = local_ip;
54 | memcpy(&ifr.ifr_addr, &sai, sizeof(struct sockaddr));
55 | assert(ioctl(sockfd, SIOCSIFADDR, &ifr) == 0); // set source ip
56 |
57 | sai.sin_addr.s_addr = remote_ip;
58 | memcpy(&ifr.ifr_addr, &sai, sizeof(struct sockaddr));
59 | assert(ioctl(sockfd, SIOCSIFDSTADDR, &ifr) == 0); // set dest ip
60 |
61 | ifr.ifr_mtu = mtu;
62 | assert(ioctl(sockfd, SIOCSIFMTU, &ifr) == 0); // set mtu
63 |
64 | assert(ioctl(sockfd, SIOCGIFFLAGS, &ifr) == 0);
65 | // ifr.ifr_flags |= ( IFF_UP|IFF_POINTOPOINT|IFF_RUNNING|IFF_NOARP|IFF_MULTICAST );
66 | ifr.ifr_flags = (IFF_UP | IFF_POINTOPOINT | IFF_RUNNING | IFF_NOARP | IFF_MULTICAST); // set interface flags
67 | assert(ioctl(sockfd, SIOCSIFFLAGS, &ifr) == 0);
68 |
69 | // printf("i m here2\n");
70 | return 0;
71 | }
72 |
73 | int put_header(char header, char *data, int &len) {
74 | assert(len >= 0);
75 | data[len] = header;
76 | len += 1;
77 | return 0;
78 | }
79 | int get_header(char &header, char *data, int &len) {
80 | assert(len >= 0);
81 | if (len < 1) return -1;
82 | len -= 1;
83 | header = data[len];
84 |
85 | return 0;
86 | }
87 | int from_normal_to_fec2(conn_info_t &conn_info, dest_t &dest, char *data, int len, char header) {
88 | int out_n;
89 | char **out_arr;
90 | int *out_len;
91 | my_time_t *out_delay;
92 |
93 | from_normal_to_fec(conn_info, data, len, out_n, out_arr, out_len, out_delay);
94 |
95 | for (int i = 0; i < out_n; i++) {
96 | char tmp_buf[buf_len];
97 | int tmp_len = out_len[i];
98 | memcpy(tmp_buf, out_arr[i], out_len[i]);
99 | put_header(header, tmp_buf, tmp_len);
100 | delay_send(out_delay[i], dest, tmp_buf, tmp_len); // this is slow but safer.just use this one
101 |
102 | // put_header(header,out_arr[i],out_len[i]);//modify in place
103 | // delay_send(out_delay[i],dest,out_arr[i],out_len[i]);//warning this is currently okay,but if you modified fec encoder,you may have to use the above code
104 | }
105 | return 0;
106 | }
107 |
108 | int from_fec_to_normal2(conn_info_t &conn_info, dest_t &dest, char *data, int len) {
109 | int out_n;
110 | char **out_arr;
111 | int *out_len;
112 | my_time_t *out_delay;
113 |
114 | from_fec_to_normal(conn_info, data, len, out_n, out_arr, out_len, out_delay);
115 |
116 | for (int i = 0; i < out_n; i++) {
117 | #if 0
118 | if (program_mode == server_mode) {
119 | char *tmp_data = out_arr[i];
120 | int tmp_len = out_len[i];
121 | iphdr *iph;
122 | iph = (struct iphdr *)tmp_data;
123 | if (tmp_len >= int(sizeof(iphdr)) && iph->version == 4) {
124 | u32_t dest_ip = iph->daddr;
125 | // printf("%s\n",my_ntoa(dest_ip));
126 | if ((ntohl(sub_net_uint32) & 0xFFFFFF00) != (ntohl(dest_ip) & 0xFFFFFF00)) {
127 | string sub = my_ntoa(dest_ip);
128 | string dst = my_ntoa(htonl(ntohl(sub_net_uint32) & 0xFFFFFF00));
129 | mylog(log_warn, "[restriction]packet's dest ip [%s] not in subnet [%s],dropped, maybe you need to compile an un-restricted server\n", sub.c_str(), dst.c_str());
130 | continue;
131 | }
132 | }
133 | }
134 | #endif
135 | delay_send(out_delay[i], dest, out_arr[i], out_len[i]);
136 | }
137 |
138 | return 0;
139 | }
140 | int do_mssfix(char *s, int len) // currently only for ipv4
141 | {
142 | if (mssfix == 0) {
143 | return 0;
144 | }
145 |
146 | if (len < int(sizeof(iphdr))) {
147 | mylog(log_debug, "packet from tun len=%d <20\n", len);
148 | return -1;
149 | }
150 | iphdr *iph;
151 | iph = (struct iphdr *)s;
152 | if (iph->version != 4) {
153 | // mylog(log_trace,"not ipv4");
154 | return 0;
155 | }
156 |
157 | if (iph->protocol != IPPROTO_TCP) {
158 | // mylog(log_trace,"not tcp");
159 | return 0;
160 | }
161 |
162 | int ip_len = ntohs(iph->tot_len);
163 | int ip_hdr_len = iph->ihl * 4;
164 |
165 | if (len < ip_hdr_len) {
166 | mylog(log_debug, "len ip_len) {
174 | mylog(log_debug, "ip_hdr_lenfrag_off) & (short)(0x1FFF)) != 0) {
179 | // not first segment
180 |
181 | // printf("line=%d %x %x \n",__LINE__,(u32_t)ntohs(iph->frag_off),u32_t( ntohs(iph->frag_off) &0xFFF8));
182 | return 0;
183 | }
184 | if ((ntohs(iph->frag_off) & (short)(0x80FF)) != 0) {
185 | // not whole segment
186 | // printf("line=%d \n",__LINE__);
187 | return 0;
188 | }
189 |
190 | char *tcp_begin = s + ip_hdr_len;
191 | int tcp_len = ip_len - ip_hdr_len;
192 |
193 | if (tcp_len < 20) {
194 | mylog(log_debug, "tcp_len<20,%d\n", tcp_len);
195 | return -1;
196 | }
197 |
198 | tcphdr *tcph = (struct tcphdr *)tcp_begin;
199 |
200 | if (int(tcph->syn) == 0) // fast fail
201 | {
202 | mylog(log_trace, "tcph->syn==0\n");
203 | return 0;
204 | }
205 |
206 | int tcp_hdr_len = tcph->doff * 4;
207 |
208 | if (tcp_len < tcp_hdr_len) {
209 | mylog(log_debug, "tcp_len = option_end) {
230 | mylog(log_debug, "invaild option ptr+1==option_end,for mss\n");
231 | return -1;
232 | }
233 | if (*(ptr + 1) != 4) {
234 | mylog(log_debug, "invaild mss len\n");
235 | return -1;
236 | }
237 | if (ptr + 3 >= option_end) {
238 | mylog(log_debug, "ptr+4>option_end for mss\n");
239 | return -1;
240 | }
241 | int mss = read_u16(ptr + 2); // uint8_t(ptr[2])*256+uint8_t(ptr[3]);
242 | int new_mss = mss;
243 | if (new_mss > ::mssfix - 40 - 10) // minus extra 10 for safe
244 | {
245 | new_mss = ::mssfix - 40 - 10;
246 | }
247 | write_u16(ptr + 2, (unsigned short)new_mss);
248 |
249 | pseudo_header psh;
250 |
251 | psh.source_address = iph->saddr;
252 | psh.dest_address = iph->daddr;
253 | psh.placeholder = 0;
254 | psh.protocol = iph->protocol;
255 | psh.tcp_length = htons(tcp_len);
256 |
257 | tcph->check = 0;
258 | tcph->check = tcp_csum(psh, (unsigned short *)tcph, tcp_len);
259 |
260 | mylog(log_trace, "mss=%d syn=%d ack=%d, changed mss to %d \n", mss, (int)tcph->syn, (int)tcph->ack, new_mss);
261 |
262 | // printf("test=%x\n",u32_t(1));
263 | // printf("frag=%x\n",u32_t( ntohs(iph->frag_off) ));
264 |
265 | return 0;
266 | } else {
267 | if (ptr + 1 >= option_end) {
268 | mylog(log_debug, "invaild option ptr+1==option_end\n");
269 | return -1;
270 | } else {
271 | int len = (unsigned char)*(ptr + 1);
272 | if (len <= 1) {
273 | mylog(log_debug, "invaild option len %d\n", len);
274 | return -1;
275 | }
276 | ptr += len;
277 | }
278 | }
279 | }
280 |
281 | return 0;
282 | }
283 | int do_keep_alive(dest_t &dest) {
284 | if (get_current_time() - last_keep_alive_time > u64_t(keep_alive_interval)) {
285 | last_keep_alive_time = get_current_time();
286 | char data[buf_len];
287 | int len;
288 | data[0] = header_keep_alive;
289 | len = 1;
290 |
291 | assert(dest.cook == 1);
292 | // do_cook(data,len);
293 |
294 | delay_send(0, dest, data, len);
295 | }
296 | return 0;
297 | }
298 |
--------------------------------------------------------------------------------
/tun_dev.h:
--------------------------------------------------------------------------------
1 | /*
2 | * tun.h
3 | *
4 | * Created on: Oct 26, 2017
5 | * Author: root
6 | */
7 |
8 | #ifndef TUN_DEV_H_
9 | #define TUN_DEV_H_
10 |
11 | #include "common.h"
12 | #include "log.h"
13 | #include "misc.h"
14 |
15 | #include //Provides declarations for tcp header
16 | #include
17 | #include //Provides declarations for ip header
18 | #include
19 |
20 | #include
21 | #include
22 |
23 | extern my_time_t last_keep_alive_time;
24 |
25 | const int keep_alive_interval = 3000; // 3000ms
26 |
27 | const char header_normal = 1;
28 | const char header_new_connect = 2;
29 | const char header_reject = 3;
30 | const char header_keep_alive = 4;
31 |
32 | int set_tun(char *if_name, u32_t local_ip, u32_t remote_ip, int mtu);
33 |
34 | int get_tun_fd(char *dev_name);
35 |
36 | int put_header(char header, char *data, int &len);
37 |
38 | int get_header(char &header, char *data, int &len);
39 | int from_normal_to_fec2(conn_info_t &conn_info, dest_t &dest, char *data, int len, char header);
40 |
41 | int from_fec_to_normal2(conn_info_t &conn_info, dest_t &dest, char *data, int len);
42 | int do_mssfix(char *s, int len);
43 | int do_keep_alive(dest_t &dest);
44 |
45 | int tun_dev_client_event_loop();
46 |
47 | int tun_dev_server_event_loop();
48 |
49 | #endif /* TUN_H_ */
50 |
--------------------------------------------------------------------------------
/tun_dev_client.cpp:
--------------------------------------------------------------------------------
1 | #include "tun_dev.h"
2 |
3 | static int got_feed_back = 0;
4 |
5 | static dest_t udp_dest;
6 | static dest_t tun_dest;
7 |
8 | static void remote_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) {
9 | assert(!(revents & EV_ERROR));
10 |
11 | conn_info_t &conn_info = *((conn_info_t *)watcher->data);
12 |
13 | char data[buf_len];
14 | int len;
15 |
16 | fd64_t fd64 = watcher->u64;
17 | int fd = fd_manager.to_fd(fd64);
18 |
19 | len = recv(fd, data, max_data_len + 1, 0);
20 |
21 | if (len == max_data_len + 1) {
22 | mylog(log_warn, "huge packet, data_len > %d,dropped\n", max_data_len);
23 | return;
24 | }
25 |
26 | if (len < 0) {
27 | mylog(log_warn, "recv return %d,errno=%s\n", len, strerror(errno));
28 | return;
29 | }
30 |
31 | if (de_cook(data, len) < 0) {
32 | mylog(log_warn, "de_cook(data,len)failed \n");
33 | return;
34 | }
35 |
36 | char header = 0;
37 | if (get_header(header, data, len) != 0) {
38 | mylog(log_warn, "get_header failed\n");
39 | return;
40 | }
41 |
42 | if (header == header_keep_alive) {
43 | mylog(log_trace, "got keep_alive packet\n");
44 | return;
45 | }
46 |
47 | if (header == header_reject) {
48 | if (keep_reconnect == 0) {
49 | mylog(log_fatal, "server restarted or switched to handle another client,exited. maybe you need --keep-reconnect\n");
50 | myexit(-1);
51 | } else {
52 | if (got_feed_back == 1)
53 | mylog(log_warn, "server restarted or switched to handle another client,but keep-reconnect enabled,trying to reconnect\n");
54 | got_feed_back = 0;
55 | }
56 | return;
57 | } else if (header == header_normal) {
58 | if (got_feed_back == 0)
59 | mylog(log_info, "connection accepted by server\n");
60 | got_feed_back = 1;
61 | } else {
62 | mylog(log_warn, "invalid header %d %d\n", int(header), len);
63 | return;
64 | }
65 |
66 | mylog(log_trace, "Received packet from udp,len: %d\n", len);
67 |
68 | from_fec_to_normal2(conn_info, tun_dest, data, len);
69 | }
70 |
71 | static void tun_fd_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) {
72 | assert(!(revents & EV_ERROR));
73 |
74 | conn_info_t &conn_info = *((conn_info_t *)watcher->data);
75 |
76 | char data[buf_len];
77 | int len;
78 | int tun_fd = watcher->fd;
79 |
80 | len = read(tun_fd, data, max_data_len + 1);
81 |
82 | if (len == max_data_len + 1) {
83 | mylog(log_warn, "huge packet, data_len > %d,dropped\n", max_data_len);
84 | return;
85 | }
86 |
87 | if (len < 0) {
88 | mylog(log_warn, "read from tun_fd return %d,errno=%s\n", len, strerror(errno));
89 | return;
90 | }
91 |
92 | do_mssfix(data, len);
93 |
94 | mylog(log_trace, "Received packet from tun,len: %d\n", len);
95 |
96 | char header = (got_feed_back == 0 ? header_new_connect : header_normal);
97 | from_normal_to_fec2(conn_info, udp_dest, data, len, header);
98 | }
99 |
100 | static void delay_manager_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents) {
101 | assert(!(revents & EV_ERROR));
102 |
103 | // do nothing
104 | }
105 |
106 | static void fec_encode_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents) {
107 | assert(!(revents & EV_ERROR));
108 |
109 | mylog(log_trace, "fec_encode_cb() called\n");
110 |
111 | conn_info_t &conn_info = *((conn_info_t *)watcher->data);
112 |
113 | /// int ret;
114 | /// fd64_t fd64=watcher->u64;
115 | /// mylog(log_trace,"events[idx].data.u64 == conn_info.fec_encode_manager.get_timer_fd64()\n");
116 |
117 | /// uint64_t value;
118 | /// if(!fd_manager.exist(fd64)) //fd64 has been closed
119 | ///{
120 | /// mylog(log_trace,"!fd_manager.exist(fd64)");
121 | /// return;
122 | /// }
123 | /// if((ret=read(fd_manager.to_fd(fd64), &value, 8))!=8)
124 | ///{
125 | /// mylog(log_trace,"(ret=read(fd_manager.to_fd(fd64), &value, 8))!=8,ret=%d\n",ret);
126 | /// return;
127 | /// }
128 | /// if(value==0)
129 | ///{
130 | /// mylog(log_debug,"value==0\n");
131 | /// return;
132 | /// }
133 | /// assert(value==1);
134 |
135 | char header = (got_feed_back == 0 ? header_new_connect : header_normal);
136 | from_normal_to_fec2(conn_info, udp_dest, 0, 0, header);
137 | }
138 |
139 | static void conn_timer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents) {
140 | assert(!(revents & EV_ERROR));
141 |
142 | conn_info_t &conn_info = *((conn_info_t *)watcher->data);
143 |
144 | /// uint64_t value;
145 | /// read(conn_info.timer.get_timer_fd(), &value, 8);
146 | /// mylog(log_trace,"events[idx].data.u64==(u64_t)conn_info.timer.get_timer_fd()\n");
147 |
148 | mylog(log_trace, "conn_timer_cb() called\n");
149 | conn_info.stat.report_as_client();
150 | if (got_feed_back) do_keep_alive(udp_dest);
151 | }
152 |
153 | static void fifo_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) {
154 | assert(!(revents & EV_ERROR));
155 | int fifo_fd = watcher->fd;
156 |
157 | char buf[buf_len];
158 | int len = read(fifo_fd, buf, sizeof(buf));
159 | if (len < 0) {
160 | mylog(log_warn, "fifo read failed len=%d,errno=%s\n", len, strerror(errno));
161 | return;
162 | }
163 | buf[len] = 0;
164 | handle_command(buf);
165 | }
166 |
167 | static void prepare_cb(struct ev_loop *loop, struct ev_prepare *watcher, int revents) {
168 | assert(!(revents & EV_ERROR));
169 |
170 | delay_manager.check();
171 | }
172 |
173 | int tun_dev_client_event_loop() {
174 | // char data[buf_len];
175 | // int len;
176 | int i, j, k, ret;
177 | int tun_fd;
178 |
179 | int remote_fd;
180 | fd64_t remote_fd64;
181 |
182 | conn_info_t *conn_info_p = new conn_info_t;
183 | conn_info_t &conn_info = *conn_info_p; // huge size of conn_info,do not allocate on stack
184 |
185 | tun_fd = get_tun_fd(tun_dev);
186 | assert(tun_fd > 0);
187 |
188 | assert(new_connected_socket2(remote_fd, remote_addr, out_addr, out_interface) == 0);
189 | remote_fd64 = fd_manager.create(remote_fd);
190 |
191 | assert(set_tun(tun_dev, htonl((ntohl(sub_net_uint32) & 0xFFFFFF00) | 2), htonl((ntohl(sub_net_uint32) & 0xFFFFFF00) | 1), tun_mtu) == 0);
192 |
193 | tun_dest.type = type_write_fd;
194 | tun_dest.inner.fd = tun_fd;
195 |
196 | udp_dest.cook = 1;
197 | udp_dest.type = type_fd64;
198 | udp_dest.inner.fd64 = remote_fd64;
199 |
200 | /// epoll_fd = epoll_create1(0);
201 | /// assert(epoll_fd>0);
202 |
203 | /// const int max_events = 4096;
204 | /// struct epoll_event ev, events[max_events];
205 | /// if (epoll_fd < 0) {
206 | /// mylog(log_fatal,"epoll return %d\n", epoll_fd);
207 | /// myexit(-1);
208 | /// }
209 |
210 | struct ev_loop *loop = ev_default_loop(0);
211 | assert(loop != NULL);
212 | conn_info.loop = loop;
213 |
214 | /// ev.events = EPOLLIN;
215 | /// ev.data.u64 = remote_fd64;
216 | /// ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, remote_fd, &ev);
217 | /// if (ret!=0) {
218 | /// mylog(log_fatal,"add remote_fd64 error\n");
219 | /// myexit(-1);
220 | /// }
221 |
222 | struct ev_io remote_watcher;
223 | remote_watcher.data = &conn_info;
224 | remote_watcher.u64 = remote_fd64;
225 |
226 | ev_io_init(&remote_watcher, remote_cb, remote_fd, EV_READ);
227 | ev_io_start(loop, &remote_watcher);
228 |
229 | /// ev.events = EPOLLIN;
230 | /// ev.data.u64 = tun_fd;
231 | /// ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, tun_fd, &ev);
232 | /// if (ret!=0) {
233 | /// mylog(log_fatal,"add tun_fd error\n");
234 | /// myexit(-1);
235 | /// }
236 |
237 | struct ev_io tun_fd_watcher;
238 | tun_fd_watcher.data = &conn_info;
239 |
240 | ev_io_init(&tun_fd_watcher, tun_fd_cb, tun_fd, EV_READ);
241 | ev_io_start(loop, &tun_fd_watcher);
242 |
243 | /// ev.events = EPOLLIN;
244 | /// ev.data.u64 = delay_manager.get_timer_fd();
245 |
246 | /// mylog(log_debug,"delay_manager.get_timer_fd()=%d\n",delay_manager.get_timer_fd());
247 | /// ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, delay_manager.get_timer_fd(), &ev);
248 | /// if (ret!= 0) {
249 | /// mylog(log_fatal,"add delay_manager.get_timer_fd() error\n");
250 | /// myexit(-1);
251 | /// }
252 |
253 | delay_manager.set_loop_and_cb(loop, delay_manager_cb);
254 |
255 | /// u64_t tmp_timer_fd64=conn_info.fec_encode_manager.get_timer_fd64();
256 | /// ev.events = EPOLLIN;
257 | /// ev.data.u64 = tmp_timer_fd64;
258 |
259 | /// mylog(log_debug,"conn_info.fec_encode_manager.get_timer_fd64()=%llu\n",conn_info.fec_encode_manager.get_timer_fd64());
260 | /// ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd_manager.to_fd(tmp_timer_fd64), &ev);
261 | /// if (ret!= 0) {
262 | /// mylog(log_fatal,"add fec_encode_manager.get_timer_fd64() error\n");
263 | /// myexit(-1);
264 | /// }
265 |
266 | conn_info.fec_encode_manager.set_data(&conn_info);
267 | conn_info.fec_encode_manager.set_loop_and_cb(loop, fec_encode_cb);
268 |
269 | // conn_info.timer.add_fd_to_epoll(epoll_fd);
270 | // conn_info.timer.data=&conn_info;
271 |
272 | conn_info.timer.data = &conn_info;
273 | ev_init(&conn_info.timer, conn_timer_cb);
274 | ev_timer_set(&conn_info.timer, 0, timer_interval / 1000.0);
275 | ev_timer_start(loop, &conn_info.timer);
276 |
277 | struct ev_io fifo_watcher;
278 |
279 | int fifo_fd = -1;
280 |
281 | if (fifo_file[0] != 0) {
282 | fifo_fd = create_fifo(fifo_file);
283 | /// ev.events = EPOLLIN;
284 | /// ev.data.u64 = fifo_fd;
285 |
286 | /// ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fifo_fd, &ev);
287 | /// if (ret!= 0) {
288 | /// mylog(log_fatal,"add fifo_fd to epoll error %s\n",strerror(errno));
289 | /// myexit(-1);
290 | /// }
291 | ev_io_init(&fifo_watcher, fifo_cb, fifo_fd, EV_READ);
292 | ev_io_start(loop, &fifo_watcher);
293 |
294 | mylog(log_info, "fifo_file=%s\n", fifo_file);
295 | }
296 |
297 | ev_prepare prepare_watcher;
298 | ev_init(&prepare_watcher, prepare_cb);
299 | ev_prepare_start(loop, &prepare_watcher);
300 |
301 | ev_run(loop, 0);
302 |
303 | mylog(log_warn, "ev_run returned\n");
304 | myexit(0);
305 |
306 | return 0;
307 | }
308 |
--------------------------------------------------------------------------------
/tun_dev_server.cpp:
--------------------------------------------------------------------------------
1 | #include "tun_dev.h"
2 |
3 | static dest_t udp_dest;
4 | static dest_t tun_dest;
5 |
6 | static void local_listen_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) {
7 | char data[buf_len];
8 | int len;
9 |
10 | assert(!(revents & EV_ERROR));
11 |
12 | conn_info_t &conn_info = *((conn_info_t *)watcher->data);
13 |
14 | int local_listen_fd = watcher->fd;
15 |
16 | // struct sockaddr_in udp_new_addr_in={0};
17 | // socklen_t udp_new_addr_len = sizeof(sockaddr_in);
18 | address_t::storage_t udp_new_addr_in = {0};
19 | socklen_t udp_new_addr_len = sizeof(address_t::storage_t);
20 |
21 | if ((len = recvfrom(local_listen_fd, data, max_data_len + 1, 0,
22 | (struct sockaddr *)&udp_new_addr_in, &udp_new_addr_len)) < 0) {
23 | mylog(log_error, "recv_from error,this shouldnt happen,err=%s,but we can try to continue\n", strerror(errno));
24 | return;
25 | // myexit(1);
26 | };
27 |
28 | address_t new_addr;
29 | new_addr.from_sockaddr((struct sockaddr *)&udp_new_addr_in, udp_new_addr_len);
30 |
31 | if (len == max_data_len + 1) {
32 | mylog(log_warn, "huge packet, data_len > %d,dropped\n", max_data_len);
33 | return;
34 | }
35 |
36 | if (de_cook(data, len) < 0) {
37 | mylog(log_warn, "de_cook(data,len)failed \n");
38 | return;
39 | }
40 |
41 | char header = 0;
42 | if (get_header(header, data, len) != 0) {
43 | mylog(log_warn, "get_header() failed\n");
44 | return;
45 | }
46 |
47 | if (udp_dest.inner.fd_addr.addr == new_addr) {
48 | if (header == header_keep_alive) {
49 | mylog(log_trace, "got keep_alive packet\n");
50 | return;
51 | }
52 |
53 | if (header != header_new_connect && header != header_normal) {
54 | mylog(log_warn, "invalid header\n");
55 | return;
56 | }
57 | } else {
58 | if (header == header_keep_alive) {
59 | mylog(log_debug, "got keep_alive packet from unexpected client\n");
60 | return;
61 | }
62 |
63 | if (header == header_new_connect) {
64 | mylog(log_info, "new connection from %s\n", new_addr.get_str());
65 | udp_dest.inner.fd_addr.addr = new_addr;
66 | // udp_dest.inner.fd_ip_port.ip_port.ip=udp_new_addr_in.sin_addr.s_addr;
67 | // udp_dest.inner.fd_ip_port.ip_port.port=ntohs(udp_new_addr_in.sin_port);
68 | conn_info.fec_decode_manager.clear();
69 | conn_info.fec_encode_manager.clear_data();
70 | conn_info.stat.clear();
71 | } else if (header == header_normal) {
72 | mylog(log_debug, "rejected connection from %s\n", new_addr.get_str());
73 |
74 | len = 1;
75 | data[0] = header_reject;
76 | do_cook(data, len);
77 |
78 | dest_t tmp_dest;
79 | tmp_dest.type = type_fd_addr;
80 |
81 | tmp_dest.inner.fd_addr.fd = local_listen_fd;
82 | tmp_dest.inner.fd_addr.addr = new_addr;
83 |
84 | delay_manager.add(0, tmp_dest, data, len);
85 | ;
86 | return;
87 | } else {
88 | mylog(log_warn, "invalid header\n");
89 | }
90 | }
91 |
92 | mylog(log_trace, "Received packet from %s,len: %d\n", new_addr.get_str(), len);
93 |
94 | from_fec_to_normal2(conn_info, tun_dest, data, len);
95 | }
96 | static void tun_fd_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) {
97 | char data[buf_len];
98 | int len;
99 |
100 | assert(!(revents & EV_ERROR));
101 |
102 | conn_info_t &conn_info = *((conn_info_t *)watcher->data);
103 | int tun_fd = watcher->fd;
104 |
105 | len = read(tun_fd, data, max_data_len + 1);
106 |
107 | if (len == max_data_len + 1) {
108 | mylog(log_warn, "huge packet, data_len > %d,dropped\n", max_data_len);
109 | return;
110 | }
111 |
112 | if (len < 0) {
113 | mylog(log_warn, "read from tun_fd return %d,errno=%s\n", len, strerror(errno));
114 | return;
115 | }
116 |
117 | do_mssfix(data, len);
118 |
119 | mylog(log_trace, "Received packet from tun,len: %d\n", len);
120 |
121 | if (udp_dest.inner.fd_addr.addr.is_vaild() == 0) {
122 | mylog(log_debug, "received packet from tun,but there is no client yet,dropped packet\n");
123 | return;
124 | }
125 |
126 | from_normal_to_fec2(conn_info, udp_dest, data, len, header_normal);
127 | }
128 |
129 | static void delay_manager_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents) {
130 | assert(!(revents & EV_ERROR));
131 |
132 | // do nothing
133 | }
134 |
135 | static void fec_encode_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents) {
136 | assert(!(revents & EV_ERROR));
137 |
138 | mylog(log_trace, "fec_encode_cb() called\n");
139 |
140 | conn_info_t &conn_info = *((conn_info_t *)watcher->data);
141 |
142 | assert(udp_dest.inner.fd_addr.addr.is_vaild() != 0);
143 | /// mylog(log_trace,"events[idx].data.u64 == conn_info.fec_encode_manager.get_timer_fd64()\n");
144 | /// uint64_t fd64=events[idx].data.u64;
145 | /// uint64_t value;
146 | /// if(!fd_manager.exist(fd64)) //fd64 has been closed
147 | ///{
148 | /// mylog(log_trace,"!fd_manager.exist(fd64)");
149 | /// continue;
150 | /// }
151 | /// if((ret=read(fd_manager.to_fd(fd64), &value, 8))!=8)
152 | ///{
153 | /// mylog(log_trace,"(ret=read(fd_manager.to_fd(fd64), &value, 8))!=8,ret=%d\n",ret);
154 | /// continue;
155 | /// }
156 | /// if(value==0)
157 | ///{
158 | /// mylog(log_debug,"value==0\n");
159 | /// continue;
160 | /// }
161 | /// assert(value==1);
162 |
163 | from_normal_to_fec2(conn_info, udp_dest, 0, 0, header_normal);
164 | }
165 |
166 | static void fifo_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) {
167 | assert(!(revents & EV_ERROR));
168 | int fifo_fd = watcher->fd;
169 |
170 | char buf[buf_len];
171 | int len = read(fifo_fd, buf, sizeof(buf));
172 | if (len < 0) {
173 | mylog(log_warn, "fifo read failed len=%d,errno=%s\n", len, strerror(errno));
174 | return;
175 | }
176 | buf[len] = 0;
177 | handle_command(buf);
178 | }
179 |
180 | static void conn_timer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents) {
181 | assert(!(revents & EV_ERROR));
182 |
183 | conn_info_t &conn_info = *((conn_info_t *)watcher->data);
184 |
185 | mylog(log_trace, "conn_timer_cb() called\n");
186 |
187 | // uint64_t value;
188 | // read(conn_info.timer.get_timer_fd(), &value, 8);
189 |
190 | if (udp_dest.inner.fd_addr.addr.is_vaild() == 0) {
191 | return;
192 | }
193 | conn_info.stat.report_as_server(udp_dest.inner.fd_addr.addr);
194 | do_keep_alive(udp_dest);
195 | }
196 |
197 | static void prepare_cb(struct ev_loop *loop, struct ev_prepare *watcher, int revents) {
198 | assert(!(revents & EV_ERROR));
199 |
200 | delay_manager.check();
201 | }
202 |
203 | int tun_dev_server_event_loop() {
204 | int i, j, k, ret;
205 | int tun_fd;
206 | int local_listen_fd;
207 |
208 | conn_info_t *conn_info_p = new conn_info_t;
209 | conn_info_t &conn_info = *conn_info_p; // huge size of conn_info,do not allocate on stack
210 |
211 | tun_fd = get_tun_fd(tun_dev);
212 | assert(tun_fd > 0);
213 |
214 | assert(new_listen_socket2(local_listen_fd, local_addr) == 0);
215 | assert(set_tun(tun_dev, htonl((ntohl(sub_net_uint32) & 0xFFFFFF00) | 1), htonl((ntohl(sub_net_uint32) & 0xFFFFFF00) | 2), tun_mtu) == 0);
216 |
217 | udp_dest.cook = 1;
218 | udp_dest.type = type_fd_addr;
219 |
220 | udp_dest.inner.fd_addr.fd = local_listen_fd;
221 | udp_dest.inner.fd_addr.addr.clear();
222 |
223 | tun_dest.type = type_write_fd;
224 | tun_dest.inner.fd = tun_fd;
225 |
226 | /// epoll_fd = epoll_create1(0);
227 | /// assert(epoll_fd>0);
228 |
229 | /// const int max_events = 4096;
230 | /// struct epoll_event ev, events[max_events];
231 | /// if (epoll_fd < 0) {
232 | /// mylog(log_fatal,"epoll return %d\n", epoll_fd);
233 | /// myexit(-1);
234 | /// }
235 |
236 | struct ev_loop *loop = ev_default_loop(0);
237 | assert(loop != NULL);
238 | conn_info.loop = loop;
239 |
240 | /// ev.events = EPOLLIN;
241 | /// ev.data.u64 = local_listen_fd;
242 | /// ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, local_listen_fd, &ev);
243 | /// if (ret!=0) {
244 | /// mylog(log_fatal,"add udp_listen_fd error\n");
245 | /// myexit(-1);
246 | /// }
247 |
248 | struct ev_io local_listen_watcher;
249 | local_listen_watcher.data = &conn_info;
250 | ev_io_init(&local_listen_watcher, local_listen_cb, local_listen_fd, EV_READ);
251 | ev_io_start(loop, &local_listen_watcher);
252 |
253 | /// ev.events = EPOLLIN;
254 | /// ev.data.u64 = tun_fd;
255 | /// ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, tun_fd, &ev);
256 | /// if (ret!=0) {
257 | /// mylog(log_fatal,"add tun_fd error\n");
258 | /// myexit(-1);
259 | /// }
260 |
261 | struct ev_io tun_fd_watcher;
262 | tun_fd_watcher.data = &conn_info;
263 |
264 | ev_io_init(&tun_fd_watcher, tun_fd_cb, tun_fd, EV_READ);
265 | ev_io_start(loop, &tun_fd_watcher);
266 |
267 | /// ev.events = EPOLLIN;
268 | /// ev.data.u64 = delay_manager.get_timer_fd();
269 |
270 | /// mylog(log_debug,"delay_manager.get_timer_fd()=%d\n",delay_manager.get_timer_fd());
271 | /// ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, delay_manager.get_timer_fd(), &ev);
272 | /// if (ret!= 0) {
273 | /// mylog(log_fatal,"add delay_manager.get_timer_fd() error\n");
274 | /// myexit(-1);
275 | /// }
276 |
277 | delay_manager.set_loop_and_cb(loop, delay_manager_cb);
278 |
279 | /// u64_t tmp_timer_fd64=conn_info.fec_encode_manager.get_timer_fd64();
280 | /// ev.events = EPOLLIN;
281 | /// ev.data.u64 = tmp_timer_fd64;
282 |
283 | /// mylog(log_debug,"conn_info.fec_encode_manager.get_timer_fd64()=%llu\n",conn_info.fec_encode_manager.get_timer_fd64());
284 | /// ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd_manager.to_fd(tmp_timer_fd64), &ev);
285 | /// if (ret!= 0) {
286 | /// mylog(log_fatal,"add fec_encode_manager.get_timer_fd64() error\n");
287 | /// myexit(-1);
288 | /// }
289 |
290 | conn_info.fec_encode_manager.set_data(&conn_info);
291 | conn_info.fec_encode_manager.set_loop_and_cb(loop, fec_encode_cb);
292 |
293 | /// conn_info.timer.add_fd_to_epoll(epoll_fd);
294 | /// conn_info.timer.set_timer_repeat_us(timer_interval*1000);
295 |
296 | conn_info.timer.data = &conn_info;
297 | ev_init(&conn_info.timer, conn_timer_cb);
298 | ev_timer_set(&conn_info.timer, 0, timer_interval / 1000.0);
299 | ev_timer_start(loop, &conn_info.timer);
300 |
301 | struct ev_io fifo_watcher;
302 | int fifo_fd = -1;
303 |
304 | if (fifo_file[0] != 0) {
305 | fifo_fd = create_fifo(fifo_file);
306 |
307 | ev_io_init(&fifo_watcher, fifo_cb, fifo_fd, EV_READ);
308 | ev_io_start(loop, &fifo_watcher);
309 |
310 | mylog(log_info, "fifo_file=%s\n", fifo_file);
311 | }
312 |
313 | ev_prepare prepare_watcher;
314 | ev_init(&prepare_watcher, prepare_cb);
315 | ev_prepare_start(loop, &prepare_watcher);
316 |
317 | mylog(log_info, "now listening at %s\n", local_addr.get_str());
318 |
319 | ev_run(loop, 0);
320 |
321 | mylog(log_warn, "ev_run returned\n");
322 | myexit(0);
323 |
324 | return 0;
325 | }
326 |
--------------------------------------------------------------------------------