Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c3d557f5d | ||
|
|
2dea3a718d |
+108
-108
@@ -1,108 +1,108 @@
|
|||||||
# 手动运行说明
|
# 手动运行说明
|
||||||
大部分情况通过<https://console.openp2p.cn> 操作即可。有些情况需要手动运行
|
大部分情况通过<https://console.openp2p.cn> 操作即可。有些情况需要手动运行
|
||||||
> :warning: 本文所有命令, Windows环境使用"openp2p.exe", Linux环境使用"./openp2p"
|
> :warning: 本文所有命令, Windows环境使用"openp2p.exe", Linux环境使用"./openp2p"
|
||||||
|
|
||||||
|
|
||||||
## 安装和监听
|
## 安装和监听
|
||||||
```
|
```
|
||||||
./openp2p install -node OFFICEPC1 -token TOKEN
|
./openp2p install -node OFFICEPC1 -token TOKEN
|
||||||
或
|
或
|
||||||
./openp2p -d -node OFFICEPC1 -token TOKEN
|
./openp2p -d -node OFFICEPC1 -token TOKEN
|
||||||
# 注意Windows系统把“./openp2p” 换成“openp2p.exe”
|
# 注意Windows系统把“./openp2p” 换成“openp2p.exe”
|
||||||
```
|
```
|
||||||
>* install: 安装模式【推荐】,会安装成系统服务,这样它就能随系统自动启动
|
>* install: 安装模式【推荐】,会安装成系统服务,这样它就能随系统自动启动
|
||||||
>* -d: daemon模式。发现worker进程意外退出就会自动启动新的worker进程
|
>* -d: daemon模式。发现worker进程意外退出就会自动启动新的worker进程
|
||||||
>* -node: 独一无二的节点名字,唯一标识
|
>* -node: 独一无二的节点名字,唯一标识
|
||||||
>* -token: 在<console.openp2p.cn>“我的”里面找到
|
>* -token: 在<console.openp2p.cn>“我的”里面找到
|
||||||
>* -sharebandwidth: 作为共享节点时提供带宽,默认10mbps. 如果是光纤大带宽,设置越大效果越好. 0表示不共享,该节点只在私有的P2P网络使用。不加入共享的P2P网络,这样也意味着无法使用别人的共享节点
|
>* -sharebandwidth: 作为共享节点时提供带宽,默认10mbps. 如果是光纤大带宽,设置越大效果越好. 0表示不共享,该节点只在私有的P2P网络使用。不加入共享的P2P网络,这样也意味着无法使用别人的共享节点
|
||||||
>* -loglevel: 需要查看更多调试日志,设置0;默认是1
|
>* -loglevel: 需要查看更多调试日志,设置0;默认是1
|
||||||
|
|
||||||
### 在docker容器里运行openp2p
|
### 在docker容器里运行openp2p
|
||||||
我们暂时还没提供官方docker镜像,你可以在随便一个容器里运行
|
我们暂时还没提供官方docker镜像,你可以在随便一个容器里运行
|
||||||
```
|
```
|
||||||
nohup ./openp2p -d -node OFFICEPC1 -token TOKEN &
|
nohup ./openp2p -d -node OFFICEPC1 -token TOKEN &
|
||||||
#这里由于一般的镜像都精简过,install系统服务会失败,所以使用直接daemon模式后台运行
|
#这里由于一般的镜像都精简过,install系统服务会失败,所以使用直接daemon模式后台运行
|
||||||
```
|
```
|
||||||
## 连接
|
## 连接
|
||||||
```
|
```
|
||||||
./openp2p -d -node HOMEPC123 -token TOKEN -appname OfficeWindowsRemote -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 3389 -srcport 23389
|
./openp2p -d -node HOMEPC123 -token TOKEN -appname OfficeWindowsRemote -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 3389 -srcport 23389
|
||||||
使用配置文件,建立多个P2PApp
|
使用配置文件,建立多个P2PApp
|
||||||
./openp2p -d
|
./openp2p -d
|
||||||
```
|
```
|
||||||
>* -appname: 这个P2P应用名字
|
>* -appname: 这个P2P应用名字
|
||||||
>* -peernode: 目标节点名字
|
>* -peernode: 目标节点名字
|
||||||
>* -dstip: 目标服务地址,默认本机127.0.0.1
|
>* -dstip: 目标服务地址,默认本机127.0.0.1
|
||||||
>* -dstport: 目标服务端口,常见的如windows远程桌面3389,Linux ssh 22
|
>* -dstport: 目标服务端口,常见的如windows远程桌面3389,Linux ssh 22
|
||||||
>* -protocol: 目标服务协议 tcp、udp
|
>* -protocol: 目标服务协议 tcp、udp
|
||||||
|
|
||||||
## 配置文件
|
## 配置文件
|
||||||
一般保存在当前目录,安装模式下会保存到 `C:\Program Files\OpenP2P\config.json` 或 `/usr/local/openp2p/config.json`
|
一般保存在当前目录,安装模式下会保存到 `C:\Program Files\OpenP2P\config.json` 或 `/usr/local/openp2p/config.json`
|
||||||
希望修改参数,或者配置多个P2PApp可手动修改配置文件
|
希望修改参数,或者配置多个P2PApp可手动修改配置文件
|
||||||
|
|
||||||
配置实例
|
配置实例
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"network": {
|
"network": {
|
||||||
"Node": "YOUR-NODE-NAME",
|
"Node": "YOUR-NODE-NAME",
|
||||||
"Token": "TOKEN",
|
"Token": "TOKEN",
|
||||||
"ShareBandwidth": 0,
|
"ShareBandwidth": 0,
|
||||||
"ServerHost": "api.openp2p.cn",
|
"ServerHost": "api.openp2p.cn",
|
||||||
"ServerPort": 27183,
|
"ServerPort": 27183,
|
||||||
"UDPPort1": 27182,
|
"UDPPort1": 27182,
|
||||||
"UDPPort2": 27183
|
"UDPPort2": 27183
|
||||||
},
|
},
|
||||||
"apps": [
|
"apps": [
|
||||||
{
|
{
|
||||||
"AppName": "OfficeWindowsPC",
|
"AppName": "OfficeWindowsPC",
|
||||||
"Protocol": "tcp",
|
"Protocol": "tcp",
|
||||||
"SrcPort": 23389,
|
"SrcPort": 23389,
|
||||||
"PeerNode": "OFFICEPC1",
|
"PeerNode": "OFFICEPC1",
|
||||||
"DstPort": 3389,
|
"DstPort": 3389,
|
||||||
"DstHost": "localhost",
|
"DstHost": "localhost",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"AppName": "OfficeServerSSH",
|
"AppName": "OfficeServerSSH",
|
||||||
"Protocol": "tcp",
|
"Protocol": "tcp",
|
||||||
"SrcPort": 22,
|
"SrcPort": 22,
|
||||||
"PeerNode": "OFFICEPC1",
|
"PeerNode": "OFFICEPC1",
|
||||||
"DstPort": 22,
|
"DstPort": 22,
|
||||||
"DstHost": "192.168.1.5",
|
"DstHost": "192.168.1.5",
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 升级客户端
|
## 升级客户端
|
||||||
```
|
```
|
||||||
# update local client
|
# update local client
|
||||||
./openp2p update
|
./openp2p update
|
||||||
# update remote client
|
# update remote client
|
||||||
curl --insecure 'https://api.openp2p.cn:27183/api/v1/device/YOUR-NODE-NAME/update?user=&password='
|
curl --insecure 'https://api.openp2p.cn:27183/api/v1/device/YOUR-NODE-NAME/update?user=&password='
|
||||||
```
|
```
|
||||||
|
|
||||||
Windows系统需要设置防火墙放行本程序,程序会自动设置,如果设置失败会影响连接功能。
|
Windows系统需要设置防火墙放行本程序,程序会自动设置,如果设置失败会影响连接功能。
|
||||||
Linux系统(Ubuntu和CentOS7)的防火墙默认配置均不会有影响,如果不行可尝试关闭防火墙
|
Linux系统(Ubuntu和CentOS7)的防火墙默认配置均不会有影响,如果不行可尝试关闭防火墙
|
||||||
```
|
```
|
||||||
systemctl stop firewalld.service
|
systemctl stop firewalld.service
|
||||||
systemctl start firewalld.service
|
systemctl start firewalld.service
|
||||||
firewall-cmd --state
|
firewall-cmd --state
|
||||||
```
|
```
|
||||||
## 停止
|
## 停止
|
||||||
TODO: windows linux macos
|
TODO: windows linux macos
|
||||||
## 卸载
|
## 卸载
|
||||||
```
|
```
|
||||||
./openp2p uninstall
|
./openp2p uninstall
|
||||||
# 已安装时
|
# 已安装时
|
||||||
# windows
|
# windows
|
||||||
C:\Program Files\OpenP2P\openp2p.exe uninstall
|
C:\Program Files\OpenP2P\openp2p.exe uninstall
|
||||||
# linux,macos
|
# linux,macos
|
||||||
sudo /usr/local/openp2p/openp2p uninstall
|
sudo /usr/local/openp2p/openp2p uninstall
|
||||||
```
|
```
|
||||||
|
|
||||||
## Docker运行
|
## Docker运行
|
||||||
```
|
```
|
||||||
# 把YOUR-TOKEN和YOUR-NODE-NAME替换成自己的
|
# 把YOUR-TOKEN和YOUR-NODE-NAME替换成自己的
|
||||||
docker run -d --restart=always --net host --name openp2p-client -e OPENP2P_TOKEN=YOUR-TOKEN -e OPENP2P_NODE=YOUR-NODE-NAME openp2pcn/openp2p-client:latest
|
docker run -d --restart=always --net host --name openp2p-client -e OPENP2P_TOKEN=YOUR-TOKEN -e OPENP2P_NODE=YOUR-NODE-NAME openp2pcn/openp2p-client:latest
|
||||||
OR
|
OR
|
||||||
docker run -d --restart=always --net host --name openp2p-client openp2pcn/openp2p-client:latest -token YOUR-TOKEN -node YOUR-NODE-NAME
|
docker run -d --restart=always --net host --name openp2p-client openp2pcn/openp2p-client:latest -token YOUR-TOKEN -node YOUR-NODE-NAME
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,109 +1,109 @@
|
|||||||
|
|
||||||
|
|
||||||
# Parameters details
|
# Parameters details
|
||||||
In most cases, you can operate it through <https://console.openp2p.cn>. In some cases it is necessary to run manually
|
In most cases, you can operate it through <https://console.openp2p.cn>. In some cases it is necessary to run manually
|
||||||
> :warning: all commands in this doc, Windows env uses "openp2p.exe", Linux env uses "./openp2p"
|
> :warning: all commands in this doc, Windows env uses "openp2p.exe", Linux env uses "./openp2p"
|
||||||
|
|
||||||
|
|
||||||
## Install and Listen
|
## Install and Listen
|
||||||
```
|
```
|
||||||
./openp2p install -node OFFICEPC1 -token TOKEN
|
./openp2p install -node OFFICEPC1 -token TOKEN
|
||||||
Or
|
Or
|
||||||
./openp2p -d -node OFFICEPC1 -token TOKEN
|
./openp2p -d -node OFFICEPC1 -token TOKEN
|
||||||
|
|
||||||
```
|
```
|
||||||
>* install: [recommand] will install as system service. So it will autorun when system booting.
|
>* install: [recommand] will install as system service. So it will autorun when system booting.
|
||||||
>* -d: daemon mode run once. When the worker process is found to exit unexpectedly, a new worker process will be automatically started
|
>* -d: daemon mode run once. When the worker process is found to exit unexpectedly, a new worker process will be automatically started
|
||||||
>* -node: Unique node name, unique identification
|
>* -node: Unique node name, unique identification
|
||||||
>* -token: See <console.openp2p.cn> "Profile"
|
>* -token: See <console.openp2p.cn> "Profile"
|
||||||
>* -sharebandwidth: Provides bandwidth when used as a shared node, the default is 10mbps. If it is a large bandwidth of optical fiber, the larger the setting, the better the effect. 0 means not shared, the node is only used in a private P2P network. Do not join the shared P2P network, which also means that you CAN NOT use other people’s shared nodes
|
>* -sharebandwidth: Provides bandwidth when used as a shared node, the default is 10mbps. If it is a large bandwidth of optical fiber, the larger the setting, the better the effect. 0 means not shared, the node is only used in a private P2P network. Do not join the shared P2P network, which also means that you CAN NOT use other people’s shared nodes
|
||||||
>* -loglevel: Need to view more debug logs, set 0; the default is 1
|
>* -loglevel: Need to view more debug logs, set 0; the default is 1
|
||||||
|
|
||||||
### Run in Docker container
|
### Run in Docker container
|
||||||
We don't provide official docker image yet, you can run it in any container
|
We don't provide official docker image yet, you can run it in any container
|
||||||
```
|
```
|
||||||
nohup ./openp2p -d -node OFFICEPC1 -token TOKEN &
|
nohup ./openp2p -d -node OFFICEPC1 -token TOKEN &
|
||||||
# Since many docker images have been simplified, the install system service will fail, so the daemon mode is used to run in the background
|
# Since many docker images have been simplified, the install system service will fail, so the daemon mode is used to run in the background
|
||||||
```
|
```
|
||||||
|
|
||||||
## Connect
|
## Connect
|
||||||
```
|
```
|
||||||
./openp2p -d -node HOMEPC123 -token TOKEN -appname OfficeWindowsRemote -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 3389 -srcport 23389
|
./openp2p -d -node HOMEPC123 -token TOKEN -appname OfficeWindowsRemote -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 3389 -srcport 23389
|
||||||
Create multiple P2PApp by config file
|
Create multiple P2PApp by config file
|
||||||
./openp2p -d
|
./openp2p -d
|
||||||
```
|
```
|
||||||
>* -appname: This P2PApp name
|
>* -appname: This P2PApp name
|
||||||
>* -peernode: Target node name
|
>* -peernode: Target node name
|
||||||
>* -dstip: Target service address, default local 127.0.0.1
|
>* -dstip: Target service address, default local 127.0.0.1
|
||||||
>* -dstport: Target service port, such as windows remote desktop 3389, Linux ssh 22
|
>* -dstport: Target service port, such as windows remote desktop 3389, Linux ssh 22
|
||||||
>* -protocol: Target service protocol tcp, udp
|
>* -protocol: Target service protocol tcp, udp
|
||||||
|
|
||||||
## Config file
|
## Config file
|
||||||
Generally saved in the current directory, in installation mode it will be saved to `C:\Program Files\OpenP2P\config.json` or `/usr/local/openp2p/config.json`
|
Generally saved in the current directory, in installation mode it will be saved to `C:\Program Files\OpenP2P\config.json` or `/usr/local/openp2p/config.json`
|
||||||
If you want to modify the parameters, or configure multiple P2PApps, you can manually modify the configuration file
|
If you want to modify the parameters, or configure multiple P2PApps, you can manually modify the configuration file
|
||||||
|
|
||||||
Configuration example
|
Configuration example
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"network": {
|
"network": {
|
||||||
"Node": "YOUR-NODE-NAME",
|
"Node": "YOUR-NODE-NAME",
|
||||||
"Token": "TOKEN",
|
"Token": "TOKEN",
|
||||||
"ShareBandwidth": 0,
|
"ShareBandwidth": 0,
|
||||||
"ServerHost": "api.openp2p.cn",
|
"ServerHost": "api.openp2p.cn",
|
||||||
"ServerPort": 27183,
|
"ServerPort": 27183,
|
||||||
"UDPPort1": 27182,
|
"UDPPort1": 27182,
|
||||||
"UDPPort2": 27183
|
"UDPPort2": 27183
|
||||||
},
|
},
|
||||||
"apps": [
|
"apps": [
|
||||||
{
|
{
|
||||||
"AppName": "OfficeWindowsPC",
|
"AppName": "OfficeWindowsPC",
|
||||||
"Protocol": "tcp",
|
"Protocol": "tcp",
|
||||||
"SrcPort": 23389,
|
"SrcPort": 23389,
|
||||||
"PeerNode": "OFFICEPC1",
|
"PeerNode": "OFFICEPC1",
|
||||||
"DstPort": 3389,
|
"DstPort": 3389,
|
||||||
"DstHost": "localhost",
|
"DstHost": "localhost",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"AppName": "OfficeServerSSH",
|
"AppName": "OfficeServerSSH",
|
||||||
"Protocol": "tcp",
|
"Protocol": "tcp",
|
||||||
"SrcPort": 22,
|
"SrcPort": 22,
|
||||||
"PeerNode": "OFFICEPC1",
|
"PeerNode": "OFFICEPC1",
|
||||||
"DstPort": 22,
|
"DstPort": 22,
|
||||||
"DstHost": "192.168.1.5",
|
"DstHost": "192.168.1.5",
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
## Client update
|
## Client update
|
||||||
```
|
```
|
||||||
# update local client
|
# update local client
|
||||||
./openp2p update
|
./openp2p update
|
||||||
# update remote client
|
# update remote client
|
||||||
curl --insecure 'https://api.openp2p.cn:27183/api/v1/device/YOUR-NODE-NAME/update?user=&password='
|
curl --insecure 'https://api.openp2p.cn:27183/api/v1/device/YOUR-NODE-NAME/update?user=&password='
|
||||||
```
|
```
|
||||||
|
|
||||||
Windows system needs to set up firewall for this program, the program will automatically set the firewall, if the setting fails, the UDP punching will be affected.
|
Windows system needs to set up firewall for this program, the program will automatically set the firewall, if the setting fails, the UDP punching will be affected.
|
||||||
The default firewall configuration of Linux system (Ubuntu and CentOS7) will not have any effect, if not, you can try to turn off the firewall
|
The default firewall configuration of Linux system (Ubuntu and CentOS7) will not have any effect, if not, you can try to turn off the firewall
|
||||||
```
|
```
|
||||||
systemctl stop firewalld.service
|
systemctl stop firewalld.service
|
||||||
systemctl start firewalld.service
|
systemctl start firewalld.service
|
||||||
firewall-cmd --state
|
firewall-cmd --state
|
||||||
```
|
```
|
||||||
|
|
||||||
## Uninstall
|
## Uninstall
|
||||||
```
|
```
|
||||||
./openp2p uninstall
|
./openp2p uninstall
|
||||||
# when already installed
|
# when already installed
|
||||||
# windows
|
# windows
|
||||||
C:\Program Files\OpenP2P\openp2p.exe uninstall
|
C:\Program Files\OpenP2P\openp2p.exe uninstall
|
||||||
# linux,macos
|
# linux,macos
|
||||||
sudo /usr/local/openp2p/openp2p uninstall
|
sudo /usr/local/openp2p/openp2p uninstall
|
||||||
```
|
```
|
||||||
|
|
||||||
## Run with Docker
|
## Run with Docker
|
||||||
```
|
```
|
||||||
# Replace YOUR-TOKEN and YOUR-NODE-NAME with yours
|
# Replace YOUR-TOKEN and YOUR-NODE-NAME with yours
|
||||||
docker run -d --net host --name openp2p-client -e OPENP2P_TOKEN=YOUR-TOKEN -e OPENP2P_NODE=YOUR-NODE-NAME openp2pcn/openp2p-client:latest
|
docker run -d --net host --name openp2p-client -e OPENP2P_TOKEN=YOUR-TOKEN -e OPENP2P_NODE=YOUR-NODE-NAME openp2pcn/openp2p-client:latest
|
||||||
OR
|
OR
|
||||||
docker run -d --net host --name openp2p-client openp2pcn/openp2p-client:latest -token YOUR-TOKEN -node YOUR-NODE-NAME
|
docker run -d --net host --name openp2p-client openp2pcn/openp2p-client:latest -token YOUR-TOKEN -node YOUR-NODE-NAME
|
||||||
```
|
```
|
||||||
+9
-9
@@ -1,9 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
op "openp2p/core"
|
op "openp2p/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
op.Run()
|
op.Run()
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-4
@@ -3,6 +3,7 @@ package openp2p
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -28,6 +29,7 @@ type AppConfig struct {
|
|||||||
ForceRelay int // default:0 disable;1 enable
|
ForceRelay int // default:0 disable;1 enable
|
||||||
Enabled int // default:1
|
Enabled int // default:1
|
||||||
// runtime info
|
// runtime info
|
||||||
|
relayMode string // private|public
|
||||||
peerVersion string
|
peerVersion string
|
||||||
peerToken uint64
|
peerToken uint64
|
||||||
peerNatType int
|
peerNatType int
|
||||||
@@ -64,6 +66,13 @@ func (c *AppConfig) ID() uint64 {
|
|||||||
return uint64(c.SrcPort)*10 + 1
|
return uint64(c.SrcPort)*10 + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *AppConfig) LogPeerNode() string {
|
||||||
|
if c.relayMode == "public" { // memapp
|
||||||
|
return fmt.Sprintf("%d", NodeNameToID(c.PeerNode))
|
||||||
|
}
|
||||||
|
return c.PeerNode
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Network NetworkConfig `json:"network"`
|
Network NetworkConfig `json:"network"`
|
||||||
Apps []*AppConfig `json:"apps"`
|
Apps []*AppConfig `json:"apps"`
|
||||||
@@ -147,7 +156,7 @@ func (c *Config) retryApp(peerNode string) {
|
|||||||
GNetwork.apps.Range(func(id, i interface{}) bool {
|
GNetwork.apps.Range(func(id, i interface{}) bool {
|
||||||
app := i.(*p2pApp)
|
app := i.(*p2pApp)
|
||||||
if app.config.PeerNode == peerNode {
|
if app.config.PeerNode == peerNode {
|
||||||
gLog.Println(LvDEBUG, "retry app ", peerNode)
|
gLog.Println(LvDEBUG, "retry app ", app.config.LogPeerNode())
|
||||||
app.config.retryNum = 0
|
app.config.retryNum = 0
|
||||||
app.config.nextRetryTime = time.Now()
|
app.config.nextRetryTime = time.Now()
|
||||||
app.retryRelayNum = 0
|
app.retryRelayNum = 0
|
||||||
@@ -157,7 +166,7 @@ func (c *Config) retryApp(peerNode string) {
|
|||||||
app.hbMtx.Unlock()
|
app.hbMtx.Unlock()
|
||||||
}
|
}
|
||||||
if app.config.RelayNode == peerNode {
|
if app.config.RelayNode == peerNode {
|
||||||
gLog.Println(LvDEBUG, "retry app ", peerNode)
|
gLog.Println(LvDEBUG, "retry app ", app.config.LogPeerNode())
|
||||||
app.retryRelayNum = 0
|
app.retryRelayNum = 0
|
||||||
app.nextRetryRelayTime = time.Now()
|
app.nextRetryRelayTime = time.Now()
|
||||||
app.hbMtx.Lock()
|
app.hbMtx.Lock()
|
||||||
@@ -171,7 +180,7 @@ func (c *Config) retryApp(peerNode string) {
|
|||||||
func (c *Config) retryAllApp() {
|
func (c *Config) retryAllApp() {
|
||||||
GNetwork.apps.Range(func(id, i interface{}) bool {
|
GNetwork.apps.Range(func(id, i interface{}) bool {
|
||||||
app := i.(*p2pApp)
|
app := i.(*p2pApp)
|
||||||
gLog.Println(LvDEBUG, "retry app ", app.config.PeerNode)
|
gLog.Println(LvDEBUG, "retry app ", app.config.LogPeerNode())
|
||||||
app.config.retryNum = 0
|
app.config.retryNum = 0
|
||||||
app.config.nextRetryTime = time.Now()
|
app.config.nextRetryTime = time.Now()
|
||||||
app.retryRelayNum = 0
|
app.retryRelayNum = 0
|
||||||
@@ -189,7 +198,7 @@ func (c *Config) retryAllMemApp() {
|
|||||||
if app.config.SrcPort != 0 {
|
if app.config.SrcPort != 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
gLog.Println(LvDEBUG, "retry app ", app.config.PeerNode)
|
gLog.Println(LvDEBUG, "retry app ", app.config.LogPeerNode())
|
||||||
app.config.retryNum = 0
|
app.config.retryNum = 0
|
||||||
app.config.nextRetryTime = time.Now()
|
app.config.nextRetryTime = time.Now()
|
||||||
app.retryRelayNum = 0
|
app.retryRelayNum = 0
|
||||||
@@ -246,6 +255,9 @@ func (c *Config) delete(app AppConfig) {
|
|||||||
func (c *Config) save() {
|
func (c *Config) save() {
|
||||||
// c.mtx.Lock()
|
// c.mtx.Lock()
|
||||||
// defer c.mtx.Unlock() // internal call
|
// defer c.mtx.Unlock() // internal call
|
||||||
|
if c.Network.Token == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
data, _ := json.MarshalIndent(c, "", " ")
|
data, _ := json.MarshalIndent(c, "", " ")
|
||||||
err := os.WriteFile("config.json", data, 0644)
|
err := os.WriteFile("config.json", data, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -256,6 +268,9 @@ func (c *Config) save() {
|
|||||||
func (c *Config) saveCache() {
|
func (c *Config) saveCache() {
|
||||||
// c.mtx.Lock()
|
// c.mtx.Lock()
|
||||||
// defer c.mtx.Unlock() // internal call
|
// defer c.mtx.Unlock() // internal call
|
||||||
|
if c.Network.Token == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
data, _ := json.MarshalIndent(c, "", " ")
|
data, _ := json.MarshalIndent(c, "", " ")
|
||||||
err := os.WriteFile("config.json0", data, 0644)
|
err := os.WriteFile("config.json0", data, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+115
-115
@@ -1,115 +1,115 @@
|
|||||||
package openp2p
|
package openp2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/openp2p-cn/service"
|
"github.com/openp2p-cn/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
type daemon struct {
|
type daemon struct {
|
||||||
running bool
|
running bool
|
||||||
proc *os.Process
|
proc *os.Process
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *daemon) Start(s service.Service) error {
|
func (d *daemon) Start(s service.Service) error {
|
||||||
gLog.Println(LvINFO, "daemon start")
|
gLog.Println(LvINFO, "daemon start")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *daemon) Stop(s service.Service) error {
|
func (d *daemon) Stop(s service.Service) error {
|
||||||
gLog.Println(LvINFO, "service stop")
|
gLog.Println(LvINFO, "service stop")
|
||||||
d.running = false
|
d.running = false
|
||||||
if d.proc != nil {
|
if d.proc != nil {
|
||||||
gLog.Println(LvINFO, "stop worker")
|
gLog.Println(LvINFO, "stop worker")
|
||||||
d.proc.Kill()
|
d.proc.Kill()
|
||||||
}
|
}
|
||||||
if service.Interactive() {
|
if service.Interactive() {
|
||||||
gLog.Println(LvINFO, "stop daemon")
|
gLog.Println(LvINFO, "stop daemon")
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *daemon) run() {
|
func (d *daemon) run() {
|
||||||
gLog.Println(LvINFO, "daemon run start")
|
gLog.Println(LvINFO, "daemon run start")
|
||||||
defer gLog.Println(LvINFO, "daemon run end")
|
defer gLog.Println(LvINFO, "daemon run end")
|
||||||
d.running = true
|
d.running = true
|
||||||
binPath, _ := os.Executable()
|
binPath, _ := os.Executable()
|
||||||
mydir, err := os.Getwd()
|
mydir, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
gLog.Println(LvINFO, mydir)
|
gLog.Println(LvINFO, mydir)
|
||||||
conf := &service.Config{
|
conf := &service.Config{
|
||||||
Name: ProductName,
|
Name: ProductName,
|
||||||
DisplayName: ProductName,
|
DisplayName: ProductName,
|
||||||
Description: ProductName,
|
Description: ProductName,
|
||||||
Executable: binPath,
|
Executable: binPath,
|
||||||
}
|
}
|
||||||
|
|
||||||
s, _ := service.New(d, conf)
|
s, _ := service.New(d, conf)
|
||||||
go s.Run()
|
go s.Run()
|
||||||
var args []string
|
var args []string
|
||||||
// rm -d parameter
|
// rm -d parameter
|
||||||
for i := 0; i < len(os.Args); i++ {
|
for i := 0; i < len(os.Args); i++ {
|
||||||
if os.Args[i] == "-d" {
|
if os.Args[i] == "-d" {
|
||||||
args = append(os.Args[0:i], os.Args[i+1:]...)
|
args = append(os.Args[0:i], os.Args[i+1:]...)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
args = append(args, "-nv")
|
args = append(args, "-nv")
|
||||||
for {
|
for {
|
||||||
// start worker
|
// start worker
|
||||||
tmpDump := filepath.Join("log", "dump.log.tmp")
|
tmpDump := filepath.Join("log", "dump.log.tmp")
|
||||||
dumpFile := filepath.Join("log", "dump.log")
|
dumpFile := filepath.Join("log", "dump.log")
|
||||||
f, err := os.Create(filepath.Join(tmpDump))
|
f, err := os.Create(filepath.Join(tmpDump))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvERROR, "start worker error:%s", err)
|
gLog.Printf(LvERROR, "start worker error:%s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
gLog.Println(LvINFO, "start worker process, args:", args)
|
gLog.Println(LvINFO, "start worker process, args:", args)
|
||||||
execSpec := &os.ProcAttr{Env: append(os.Environ(), "GOTRACEBACK=crash"), Files: []*os.File{os.Stdin, os.Stdout, f}}
|
execSpec := &os.ProcAttr{Env: append(os.Environ(), "GOTRACEBACK=crash"), Files: []*os.File{os.Stdin, os.Stdout, f}}
|
||||||
p, err := os.StartProcess(binPath, args, execSpec)
|
p, err := os.StartProcess(binPath, args, execSpec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvERROR, "start worker error:%s", err)
|
gLog.Printf(LvERROR, "start worker error:%s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
d.proc = p
|
d.proc = p
|
||||||
_, _ = p.Wait()
|
_, _ = p.Wait()
|
||||||
f.Close()
|
f.Close()
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
err = os.Rename(tmpDump, dumpFile)
|
err = os.Rename(tmpDump, dumpFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvERROR, "rename dump error:%s", err)
|
gLog.Printf(LvERROR, "rename dump error:%s", err)
|
||||||
}
|
}
|
||||||
if !d.running {
|
if !d.running {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
gLog.Printf(LvERROR, "worker stop, restart it after 10s")
|
gLog.Printf(LvERROR, "worker stop, restart it after 10s")
|
||||||
time.Sleep(time.Second * 10)
|
time.Sleep(time.Second * 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *daemon) Control(ctrlComm string, exeAbsPath string, args []string) error {
|
func (d *daemon) Control(ctrlComm string, exeAbsPath string, args []string) error {
|
||||||
svcConfig := &service.Config{
|
svcConfig := &service.Config{
|
||||||
Name: ProductName,
|
Name: ProductName,
|
||||||
DisplayName: ProductName,
|
DisplayName: ProductName,
|
||||||
Description: ProductName,
|
Description: ProductName,
|
||||||
Executable: exeAbsPath,
|
Executable: exeAbsPath,
|
||||||
Arguments: args,
|
Arguments: args,
|
||||||
}
|
}
|
||||||
|
|
||||||
s, e := service.New(d, svcConfig)
|
s, e := service.New(d, svcConfig)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
e = service.Control(s, ctrlComm)
|
e = service.Control(s, ctrlComm)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,4 +29,5 @@ var (
|
|||||||
ErrPeerConnectRelay = errors.New("peer connect relayNode error")
|
ErrPeerConnectRelay = errors.New("peer connect relayNode error")
|
||||||
ErrBuildTunnelBusy = errors.New("build tunnel busy")
|
ErrBuildTunnelBusy = errors.New("build tunnel busy")
|
||||||
ErrMemAppTunnelNotFound = errors.New("memapp tunnel not found")
|
ErrMemAppTunnelNotFound = errors.New("memapp tunnel not found")
|
||||||
|
ErrRemoteServiceUnable = errors.New("remote service unable")
|
||||||
)
|
)
|
||||||
|
|||||||
+482
-460
@@ -1,460 +1,482 @@
|
|||||||
package openp2p
|
package openp2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"net"
|
||||||
"path/filepath"
|
"os"
|
||||||
"reflect"
|
"path/filepath"
|
||||||
"runtime"
|
"reflect"
|
||||||
"time"
|
"runtime"
|
||||||
|
"time"
|
||||||
"github.com/openp2p-cn/totp"
|
|
||||||
)
|
"github.com/openp2p-cn/totp"
|
||||||
|
)
|
||||||
func handlePush(subType uint16, msg []byte) error {
|
|
||||||
pushHead := PushHeader{}
|
func handlePush(subType uint16, msg []byte) error {
|
||||||
err := binary.Read(bytes.NewReader(msg[openP2PHeaderSize:openP2PHeaderSize+PushHeaderSize]), binary.LittleEndian, &pushHead)
|
pushHead := PushHeader{}
|
||||||
if err != nil {
|
err := binary.Read(bytes.NewReader(msg[openP2PHeaderSize:openP2PHeaderSize+PushHeaderSize]), binary.LittleEndian, &pushHead)
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
gLog.Printf(LvDEBUG, "handle push msg type:%d, push header:%+v", subType, pushHead)
|
}
|
||||||
switch subType {
|
gLog.Printf(LvDEBUG, "handle push msg type:%d, push header:%+v", subType, pushHead)
|
||||||
case MsgPushConnectReq:
|
switch subType {
|
||||||
err = handleConnectReq(msg)
|
case MsgPushConnectReq:
|
||||||
case MsgPushRsp:
|
err = handleConnectReq(msg)
|
||||||
rsp := PushRsp{}
|
case MsgPushRsp:
|
||||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &rsp); err != nil {
|
rsp := PushRsp{}
|
||||||
gLog.Printf(LvERROR, "wrong pushRsp:%s", err)
|
if err = json.Unmarshal(msg[openP2PHeaderSize:], &rsp); err != nil {
|
||||||
return err
|
gLog.Printf(LvERROR, "wrong pushRsp:%s", err)
|
||||||
}
|
return err
|
||||||
if rsp.Error == 0 {
|
}
|
||||||
gLog.Printf(LvDEBUG, "push ok, detail:%s", rsp.Detail)
|
if rsp.Error == 0 {
|
||||||
} else {
|
gLog.Printf(LvDEBUG, "push ok, detail:%s", rsp.Detail)
|
||||||
gLog.Printf(LvERROR, "push error:%d, detail:%s", rsp.Error, rsp.Detail)
|
} else {
|
||||||
}
|
gLog.Printf(LvERROR, "push error:%d, detail:%s", rsp.Error, rsp.Detail)
|
||||||
case MsgPushAddRelayTunnelReq:
|
}
|
||||||
req := AddRelayTunnelReq{}
|
case MsgPushAddRelayTunnelReq:
|
||||||
if err = json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req); err != nil {
|
req := AddRelayTunnelReq{}
|
||||||
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
if err = json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req); err != nil {
|
||||||
return err
|
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
||||||
}
|
return err
|
||||||
config := AppConfig{}
|
}
|
||||||
config.PeerNode = req.RelayName
|
config := AppConfig{}
|
||||||
config.peerToken = req.RelayToken
|
config.PeerNode = req.RelayName
|
||||||
go func(r AddRelayTunnelReq) {
|
config.peerToken = req.RelayToken
|
||||||
t, errDt := GNetwork.addDirectTunnel(config, 0)
|
config.relayMode = req.RelayMode
|
||||||
if errDt == nil {
|
go func(r AddRelayTunnelReq) {
|
||||||
// notify peer relay ready
|
t, errDt := GNetwork.addDirectTunnel(config, 0)
|
||||||
msg := TunnelMsg{ID: t.id}
|
if errDt == nil {
|
||||||
GNetwork.push(r.From, MsgPushAddRelayTunnelRsp, msg)
|
// notify peer relay ready
|
||||||
appConfig := config
|
msg := TunnelMsg{ID: t.id}
|
||||||
appConfig.PeerNode = req.From
|
GNetwork.push(r.From, MsgPushAddRelayTunnelRsp, msg)
|
||||||
} else {
|
appConfig := config
|
||||||
gLog.Printf(LvERROR, "addDirectTunnel error:%s", errDt)
|
appConfig.PeerNode = req.From
|
||||||
GNetwork.push(r.From, MsgPushAddRelayTunnelRsp, "error") // compatible with old version client, trigger unmarshal error
|
} else {
|
||||||
}
|
gLog.Printf(LvERROR, "addDirectTunnel error:%s", errDt)
|
||||||
}(req)
|
GNetwork.push(r.From, MsgPushAddRelayTunnelRsp, "error") // compatible with old version client, trigger unmarshal error
|
||||||
case MsgPushServerSideSaveMemApp:
|
}
|
||||||
req := ServerSideSaveMemApp{}
|
}(req)
|
||||||
if err = json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req); err != nil {
|
case MsgPushServerSideSaveMemApp:
|
||||||
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
req := ServerSideSaveMemApp{}
|
||||||
return err
|
if err = json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req); err != nil {
|
||||||
}
|
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
||||||
gLog.Println(LvDEBUG, "handle MsgPushServerSideSaveMemApp:", prettyJson(req))
|
return err
|
||||||
var existTunnel *P2PTunnel
|
}
|
||||||
i, ok := GNetwork.allTunnels.Load(req.TunnelID)
|
gLog.Println(LvDEBUG, "handle MsgPushServerSideSaveMemApp:", prettyJson(req))
|
||||||
if !ok {
|
var existTunnel *P2PTunnel
|
||||||
time.Sleep(time.Millisecond * 100)
|
i, ok := GNetwork.allTunnels.Load(req.TunnelID)
|
||||||
i, ok = GNetwork.allTunnels.Load(req.TunnelID) // retry sometimes will receive MsgPushServerSideSaveMemApp but p2ptunnel not store yet.
|
if !ok {
|
||||||
if !ok {
|
time.Sleep(time.Millisecond * 100)
|
||||||
gLog.Println(LvERROR, "handle MsgPushServerSideSaveMemApp error:", ErrMemAppTunnelNotFound)
|
i, ok = GNetwork.allTunnels.Load(req.TunnelID) // retry sometimes will receive MsgPushServerSideSaveMemApp but p2ptunnel not store yet.
|
||||||
return ErrMemAppTunnelNotFound
|
if !ok {
|
||||||
}
|
gLog.Println(LvERROR, "handle MsgPushServerSideSaveMemApp error:", ErrMemAppTunnelNotFound)
|
||||||
}
|
return ErrMemAppTunnelNotFound
|
||||||
existTunnel = i.(*P2PTunnel)
|
}
|
||||||
peerID := NodeNameToID(req.From)
|
}
|
||||||
existApp, appok := GNetwork.apps.Load(peerID)
|
existTunnel = i.(*P2PTunnel)
|
||||||
if appok {
|
peerID := NodeNameToID(req.From)
|
||||||
app := existApp.(*p2pApp)
|
existApp, appok := GNetwork.apps.Load(peerID)
|
||||||
app.config.AppName = fmt.Sprintf("%d", peerID)
|
if appok {
|
||||||
app.id = req.AppID
|
app := existApp.(*p2pApp)
|
||||||
app.setRelayTunnelID(req.RelayTunnelID)
|
app.config.AppName = fmt.Sprintf("%d", peerID)
|
||||||
app.relayMode = req.RelayMode
|
app.id = req.AppID
|
||||||
app.hbTimeRelay = time.Now()
|
app.setRelayTunnelID(req.RelayTunnelID)
|
||||||
if req.RelayTunnelID == 0 {
|
app.relayMode = req.RelayMode
|
||||||
app.setDirectTunnel(existTunnel)
|
app.hbTimeRelay = time.Now()
|
||||||
} else {
|
if req.RelayTunnelID == 0 {
|
||||||
app.setRelayTunnel(existTunnel)
|
app.setDirectTunnel(existTunnel)
|
||||||
}
|
} else {
|
||||||
gLog.Println(LvDEBUG, "find existing memapp, update it")
|
app.setRelayTunnel(existTunnel)
|
||||||
} else {
|
}
|
||||||
appConfig := existTunnel.config
|
gLog.Println(LvDEBUG, "find existing memapp, update it")
|
||||||
appConfig.SrcPort = 0
|
} else {
|
||||||
appConfig.Protocol = ""
|
appConfig := existTunnel.config
|
||||||
appConfig.AppName = fmt.Sprintf("%d", peerID)
|
appConfig.SrcPort = 0
|
||||||
appConfig.PeerNode = req.From
|
appConfig.Protocol = ""
|
||||||
app := p2pApp{
|
appConfig.AppName = fmt.Sprintf("%d", peerID)
|
||||||
id: req.AppID,
|
appConfig.PeerNode = req.From
|
||||||
config: appConfig,
|
app := p2pApp{
|
||||||
relayMode: req.RelayMode,
|
id: req.AppID,
|
||||||
running: true,
|
config: appConfig,
|
||||||
hbTimeRelay: time.Now(),
|
relayMode: req.RelayMode,
|
||||||
}
|
running: true,
|
||||||
if req.RelayTunnelID == 0 {
|
hbTimeRelay: time.Now(),
|
||||||
app.setDirectTunnel(existTunnel)
|
}
|
||||||
} else {
|
if req.RelayTunnelID == 0 {
|
||||||
app.setRelayTunnel(existTunnel)
|
app.setDirectTunnel(existTunnel)
|
||||||
app.setRelayTunnelID(req.RelayTunnelID)
|
} else {
|
||||||
}
|
app.setRelayTunnel(existTunnel)
|
||||||
if req.RelayTunnelID != 0 {
|
app.setRelayTunnelID(req.RelayTunnelID)
|
||||||
app.relayNode = req.Node
|
}
|
||||||
}
|
if req.RelayTunnelID != 0 {
|
||||||
GNetwork.apps.Store(NodeNameToID(req.From), &app)
|
app.relayNode = req.Node
|
||||||
}
|
}
|
||||||
|
GNetwork.apps.Store(NodeNameToID(req.From), &app)
|
||||||
return nil
|
}
|
||||||
case MsgPushAPPKey:
|
|
||||||
req := APPKeySync{}
|
return nil
|
||||||
if err = json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req); err != nil {
|
case MsgPushAPPKey:
|
||||||
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
req := APPKeySync{}
|
||||||
return err
|
if err = json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req); err != nil {
|
||||||
}
|
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
||||||
SaveKey(req.AppID, req.AppKey)
|
return err
|
||||||
case MsgPushUpdate:
|
}
|
||||||
gLog.Println(LvINFO, "MsgPushUpdate")
|
SaveKey(req.AppID, req.AppKey)
|
||||||
err := update(gConf.Network.ServerHost, gConf.Network.ServerPort)
|
case MsgPushUpdate:
|
||||||
if err == nil {
|
gLog.Println(LvINFO, "MsgPushUpdate")
|
||||||
os.Exit(0)
|
err := update(gConf.Network.ServerHost, gConf.Network.ServerPort)
|
||||||
}
|
if err == nil {
|
||||||
return err
|
os.Exit(0)
|
||||||
case MsgPushRestart:
|
}
|
||||||
gLog.Println(LvINFO, "MsgPushRestart")
|
return err
|
||||||
os.Exit(0)
|
case MsgPushRestart:
|
||||||
return err
|
gLog.Println(LvINFO, "MsgPushRestart")
|
||||||
case MsgPushReportApps:
|
os.Exit(0)
|
||||||
err = handleReportApps()
|
return err
|
||||||
case MsgPushReportMemApps:
|
case MsgPushReportApps:
|
||||||
err = handleReportMemApps()
|
err = handleReportApps()
|
||||||
case MsgPushReportLog:
|
case MsgPushReportMemApps:
|
||||||
err = handleLog(msg)
|
err = handleReportMemApps()
|
||||||
case MsgPushReportGoroutine:
|
case MsgPushReportLog:
|
||||||
err = handleReportGoroutine()
|
err = handleLog(msg)
|
||||||
case MsgPushEditApp:
|
case MsgPushReportGoroutine:
|
||||||
err = handleEditApp(msg)
|
err = handleReportGoroutine()
|
||||||
case MsgPushEditNode:
|
case MsgPushCheckRemoteService:
|
||||||
gLog.Println(LvINFO, "MsgPushEditNode")
|
err = handleCheckRemoteService(msg)
|
||||||
req := EditNode{}
|
case MsgPushEditApp:
|
||||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &req); err != nil {
|
err = handleEditApp(msg)
|
||||||
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(req), err, string(msg[openP2PHeaderSize:]))
|
case MsgPushEditNode:
|
||||||
return err
|
gLog.Println(LvINFO, "MsgPushEditNode")
|
||||||
}
|
req := EditNode{}
|
||||||
gConf.setNode(req.NewName)
|
if err = json.Unmarshal(msg[openP2PHeaderSize:], &req); err != nil {
|
||||||
gConf.setShareBandwidth(req.Bandwidth)
|
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(req), err, string(msg[openP2PHeaderSize:]))
|
||||||
os.Exit(0)
|
return err
|
||||||
case MsgPushSwitchApp:
|
}
|
||||||
gLog.Println(LvINFO, "MsgPushSwitchApp")
|
gConf.setNode(req.NewName)
|
||||||
app := AppInfo{}
|
gConf.setShareBandwidth(req.Bandwidth)
|
||||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &app); err != nil {
|
os.Exit(0)
|
||||||
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(app), err, string(msg[openP2PHeaderSize:]))
|
case MsgPushSwitchApp:
|
||||||
return err
|
gLog.Println(LvINFO, "MsgPushSwitchApp")
|
||||||
}
|
app := AppInfo{}
|
||||||
config := AppConfig{Enabled: app.Enabled, SrcPort: app.SrcPort, Protocol: app.Protocol}
|
if err = json.Unmarshal(msg[openP2PHeaderSize:], &app); err != nil {
|
||||||
gLog.Println(LvINFO, app.AppName, " switch to ", app.Enabled)
|
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(app), err, string(msg[openP2PHeaderSize:]))
|
||||||
gConf.switchApp(config, app.Enabled)
|
return err
|
||||||
if app.Enabled == 0 {
|
}
|
||||||
// disable APP
|
config := AppConfig{Enabled: app.Enabled, SrcPort: app.SrcPort, Protocol: app.Protocol}
|
||||||
GNetwork.DeleteApp(config)
|
gLog.Println(LvINFO, app.AppName, " switch to ", app.Enabled)
|
||||||
}
|
gConf.switchApp(config, app.Enabled)
|
||||||
case MsgPushDstNodeOnline:
|
if app.Enabled == 0 {
|
||||||
gLog.Println(LvINFO, "MsgPushDstNodeOnline")
|
// disable APP
|
||||||
req := PushDstNodeOnline{}
|
GNetwork.DeleteApp(config)
|
||||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &req); err != nil {
|
}
|
||||||
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(req), err, string(msg[openP2PHeaderSize:]))
|
case MsgPushDstNodeOnline:
|
||||||
return err
|
gLog.Println(LvINFO, "MsgPushDstNodeOnline")
|
||||||
}
|
req := PushDstNodeOnline{}
|
||||||
gLog.Println(LvINFO, "retry peerNode ", req.Node)
|
if err = json.Unmarshal(msg[openP2PHeaderSize:], &req); err != nil {
|
||||||
gConf.retryApp(req.Node)
|
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(req), err, string(msg[openP2PHeaderSize:]))
|
||||||
default:
|
return err
|
||||||
i, ok := GNetwork.msgMap.Load(pushHead.From)
|
}
|
||||||
if !ok {
|
gLog.Println(LvINFO, "retry peerNode ", req.Node)
|
||||||
return ErrMsgChannelNotFound
|
gConf.retryApp(req.Node)
|
||||||
}
|
default:
|
||||||
ch := i.(chan msgCtx)
|
i, ok := GNetwork.msgMap.Load(pushHead.From)
|
||||||
ch <- msgCtx{data: msg, ts: time.Now()}
|
if !ok {
|
||||||
}
|
return ErrMsgChannelNotFound
|
||||||
return err
|
}
|
||||||
}
|
ch := i.(chan msgCtx)
|
||||||
|
ch <- msgCtx{data: msg, ts: time.Now()}
|
||||||
func handleEditApp(msg []byte) (err error) {
|
}
|
||||||
gLog.Println(LvINFO, "MsgPushEditApp")
|
return err
|
||||||
newApp := AppInfo{}
|
}
|
||||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &newApp); err != nil {
|
|
||||||
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(newApp), err, string(msg[openP2PHeaderSize:]))
|
func handleEditApp(msg []byte) (err error) {
|
||||||
return err
|
gLog.Println(LvINFO, "MsgPushEditApp")
|
||||||
}
|
newApp := AppInfo{}
|
||||||
oldConf := AppConfig{Enabled: 1}
|
if err = json.Unmarshal(msg[openP2PHeaderSize:], &newApp); err != nil {
|
||||||
// protocol0+srcPort0 exist, delApp
|
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(newApp), err, string(msg[openP2PHeaderSize:]))
|
||||||
oldConf.AppName = newApp.AppName
|
return err
|
||||||
oldConf.Protocol = newApp.Protocol0
|
}
|
||||||
oldConf.Whitelist = newApp.Whitelist
|
oldConf := AppConfig{Enabled: 1}
|
||||||
oldConf.SrcPort = newApp.SrcPort0
|
// protocol0+srcPort0 exist, delApp
|
||||||
oldConf.PeerNode = newApp.PeerNode
|
oldConf.AppName = newApp.AppName
|
||||||
oldConf.DstHost = newApp.DstHost
|
oldConf.Protocol = newApp.Protocol0
|
||||||
oldConf.DstPort = newApp.DstPort
|
oldConf.Whitelist = newApp.Whitelist
|
||||||
if newApp.Protocol0 != "" && newApp.SrcPort0 != 0 { // not edit
|
oldConf.SrcPort = newApp.SrcPort0
|
||||||
gConf.delete(oldConf)
|
oldConf.PeerNode = newApp.PeerNode
|
||||||
}
|
oldConf.DstHost = newApp.DstHost
|
||||||
|
oldConf.DstPort = newApp.DstPort
|
||||||
// AddApp
|
if newApp.Protocol0 != "" && newApp.SrcPort0 != 0 { // not edit
|
||||||
newConf := oldConf
|
gConf.delete(oldConf)
|
||||||
newConf.Protocol = newApp.Protocol
|
}
|
||||||
newConf.SrcPort = newApp.SrcPort
|
|
||||||
newConf.RelayNode = newApp.SpecRelayNode
|
// AddApp
|
||||||
newConf.PunchPriority = newApp.PunchPriority
|
newConf := oldConf
|
||||||
gConf.add(newConf, false)
|
newConf.Protocol = newApp.Protocol
|
||||||
if newApp.Protocol0 != "" && newApp.SrcPort0 != 0 { // not edit
|
newConf.SrcPort = newApp.SrcPort
|
||||||
GNetwork.DeleteApp(oldConf) // DeleteApp may cost some times, execute at the end
|
newConf.RelayNode = newApp.SpecRelayNode
|
||||||
}
|
newConf.PunchPriority = newApp.PunchPriority
|
||||||
return nil
|
gConf.add(newConf, false)
|
||||||
}
|
if newApp.Protocol0 != "" && newApp.SrcPort0 != 0 { // not edit
|
||||||
|
GNetwork.DeleteApp(oldConf) // DeleteApp may cost some times, execute at the end
|
||||||
func handleConnectReq(msg []byte) (err error) {
|
}
|
||||||
req := PushConnectReq{}
|
return nil
|
||||||
if err = json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req); err != nil {
|
}
|
||||||
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
|
||||||
return err
|
func handleConnectReq(msg []byte) (err error) {
|
||||||
}
|
req := PushConnectReq{}
|
||||||
gLog.Printf(LvDEBUG, "%s is connecting...", req.From)
|
if err = json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req); err != nil {
|
||||||
gLog.Println(LvDEBUG, "push connect response to ", req.From)
|
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
||||||
if compareVersion(req.Version, LeastSupportVersion) < 0 {
|
return err
|
||||||
gLog.Println(LvERROR, ErrVersionNotCompatible.Error(), ":", req.From)
|
}
|
||||||
rsp := PushConnectRsp{
|
gLog.Printf(LvDEBUG, "%s is connecting...", req.From)
|
||||||
Error: 10,
|
gLog.Println(LvDEBUG, "push connect response to ", req.From)
|
||||||
Detail: ErrVersionNotCompatible.Error(),
|
if compareVersion(req.Version, LeastSupportVersion) < 0 {
|
||||||
To: req.From,
|
gLog.Println(LvERROR, ErrVersionNotCompatible.Error(), ":", req.From)
|
||||||
From: gConf.Network.Node,
|
rsp := PushConnectRsp{
|
||||||
}
|
Error: 10,
|
||||||
GNetwork.push(req.From, MsgPushConnectRsp, rsp)
|
Detail: ErrVersionNotCompatible.Error(),
|
||||||
return ErrVersionNotCompatible
|
To: req.From,
|
||||||
}
|
From: gConf.Network.Node,
|
||||||
// verify totp token or token
|
}
|
||||||
t := totp.TOTP{Step: totp.RelayTOTPStep}
|
GNetwork.push(req.From, MsgPushConnectRsp, rsp)
|
||||||
if t.Verify(req.Token, gConf.Network.Token, time.Now().Unix()-GNetwork.dt/int64(time.Second)) { // localTs may behind, auto adjust ts
|
return ErrVersionNotCompatible
|
||||||
gLog.Printf(LvINFO, "Access Granted")
|
}
|
||||||
config := AppConfig{}
|
// verify totp token or token
|
||||||
config.peerNatType = req.NatType
|
t := totp.TOTP{Step: totp.RelayTOTPStep}
|
||||||
config.peerConeNatPort = req.ConeNatPort
|
if t.Verify(req.Token, gConf.Network.Token, time.Now().Unix()-GNetwork.dt/int64(time.Second)) { // localTs may behind, auto adjust ts
|
||||||
config.peerIP = req.FromIP
|
gLog.Printf(LvINFO, "Access Granted")
|
||||||
config.PeerNode = req.From
|
config := AppConfig{}
|
||||||
config.peerVersion = req.Version
|
config.peerNatType = req.NatType
|
||||||
config.fromToken = req.Token
|
config.peerConeNatPort = req.ConeNatPort
|
||||||
config.peerIPv6 = req.IPv6
|
config.peerIP = req.FromIP
|
||||||
config.hasIPv4 = req.HasIPv4
|
config.PeerNode = req.From
|
||||||
config.hasUPNPorNATPMP = req.HasUPNPorNATPMP
|
config.peerVersion = req.Version
|
||||||
config.linkMode = req.LinkMode
|
config.fromToken = req.Token
|
||||||
config.isUnderlayServer = req.IsUnderlayServer
|
config.peerIPv6 = req.IPv6
|
||||||
config.UnderlayProtocol = req.UnderlayProtocol
|
config.hasIPv4 = req.HasIPv4
|
||||||
// share relay node will limit bandwidth
|
config.hasUPNPorNATPMP = req.HasUPNPorNATPMP
|
||||||
if req.Token != gConf.Network.Token {
|
config.linkMode = req.LinkMode
|
||||||
gLog.Printf(LvINFO, "set share bandwidth %d mbps", gConf.Network.ShareBandwidth)
|
config.isUnderlayServer = req.IsUnderlayServer
|
||||||
config.shareBandwidth = gConf.Network.ShareBandwidth
|
config.UnderlayProtocol = req.UnderlayProtocol
|
||||||
}
|
// share relay node will limit bandwidth
|
||||||
// go GNetwork.AddTunnel(config, req.ID)
|
if req.Token != gConf.Network.Token {
|
||||||
go func() {
|
gLog.Printf(LvINFO, "set share bandwidth %d mbps", gConf.Network.ShareBandwidth)
|
||||||
GNetwork.addDirectTunnel(config, req.ID)
|
config.shareBandwidth = gConf.Network.ShareBandwidth
|
||||||
}()
|
}
|
||||||
return nil
|
// go GNetwork.AddTunnel(config, req.ID)
|
||||||
}
|
go func() {
|
||||||
gLog.Println(LvERROR, "Access Denied:", req.From)
|
GNetwork.addDirectTunnel(config, req.ID)
|
||||||
rsp := PushConnectRsp{
|
}()
|
||||||
Error: 1,
|
return nil
|
||||||
Detail: fmt.Sprintf("connect to %s error: Access Denied", gConf.Network.Node),
|
}
|
||||||
To: req.From,
|
gLog.Println(LvERROR, "Access Denied:", req.From)
|
||||||
From: gConf.Network.Node,
|
rsp := PushConnectRsp{
|
||||||
}
|
Error: 1,
|
||||||
return GNetwork.push(req.From, MsgPushConnectRsp, rsp)
|
Detail: fmt.Sprintf("connect to %s error: Access Denied", gConf.Network.Node),
|
||||||
}
|
To: req.From,
|
||||||
|
From: gConf.Network.Node,
|
||||||
func handleReportApps() (err error) {
|
}
|
||||||
gLog.Println(LvINFO, "MsgPushReportApps")
|
return GNetwork.push(req.From, MsgPushConnectRsp, rsp)
|
||||||
req := ReportApps{}
|
}
|
||||||
gConf.mtx.Lock()
|
|
||||||
defer gConf.mtx.Unlock()
|
func handleReportApps() (err error) {
|
||||||
|
gLog.Println(LvINFO, "MsgPushReportApps")
|
||||||
for _, config := range gConf.Apps {
|
req := ReportApps{}
|
||||||
appActive := 0
|
gConf.mtx.Lock()
|
||||||
relayNode := ""
|
defer gConf.mtx.Unlock()
|
||||||
specRelayNode := ""
|
|
||||||
relayMode := ""
|
for _, config := range gConf.Apps {
|
||||||
linkMode := LinkModeUDPPunch
|
appActive := 0
|
||||||
var connectTime string
|
relayNode := ""
|
||||||
var retryTime string
|
specRelayNode := ""
|
||||||
var app *p2pApp
|
relayMode := ""
|
||||||
i, ok := GNetwork.apps.Load(config.ID())
|
linkMode := LinkModeUDPPunch
|
||||||
if ok {
|
var connectTime string
|
||||||
app = i.(*p2pApp)
|
var retryTime string
|
||||||
if app.isActive() {
|
var app *p2pApp
|
||||||
appActive = 1
|
i, ok := GNetwork.apps.Load(config.ID())
|
||||||
}
|
if ok {
|
||||||
if app.config.SrcPort == 0 { // memapp
|
app = i.(*p2pApp)
|
||||||
continue
|
if app.isActive() {
|
||||||
}
|
appActive = 1
|
||||||
specRelayNode = app.config.RelayNode
|
}
|
||||||
if !app.isDirect() { // TODO: should always report relay node for app edit
|
if app.config.SrcPort == 0 { // memapp
|
||||||
relayNode = app.relayNode
|
continue
|
||||||
relayMode = app.relayMode
|
}
|
||||||
}
|
specRelayNode = app.config.RelayNode
|
||||||
|
if !app.isDirect() { // TODO: should always report relay node for app edit
|
||||||
if app.Tunnel() != nil {
|
relayNode = app.relayNode
|
||||||
linkMode = app.Tunnel().linkModeWeb
|
relayMode = app.relayMode
|
||||||
}
|
}
|
||||||
retryTime = app.RetryTime().Local().Format("2006-01-02T15:04:05-0700")
|
|
||||||
connectTime = app.ConnectTime().Local().Format("2006-01-02T15:04:05-0700")
|
if app.Tunnel() != nil {
|
||||||
|
linkMode = app.Tunnel().linkModeWeb
|
||||||
}
|
}
|
||||||
appInfo := AppInfo{
|
retryTime = app.RetryTime().Local().Format("2006-01-02T15:04:05-0700")
|
||||||
AppName: config.AppName,
|
connectTime = app.ConnectTime().Local().Format("2006-01-02T15:04:05-0700")
|
||||||
Error: config.errMsg,
|
|
||||||
Protocol: config.Protocol,
|
}
|
||||||
PunchPriority: config.PunchPriority,
|
appInfo := AppInfo{
|
||||||
Whitelist: config.Whitelist,
|
AppName: config.AppName,
|
||||||
SrcPort: config.SrcPort,
|
Error: config.errMsg,
|
||||||
RelayNode: relayNode,
|
Protocol: config.Protocol,
|
||||||
SpecRelayNode: specRelayNode,
|
PunchPriority: config.PunchPriority,
|
||||||
RelayMode: relayMode,
|
Whitelist: config.Whitelist,
|
||||||
LinkMode: linkMode,
|
SrcPort: config.SrcPort,
|
||||||
PeerNode: config.PeerNode,
|
RelayNode: relayNode,
|
||||||
DstHost: config.DstHost,
|
SpecRelayNode: specRelayNode,
|
||||||
DstPort: config.DstPort,
|
RelayMode: relayMode,
|
||||||
PeerUser: config.PeerUser,
|
LinkMode: linkMode,
|
||||||
PeerIP: config.peerIP,
|
PeerNode: config.PeerNode,
|
||||||
PeerNatType: config.peerNatType,
|
DstHost: config.DstHost,
|
||||||
RetryTime: retryTime,
|
DstPort: config.DstPort,
|
||||||
ConnectTime: connectTime,
|
PeerUser: config.PeerUser,
|
||||||
IsActive: appActive,
|
PeerIP: config.peerIP,
|
||||||
Enabled: config.Enabled,
|
PeerNatType: config.peerNatType,
|
||||||
}
|
RetryTime: retryTime,
|
||||||
req.Apps = append(req.Apps, appInfo)
|
ConnectTime: connectTime,
|
||||||
}
|
IsActive: appActive,
|
||||||
return GNetwork.write(MsgReport, MsgReportApps, &req)
|
Enabled: config.Enabled,
|
||||||
|
}
|
||||||
}
|
req.Apps = append(req.Apps, appInfo)
|
||||||
|
}
|
||||||
func handleReportMemApps() (err error) {
|
return GNetwork.write(MsgReport, MsgReportApps, &req)
|
||||||
gLog.Println(LvINFO, "handleReportMemApps")
|
|
||||||
req := ReportApps{}
|
}
|
||||||
gConf.mtx.Lock()
|
|
||||||
defer gConf.mtx.Unlock()
|
func handleReportMemApps() (err error) {
|
||||||
GNetwork.sdwan.sysRoute.Range(func(key, value interface{}) bool {
|
gLog.Println(LvINFO, "handleReportMemApps")
|
||||||
node := value.(*sdwanNode)
|
req := ReportApps{}
|
||||||
appActive := 0
|
gConf.mtx.Lock()
|
||||||
relayMode := ""
|
defer gConf.mtx.Unlock()
|
||||||
var connectTime string
|
GNetwork.sdwan.sysRoute.Range(func(key, value interface{}) bool {
|
||||||
var retryTime string
|
node := value.(*sdwanNode)
|
||||||
|
appActive := 0
|
||||||
i, ok := GNetwork.apps.Load(node.id)
|
relayMode := ""
|
||||||
var app *p2pApp
|
var connectTime string
|
||||||
if ok {
|
var retryTime string
|
||||||
app = i.(*p2pApp)
|
|
||||||
if app.isActive() {
|
i, ok := GNetwork.apps.Load(node.id)
|
||||||
appActive = 1
|
var app *p2pApp
|
||||||
}
|
if ok {
|
||||||
if !app.isDirect() {
|
app = i.(*p2pApp)
|
||||||
relayMode = app.relayMode
|
if app.isActive() {
|
||||||
}
|
appActive = 1
|
||||||
retryTime = app.RetryTime().Local().Format("2006-01-02T15:04:05-0700")
|
}
|
||||||
connectTime = app.ConnectTime().Local().Format("2006-01-02T15:04:05-0700")
|
if !app.isDirect() {
|
||||||
}
|
relayMode = app.relayMode
|
||||||
appInfo := AppInfo{
|
}
|
||||||
RelayMode: relayMode,
|
retryTime = app.RetryTime().Local().Format("2006-01-02T15:04:05-0700")
|
||||||
PeerNode: node.name,
|
connectTime = app.ConnectTime().Local().Format("2006-01-02T15:04:05-0700")
|
||||||
IsActive: appActive,
|
}
|
||||||
Enabled: 1,
|
appInfo := AppInfo{
|
||||||
}
|
RelayMode: relayMode,
|
||||||
if app != nil {
|
PeerNode: node.name,
|
||||||
appInfo.AppName = app.config.AppName
|
IsActive: appActive,
|
||||||
appInfo.Error = app.config.errMsg
|
Enabled: 1,
|
||||||
appInfo.Protocol = app.config.Protocol
|
}
|
||||||
appInfo.Whitelist = app.config.Whitelist
|
if app != nil {
|
||||||
appInfo.SrcPort = app.config.SrcPort
|
appInfo.AppName = app.config.AppName
|
||||||
if !app.isDirect() {
|
appInfo.Error = app.config.errMsg
|
||||||
appInfo.RelayNode = app.relayNode
|
appInfo.Protocol = app.config.Protocol
|
||||||
}
|
appInfo.Whitelist = app.config.Whitelist
|
||||||
|
appInfo.SrcPort = app.config.SrcPort
|
||||||
if app.Tunnel() != nil {
|
if !app.isDirect() {
|
||||||
appInfo.LinkMode = app.Tunnel().linkModeWeb
|
appInfo.RelayNode = app.relayNode
|
||||||
}
|
}
|
||||||
appInfo.DstHost = app.config.DstHost
|
|
||||||
appInfo.DstPort = app.config.DstPort
|
if app.Tunnel() != nil {
|
||||||
appInfo.PeerUser = app.config.PeerUser
|
appInfo.LinkMode = app.Tunnel().linkModeWeb
|
||||||
appInfo.PeerIP = app.config.peerIP
|
}
|
||||||
appInfo.PeerNatType = app.config.peerNatType
|
appInfo.DstHost = app.config.DstHost
|
||||||
appInfo.RetryTime = retryTime
|
appInfo.DstPort = app.config.DstPort
|
||||||
appInfo.ConnectTime = connectTime
|
appInfo.PeerUser = app.config.PeerUser
|
||||||
}
|
appInfo.PeerIP = app.config.peerIP
|
||||||
req.Apps = append(req.Apps, appInfo)
|
appInfo.PeerNatType = app.config.peerNatType
|
||||||
return true
|
appInfo.RetryTime = retryTime
|
||||||
})
|
appInfo.ConnectTime = connectTime
|
||||||
gLog.Println(LvDEBUG, "handleReportMemApps res:", prettyJson(req))
|
}
|
||||||
return GNetwork.write(MsgReport, MsgReportMemApps, &req)
|
req.Apps = append(req.Apps, appInfo)
|
||||||
}
|
return true
|
||||||
|
})
|
||||||
func handleLog(msg []byte) (err error) {
|
gLog.Println(LvDEBUG, "handleReportMemApps res:", prettyJson(req))
|
||||||
gLog.Println(LvDEBUG, "MsgPushReportLog")
|
return GNetwork.write(MsgReport, MsgReportMemApps, &req)
|
||||||
const defaultLen = 1024 * 128
|
}
|
||||||
const maxLen = 1024 * 1024
|
|
||||||
req := ReportLogReq{}
|
func handleLog(msg []byte) (err error) {
|
||||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &req); err != nil {
|
gLog.Println(LvDEBUG, "MsgPushReportLog")
|
||||||
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(req), err, string(msg[openP2PHeaderSize:]))
|
const defaultLen = 1024 * 128
|
||||||
return err
|
const maxLen = 1024 * 1024
|
||||||
}
|
req := ReportLogReq{}
|
||||||
if req.FileName == "" {
|
if err = json.Unmarshal(msg[openP2PHeaderSize:], &req); err != nil {
|
||||||
req.FileName = "openp2p.log"
|
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(req), err, string(msg[openP2PHeaderSize:]))
|
||||||
} else {
|
return err
|
||||||
req.FileName = sanitizeFileName(req.FileName)
|
}
|
||||||
}
|
if req.FileName == "" {
|
||||||
f, err := os.Open(filepath.Join("log", req.FileName))
|
req.FileName = "openp2p.log"
|
||||||
if err != nil {
|
} else {
|
||||||
gLog.Println(LvERROR, "read log file error:", err)
|
req.FileName = sanitizeFileName(req.FileName)
|
||||||
return err
|
}
|
||||||
}
|
f, err := os.Open(filepath.Join("log", req.FileName))
|
||||||
fi, err := f.Stat()
|
if err != nil {
|
||||||
if err != nil {
|
gLog.Println(LvERROR, "read log file error:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if req.Offset > fi.Size() {
|
fi, err := f.Stat()
|
||||||
req.Offset = fi.Size() - defaultLen
|
if err != nil {
|
||||||
}
|
return err
|
||||||
// verify input parameters
|
}
|
||||||
if req.Offset < 0 {
|
if req.Offset > fi.Size() {
|
||||||
req.Offset = 0
|
req.Offset = fi.Size() - defaultLen
|
||||||
}
|
}
|
||||||
if req.Len <= 0 || req.Len > maxLen {
|
// verify input parameters
|
||||||
req.Len = defaultLen
|
if req.Offset < 0 {
|
||||||
}
|
req.Offset = 0
|
||||||
|
}
|
||||||
f.Seek(req.Offset, 0)
|
if req.Len <= 0 || req.Len > maxLen {
|
||||||
buff := make([]byte, req.Len)
|
req.Len = defaultLen
|
||||||
readLength, err := f.Read(buff)
|
}
|
||||||
f.Close()
|
|
||||||
if err != nil {
|
f.Seek(req.Offset, 0)
|
||||||
gLog.Println(LvERROR, "read log content error:", err)
|
buff := make([]byte, req.Len)
|
||||||
return err
|
readLength, err := f.Read(buff)
|
||||||
}
|
f.Close()
|
||||||
rsp := ReportLogRsp{}
|
if err != nil {
|
||||||
rsp.Content = string(buff[:readLength])
|
gLog.Println(LvERROR, "read log content error:", err)
|
||||||
rsp.FileName = req.FileName
|
return err
|
||||||
rsp.Total = fi.Size()
|
}
|
||||||
rsp.Len = req.Len
|
rsp := ReportLogRsp{}
|
||||||
return GNetwork.write(MsgReport, MsgPushReportLog, &rsp)
|
rsp.Content = string(buff[:readLength])
|
||||||
}
|
rsp.FileName = req.FileName
|
||||||
|
rsp.Total = fi.Size()
|
||||||
func handleReportGoroutine() (err error) {
|
rsp.Len = req.Len
|
||||||
gLog.Println(LvDEBUG, "handleReportGoroutine")
|
return GNetwork.write(MsgReport, MsgPushReportLog, &rsp)
|
||||||
buf := make([]byte, 1024*128)
|
}
|
||||||
stackLen := runtime.Stack(buf, true)
|
|
||||||
return GNetwork.write(MsgReport, MsgPushReportLog, string(buf[:stackLen]))
|
func handleReportGoroutine() (err error) {
|
||||||
}
|
gLog.Println(LvDEBUG, "handleReportGoroutine")
|
||||||
|
buf := make([]byte, 1024*128)
|
||||||
|
stackLen := runtime.Stack(buf, true)
|
||||||
|
return GNetwork.write(MsgReport, MsgPushReportLog, string(buf[:stackLen]))
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleCheckRemoteService(msg []byte) (err error) {
|
||||||
|
gLog.Println(LvDEBUG, "handleCheckRemoteService")
|
||||||
|
req := CheckRemoteService{}
|
||||||
|
if err = json.Unmarshal(msg[openP2PHeaderSize:], &req); err != nil {
|
||||||
|
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(req), err, string(msg[openP2PHeaderSize:]))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rsp := PushRsp{Error: 0}
|
||||||
|
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", req.Host, req.Port), time.Second*3)
|
||||||
|
if err != nil {
|
||||||
|
rsp.Error = 1
|
||||||
|
rsp.Detail = ErrRemoteServiceUnable.Error()
|
||||||
|
} else {
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
return GNetwork.write(MsgReport, MsgReportResponse, rsp)
|
||||||
|
}
|
||||||
|
|||||||
+124
-124
@@ -1,124 +1,124 @@
|
|||||||
package openp2p
|
package openp2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func install() {
|
func install() {
|
||||||
gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion)
|
gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion)
|
||||||
gLog.Println(LvINFO, "Contact: QQ group 16947733, Email [email protected]")
|
gLog.Println(LvINFO, "Contact: QQ group 16947733, Email [email protected]")
|
||||||
gLog.Println(LvINFO, "install start")
|
gLog.Println(LvINFO, "install start")
|
||||||
defer gLog.Println(LvINFO, "install end")
|
defer gLog.Println(LvINFO, "install end")
|
||||||
// auto uninstall
|
// auto uninstall
|
||||||
err := os.MkdirAll(defaultInstallPath, 0775)
|
err := os.MkdirAll(defaultInstallPath, 0775)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvERROR, "MkdirAll %s error:%s", defaultInstallPath, err)
|
gLog.Printf(LvERROR, "MkdirAll %s error:%s", defaultInstallPath, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = os.Chdir(defaultInstallPath)
|
err = os.Chdir(defaultInstallPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "cd error:", err)
|
gLog.Println(LvERROR, "cd error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstall()
|
uninstall()
|
||||||
// save config file
|
// save config file
|
||||||
parseParams("install", "")
|
parseParams("install", "")
|
||||||
targetPath := filepath.Join(defaultInstallPath, defaultBinName)
|
targetPath := filepath.Join(defaultInstallPath, defaultBinName)
|
||||||
d := daemon{}
|
d := daemon{}
|
||||||
// copy files
|
// copy files
|
||||||
|
|
||||||
binPath, _ := os.Executable()
|
binPath, _ := os.Executable()
|
||||||
src, errFiles := os.Open(binPath) // can not use args[0], on Windows call openp2p is ok(=openp2p.exe)
|
src, errFiles := os.Open(binPath) // can not use args[0], on Windows call openp2p is ok(=openp2p.exe)
|
||||||
if errFiles != nil {
|
if errFiles != nil {
|
||||||
gLog.Printf(LvERROR, "os.OpenFile %s error:%s", os.Args[0], errFiles)
|
gLog.Printf(LvERROR, "os.OpenFile %s error:%s", os.Args[0], errFiles)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dst, errFiles := os.OpenFile(targetPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0775)
|
dst, errFiles := os.OpenFile(targetPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0775)
|
||||||
if errFiles != nil {
|
if errFiles != nil {
|
||||||
gLog.Printf(LvERROR, "os.OpenFile %s error:%s", targetPath, errFiles)
|
gLog.Printf(LvERROR, "os.OpenFile %s error:%s", targetPath, errFiles)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, errFiles = io.Copy(dst, src)
|
_, errFiles = io.Copy(dst, src)
|
||||||
if errFiles != nil {
|
if errFiles != nil {
|
||||||
gLog.Printf(LvERROR, "io.Copy error:%s", errFiles)
|
gLog.Printf(LvERROR, "io.Copy error:%s", errFiles)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
src.Close()
|
src.Close()
|
||||||
dst.Close()
|
dst.Close()
|
||||||
|
|
||||||
// install system service
|
// install system service
|
||||||
gLog.Println(LvINFO, "targetPath:", targetPath)
|
gLog.Println(LvINFO, "targetPath:", targetPath)
|
||||||
err = d.Control("install", targetPath, []string{"-d"})
|
err = d.Control("install", targetPath, []string{"-d"})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
gLog.Println(LvINFO, "install system service ok.")
|
gLog.Println(LvINFO, "install system service ok.")
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second * 2)
|
time.Sleep(time.Second * 2)
|
||||||
err = d.Control("start", targetPath, []string{"-d"})
|
err = d.Control("start", targetPath, []string{"-d"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "start openp2p service error:", err)
|
gLog.Println(LvERROR, "start openp2p service error:", err)
|
||||||
} else {
|
} else {
|
||||||
gLog.Println(LvINFO, "start openp2p service ok.")
|
gLog.Println(LvINFO, "start openp2p service ok.")
|
||||||
}
|
}
|
||||||
gLog.Println(LvINFO, "Visit WebUI on https://console.openp2p.cn")
|
gLog.Println(LvINFO, "Visit WebUI on https://console.openp2p.cn")
|
||||||
}
|
}
|
||||||
|
|
||||||
func installByFilename() {
|
func installByFilename() {
|
||||||
params := strings.Split(filepath.Base(os.Args[0]), "-")
|
params := strings.Split(filepath.Base(os.Args[0]), "-")
|
||||||
if len(params) < 4 {
|
if len(params) < 4 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
serverHost := params[1]
|
serverHost := params[1]
|
||||||
token := params[2]
|
token := params[2]
|
||||||
gLog.Println(LvINFO, "install start")
|
gLog.Println(LvINFO, "install start")
|
||||||
targetPath := os.Args[0]
|
targetPath := os.Args[0]
|
||||||
args := []string{"install"}
|
args := []string{"install"}
|
||||||
args = append(args, "-serverhost")
|
args = append(args, "-serverhost")
|
||||||
args = append(args, serverHost)
|
args = append(args, serverHost)
|
||||||
args = append(args, "-token")
|
args = append(args, "-token")
|
||||||
args = append(args, token)
|
args = append(args, token)
|
||||||
env := os.Environ()
|
env := os.Environ()
|
||||||
cmd := exec.Command(targetPath, args...)
|
cmd := exec.Command(targetPath, args...)
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
cmd.Stdin = os.Stdin
|
cmd.Stdin = os.Stdin
|
||||||
cmd.Env = env
|
cmd.Env = env
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "install by filename, start process error:", err)
|
gLog.Println(LvERROR, "install by filename, start process error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
gLog.Println(LvINFO, "install end")
|
gLog.Println(LvINFO, "install end")
|
||||||
gLog.Println(LvINFO, "Visit WebUI on https://console.openp2p.cn")
|
gLog.Println(LvINFO, "Visit WebUI on https://console.openp2p.cn")
|
||||||
fmt.Println("Press the Any Key to exit")
|
fmt.Println("Press the Any Key to exit")
|
||||||
fmt.Scanln()
|
fmt.Scanln()
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
func uninstall() {
|
func uninstall() {
|
||||||
gLog.Println(LvINFO, "uninstall start")
|
gLog.Println(LvINFO, "uninstall start")
|
||||||
defer gLog.Println(LvINFO, "uninstall end")
|
defer gLog.Println(LvINFO, "uninstall end")
|
||||||
d := daemon{}
|
d := daemon{}
|
||||||
err := d.Control("stop", "", nil)
|
err := d.Control("stop", "", nil)
|
||||||
if err != nil { // service maybe not install
|
if err != nil { // service maybe not install
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = d.Control("uninstall", "", nil)
|
err = d.Control("uninstall", "", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "uninstall system service error:", err)
|
gLog.Println(LvERROR, "uninstall system service error:", err)
|
||||||
} else {
|
} else {
|
||||||
gLog.Println(LvINFO, "uninstall system service ok.")
|
gLog.Println(LvINFO, "uninstall system service ok.")
|
||||||
}
|
}
|
||||||
binPath := filepath.Join(defaultInstallPath, defaultBinName)
|
binPath := filepath.Join(defaultInstallPath, defaultBinName)
|
||||||
os.Remove(binPath + "0")
|
os.Remove(binPath + "0")
|
||||||
os.Remove(binPath)
|
os.Remove(binPath)
|
||||||
// os.RemoveAll(defaultInstallPath) // reserve config.json
|
// os.RemoveAll(defaultInstallPath) // reserve config.json
|
||||||
}
|
}
|
||||||
|
|||||||
+74
-74
@@ -1,74 +1,74 @@
|
|||||||
package openp2p
|
package openp2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
func allowTunForward() {
|
func allowTunForward() {
|
||||||
if runtime.GOOS != "linux" { // only support Linux
|
if runtime.GOOS != "linux" { // only support Linux
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
exec.Command("sh", "-c", `iptables -t filter -D FORWARD -i optun -j ACCEPT`).Run()
|
exec.Command("sh", "-c", `iptables -t filter -D FORWARD -i optun -j ACCEPT`).Run()
|
||||||
exec.Command("sh", "-c", `iptables -t filter -D FORWARD -o optun -j ACCEPT`).Run()
|
exec.Command("sh", "-c", `iptables -t filter -D FORWARD -o optun -j ACCEPT`).Run()
|
||||||
err := exec.Command("sh", "-c", `iptables -t filter -I FORWARD -i optun -j ACCEPT`).Run()
|
err := exec.Command("sh", "-c", `iptables -t filter -I FORWARD -i optun -j ACCEPT`).Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("allow foward in error:", err)
|
log.Println("allow foward in error:", err)
|
||||||
}
|
}
|
||||||
err = exec.Command("sh", "-c", `iptables -t filter -I FORWARD -o optun -j ACCEPT`).Run()
|
err = exec.Command("sh", "-c", `iptables -t filter -I FORWARD -o optun -j ACCEPT`).Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("allow foward out error:", err)
|
log.Println("allow foward out error:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func clearSNATRule() {
|
func clearSNATRule() {
|
||||||
if runtime.GOOS != "linux" {
|
if runtime.GOOS != "linux" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
execCommand("iptables", true, "-t", "nat", "-D", "POSTROUTING", "-j", "OPSDWAN")
|
execCommand("iptables", true, "-t", "nat", "-D", "POSTROUTING", "-j", "OPSDWAN")
|
||||||
execCommand("iptables", true, "-t", "nat", "-F", "OPSDWAN")
|
execCommand("iptables", true, "-t", "nat", "-F", "OPSDWAN")
|
||||||
execCommand("iptables", true, "-t", "nat", "-X", "OPSDWAN")
|
execCommand("iptables", true, "-t", "nat", "-X", "OPSDWAN")
|
||||||
}
|
}
|
||||||
|
|
||||||
func initSNATRule(localNet string) {
|
func initSNATRule(localNet string) {
|
||||||
if runtime.GOOS != "linux" {
|
if runtime.GOOS != "linux" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
clearSNATRule()
|
clearSNATRule()
|
||||||
|
|
||||||
err := execCommand("iptables", true, "-t", "nat", "-N", "OPSDWAN")
|
err := execCommand("iptables", true, "-t", "nat", "-N", "OPSDWAN")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("iptables new sdwan chain error:", err)
|
log.Println("iptables new sdwan chain error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = execCommand("iptables", true, "-t", "nat", "-A", "POSTROUTING", "-j", "OPSDWAN")
|
err = execCommand("iptables", true, "-t", "nat", "-A", "POSTROUTING", "-j", "OPSDWAN")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("iptables append postrouting error:", err)
|
log.Println("iptables append postrouting error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = execCommand("iptables", true, "-t", "nat", "-A", "OPSDWAN",
|
err = execCommand("iptables", true, "-t", "nat", "-A", "OPSDWAN",
|
||||||
"-o", "optun", "!", "-s", localNet, "-j", "MASQUERADE")
|
"-o", "optun", "!", "-s", localNet, "-j", "MASQUERADE")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("add optun snat error:", err)
|
log.Println("add optun snat error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = execCommand("iptables", true, "-t", "nat", "-A", "OPSDWAN", "!", "-o", "optun",
|
err = execCommand("iptables", true, "-t", "nat", "-A", "OPSDWAN", "!", "-o", "optun",
|
||||||
"-s", localNet, "-j", "MASQUERADE")
|
"-s", localNet, "-j", "MASQUERADE")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("add optun snat error:", err)
|
log.Println("add optun snat error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addSNATRule(target string) {
|
func addSNATRule(target string) {
|
||||||
if runtime.GOOS != "linux" {
|
if runtime.GOOS != "linux" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err := execCommand("iptables", true, "-t", "nat", "-A", "OPSDWAN", "!", "-o", "optun",
|
err := execCommand("iptables", true, "-t", "nat", "-A", "OPSDWAN", "!", "-o", "optun",
|
||||||
"-s", target, "-j", "MASQUERADE")
|
"-s", target, "-j", "MASQUERADE")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("iptables add optun snat error:", err)
|
log.Println("iptables add optun snat error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+189
-189
@@ -1,189 +1,189 @@
|
|||||||
package openp2p
|
package openp2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
reuse "github.com/openp2p-cn/go-reuseport"
|
reuse "github.com/openp2p-cn/go-reuseport"
|
||||||
)
|
)
|
||||||
|
|
||||||
func natTCP(serverHost string, serverPort int) (publicIP string, publicPort int, localPort int) {
|
func natTCP(serverHost string, serverPort int) (publicIP string, publicPort int, localPort int) {
|
||||||
// dialer := &net.Dialer{
|
// dialer := &net.Dialer{
|
||||||
// LocalAddr: &net.TCPAddr{
|
// LocalAddr: &net.TCPAddr{
|
||||||
// IP: net.ParseIP("0.0.0.0"),
|
// IP: net.ParseIP("0.0.0.0"),
|
||||||
// Port: localPort,
|
// Port: localPort,
|
||||||
// },
|
// },
|
||||||
// }
|
// }
|
||||||
conn, err := reuse.DialTimeout("tcp4", fmt.Sprintf("%s:%d", "0.0.0.0", 0), fmt.Sprintf("%s:%d", serverHost, serverPort), NatTestTimeout)
|
conn, err := reuse.DialTimeout("tcp4", fmt.Sprintf("%s:%d", "0.0.0.0", 0), fmt.Sprintf("%s:%d", serverHost, serverPort), NatTestTimeout)
|
||||||
// conn, err := net.Dial("tcp4", fmt.Sprintf("%s:%d", serverHost, serverPort))
|
// conn, err := net.Dial("tcp4", fmt.Sprintf("%s:%d", serverHost, serverPort))
|
||||||
// log.Println(LvINFO, conn.LocalAddr())
|
// log.Println(LvINFO, conn.LocalAddr())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Dial tcp4 %s:%d error:%s", serverHost, serverPort, err)
|
fmt.Printf("Dial tcp4 %s:%d error:%s", serverHost, serverPort, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
localPort, _ = strconv.Atoi(strings.Split(conn.LocalAddr().String(), ":")[1])
|
localPort, _ = strconv.Atoi(strings.Split(conn.LocalAddr().String(), ":")[1])
|
||||||
_, wrerr := conn.Write([]byte("1"))
|
_, wrerr := conn.Write([]byte("1"))
|
||||||
if wrerr != nil {
|
if wrerr != nil {
|
||||||
fmt.Printf("Write error: %s\n", wrerr)
|
fmt.Printf("Write error: %s\n", wrerr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b := make([]byte, 1000)
|
b := make([]byte, 1000)
|
||||||
conn.SetReadDeadline(time.Now().Add(NatTestTimeout))
|
conn.SetReadDeadline(time.Now().Add(NatTestTimeout))
|
||||||
n, rderr := conn.Read(b)
|
n, rderr := conn.Read(b)
|
||||||
if rderr != nil {
|
if rderr != nil {
|
||||||
fmt.Printf("Read error: %s\n", rderr)
|
fmt.Printf("Read error: %s\n", rderr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
arr := strings.Split(string(b[:n]), ":")
|
arr := strings.Split(string(b[:n]), ":")
|
||||||
if len(arr) < 2 {
|
if len(arr) < 2 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
publicIP = arr[0]
|
publicIP = arr[0]
|
||||||
port, _ := strconv.ParseInt(arr[1], 10, 32)
|
port, _ := strconv.ParseInt(arr[1], 10, 32)
|
||||||
publicPort = int(port)
|
publicPort = int(port)
|
||||||
return
|
return
|
||||||
|
|
||||||
}
|
}
|
||||||
func natTest(serverHost string, serverPort int, localPort int) (publicIP string, publicPort int, err error) {
|
func natTest(serverHost string, serverPort int, localPort int) (publicIP string, publicPort int, err error) {
|
||||||
gLog.Println(LvDEBUG, "natTest start")
|
gLog.Println(LvDEBUG, "natTest start")
|
||||||
defer gLog.Println(LvDEBUG, "natTest end")
|
defer gLog.Println(LvDEBUG, "natTest end")
|
||||||
conn, err := net.ListenPacket("udp", fmt.Sprintf(":%d", localPort))
|
conn, err := net.ListenPacket("udp", fmt.Sprintf(":%d", localPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "natTest listen udp error:", err)
|
gLog.Println(LvERROR, "natTest listen udp error:", err)
|
||||||
return "", 0, err
|
return "", 0, err
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
dst, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", serverHost, serverPort))
|
dst, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", serverHost, serverPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, err
|
return "", 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// The connection can write data to the desired address.
|
// The connection can write data to the desired address.
|
||||||
msg, err := newMessage(MsgNATDetect, 0, nil)
|
msg, err := newMessage(MsgNATDetect, 0, nil)
|
||||||
_, err = conn.WriteTo(msg, dst)
|
_, err = conn.WriteTo(msg, dst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, err
|
return "", 0, err
|
||||||
}
|
}
|
||||||
deadline := time.Now().Add(NatTestTimeout)
|
deadline := time.Now().Add(NatTestTimeout)
|
||||||
err = conn.SetReadDeadline(deadline)
|
err = conn.SetReadDeadline(deadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, err
|
return "", 0, err
|
||||||
}
|
}
|
||||||
buffer := make([]byte, 1024)
|
buffer := make([]byte, 1024)
|
||||||
nRead, _, err := conn.ReadFrom(buffer)
|
nRead, _, err := conn.ReadFrom(buffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "NAT detect error:", err)
|
gLog.Println(LvERROR, "NAT detect error:", err)
|
||||||
return "", 0, err
|
return "", 0, err
|
||||||
}
|
}
|
||||||
natRsp := NatDetectRsp{}
|
natRsp := NatDetectRsp{}
|
||||||
json.Unmarshal(buffer[openP2PHeaderSize:nRead], &natRsp)
|
json.Unmarshal(buffer[openP2PHeaderSize:nRead], &natRsp)
|
||||||
|
|
||||||
return natRsp.IP, natRsp.Port, nil
|
return natRsp.IP, natRsp.Port, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNATType(host string, udp1 int, udp2 int) (publicIP string, NATType int, err error) {
|
func getNATType(host string, udp1 int, udp2 int) (publicIP string, NATType int, err error) {
|
||||||
// the random local port may be used by other.
|
// the random local port may be used by other.
|
||||||
localPort := int(rand.Uint32()%15000 + 50000)
|
localPort := int(rand.Uint32()%15000 + 50000)
|
||||||
|
|
||||||
ip1, port1, err := natTest(host, udp1, localPort)
|
ip1, port1, err := natTest(host, udp1, localPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, err
|
return "", 0, err
|
||||||
}
|
}
|
||||||
_, port2, err := natTest(host, udp2, localPort) // 2rd nat test not need testing publicip
|
_, port2, err := natTest(host, udp2, localPort) // 2rd nat test not need testing publicip
|
||||||
gLog.Printf(LvDEBUG, "local port:%d nat port:%d", localPort, port2)
|
gLog.Printf(LvDEBUG, "local port:%d nat port:%d", localPort, port2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, err
|
return "", 0, err
|
||||||
}
|
}
|
||||||
natType := NATSymmetric
|
natType := NATSymmetric
|
||||||
if port1 == port2 {
|
if port1 == port2 {
|
||||||
natType = NATCone
|
natType = NATCone
|
||||||
}
|
}
|
||||||
return ip1, natType, nil
|
return ip1, natType, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func publicIPTest(publicIP string, echoPort int) (hasPublicIP int, hasUPNPorNATPMP int) {
|
func publicIPTest(publicIP string, echoPort int) (hasPublicIP int, hasUPNPorNATPMP int) {
|
||||||
if publicIP == "" || echoPort == 0 {
|
if publicIP == "" || echoPort == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var echoConn *net.UDPConn
|
var echoConn *net.UDPConn
|
||||||
gLog.Println(LvDEBUG, "echo server start")
|
gLog.Println(LvDEBUG, "echo server start")
|
||||||
var err error
|
var err error
|
||||||
echoConn, err = net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: echoPort})
|
echoConn, err = net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: echoPort})
|
||||||
if err != nil { // listen error
|
if err != nil { // listen error
|
||||||
gLog.Println(LvERROR, "echo server listen error:", err)
|
gLog.Println(LvERROR, "echo server listen error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer echoConn.Close()
|
defer echoConn.Close()
|
||||||
go func() {
|
go func() {
|
||||||
// close outside for breaking the ReadFromUDP
|
// close outside for breaking the ReadFromUDP
|
||||||
// wait 30s for echo testing
|
// wait 30s for echo testing
|
||||||
buf := make([]byte, 1600)
|
buf := make([]byte, 1600)
|
||||||
echoConn.SetReadDeadline(time.Now().Add(time.Second * 30))
|
echoConn.SetReadDeadline(time.Now().Add(time.Second * 30))
|
||||||
n, addr, err := echoConn.ReadFromUDP(buf)
|
n, addr, err := echoConn.ReadFromUDP(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
echoConn.WriteToUDP(buf[0:n], addr)
|
echoConn.WriteToUDP(buf[0:n], addr)
|
||||||
gLog.Println(LvDEBUG, "echo server end")
|
gLog.Println(LvDEBUG, "echo server end")
|
||||||
}()
|
}()
|
||||||
// testing for public ip
|
// testing for public ip
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
// test upnp or nat-pmp
|
// test upnp or nat-pmp
|
||||||
gLog.Println(LvDEBUG, "upnp test start")
|
gLog.Println(LvDEBUG, "upnp test start")
|
||||||
nat, err := Discover()
|
nat, err := Discover()
|
||||||
if err != nil || nat == nil {
|
if err != nil || nat == nil {
|
||||||
gLog.Println(LvDEBUG, "could not perform UPNP discover:", err)
|
gLog.Println(LvDEBUG, "could not perform UPNP discover:", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
ext, err := nat.GetExternalAddress()
|
ext, err := nat.GetExternalAddress()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvDEBUG, "could not perform UPNP external address:", err)
|
gLog.Println(LvDEBUG, "could not perform UPNP external address:", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
gLog.Println(LvINFO, "PublicIP:", ext)
|
gLog.Println(LvINFO, "PublicIP:", ext)
|
||||||
|
|
||||||
externalPort, err := nat.AddPortMapping("udp", echoPort, echoPort, "openp2p", 30) // 30 seconds fot upnp testing
|
externalPort, err := nat.AddPortMapping("udp", echoPort, echoPort, "openp2p", 30) // 30 seconds fot upnp testing
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvDEBUG, "could not add udp UPNP port mapping", externalPort)
|
gLog.Println(LvDEBUG, "could not add udp UPNP port mapping", externalPort)
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
nat.AddPortMapping("tcp", echoPort, echoPort, "openp2p", 604800) // 7 days for tcp connection
|
nat.AddPortMapping("tcp", echoPort, echoPort, "openp2p", 604800) // 7 days for tcp connection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gLog.Printf(LvDEBUG, "public ip test start %s:%d", publicIP, echoPort)
|
gLog.Printf(LvDEBUG, "public ip test start %s:%d", publicIP, echoPort)
|
||||||
conn, err := net.ListenUDP("udp", nil)
|
conn, err := net.ListenUDP("udp", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
dst, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", publicIP, echoPort))
|
dst, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", publicIP, echoPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
conn.WriteTo([]byte("echo"), dst)
|
conn.WriteTo([]byte("echo"), dst)
|
||||||
buf := make([]byte, 1600)
|
buf := make([]byte, 1600)
|
||||||
|
|
||||||
// wait for echo testing
|
// wait for echo testing
|
||||||
conn.SetReadDeadline(time.Now().Add(PublicIPEchoTimeout))
|
conn.SetReadDeadline(time.Now().Add(PublicIPEchoTimeout))
|
||||||
_, _, err = conn.ReadFromUDP(buf)
|
_, _, err = conn.ReadFromUDP(buf)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
gLog.Println(LvDEBUG, "UPNP or NAT-PMP:YES")
|
gLog.Println(LvDEBUG, "UPNP or NAT-PMP:YES")
|
||||||
hasUPNPorNATPMP = 1
|
hasUPNPorNATPMP = 1
|
||||||
} else {
|
} else {
|
||||||
gLog.Println(LvDEBUG, "public ip:YES")
|
gLog.Println(LvDEBUG, "public ip:YES")
|
||||||
hasPublicIP = 1
|
hasPublicIP = 1
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+121
-121
@@ -1,121 +1,121 @@
|
|||||||
package openp2p
|
package openp2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var GNetwork *P2PNetwork
|
var GNetwork *P2PNetwork
|
||||||
|
|
||||||
func Run() {
|
func Run() {
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
baseDir := filepath.Dir(os.Args[0])
|
baseDir := filepath.Dir(os.Args[0])
|
||||||
os.Chdir(baseDir) // for system service
|
os.Chdir(baseDir) // for system service
|
||||||
gLog = NewLogger(baseDir, ProductName, LvDEBUG, 1024*1024, LogFile|LogConsole)
|
gLog = NewLogger(baseDir, ProductName, LvDEBUG, 1024*1024, LogFile|LogConsole)
|
||||||
if len(os.Args) > 1 {
|
if len(os.Args) > 1 {
|
||||||
switch os.Args[1] {
|
switch os.Args[1] {
|
||||||
case "version", "-v", "--version":
|
case "version", "-v", "--version":
|
||||||
fmt.Println(OpenP2PVersion)
|
fmt.Println(OpenP2PVersion)
|
||||||
return
|
return
|
||||||
case "install":
|
case "install":
|
||||||
install()
|
install()
|
||||||
return
|
return
|
||||||
case "uninstall":
|
case "uninstall":
|
||||||
uninstall()
|
uninstall()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
installByFilename()
|
installByFilename()
|
||||||
}
|
}
|
||||||
parseParams("", "")
|
parseParams("", "")
|
||||||
gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion)
|
gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion)
|
||||||
gLog.Println(LvINFO, "Contact: QQ group 16947733, Email [email protected]")
|
gLog.Println(LvINFO, "Contact: QQ group 16947733, Email [email protected]")
|
||||||
|
|
||||||
if gConf.daemonMode {
|
if gConf.daemonMode {
|
||||||
d := daemon{}
|
d := daemon{}
|
||||||
d.run()
|
d.run()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
gLog.Println(LvINFO, &gConf)
|
gLog.Println(LvINFO, &gConf)
|
||||||
setFirewall()
|
setFirewall()
|
||||||
err := setRLimit()
|
err := setRLimit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvINFO, "setRLimit error:", err)
|
gLog.Println(LvINFO, "setRLimit error:", err)
|
||||||
}
|
}
|
||||||
GNetwork = P2PNetworkInstance()
|
GNetwork = P2PNetworkInstance()
|
||||||
if ok := GNetwork.Connect(30000); !ok {
|
if ok := GNetwork.Connect(30000); !ok {
|
||||||
gLog.Println(LvERROR, "P2PNetwork login error")
|
gLog.Println(LvERROR, "P2PNetwork login error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// gLog.Println(LvINFO, "waiting for connection...")
|
// gLog.Println(LvINFO, "waiting for connection...")
|
||||||
forever := make(chan bool)
|
forever := make(chan bool)
|
||||||
<-forever
|
<-forever
|
||||||
}
|
}
|
||||||
|
|
||||||
// for Android app
|
// for Android app
|
||||||
// gomobile not support uint64 exported to java
|
// gomobile not support uint64 exported to java
|
||||||
|
|
||||||
func RunAsModule(baseDir string, token string, bw int, logLevel int) *P2PNetwork {
|
func RunAsModule(baseDir string, token string, bw int, logLevel int) *P2PNetwork {
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
os.Chdir(baseDir) // for system service
|
os.Chdir(baseDir) // for system service
|
||||||
gLog = NewLogger(baseDir, ProductName, LvINFO, 1024*1024, LogFile|LogConsole)
|
gLog = NewLogger(baseDir, ProductName, LvINFO, 1024*1024, LogFile|LogConsole)
|
||||||
|
|
||||||
parseParams("", "")
|
parseParams("", "")
|
||||||
|
|
||||||
n, err := strconv.ParseUint(token, 10, 64)
|
n, err := strconv.ParseUint(token, 10, 64)
|
||||||
if err == nil && n > 0 {
|
if err == nil && n > 0 {
|
||||||
gConf.setToken(n)
|
gConf.setToken(n)
|
||||||
}
|
}
|
||||||
if n <= 0 && gConf.Network.Token == 0 { // not input token
|
if n <= 0 && gConf.Network.Token == 0 { // not input token
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// gLog.setLevel(LogLevel(logLevel))
|
// gLog.setLevel(LogLevel(logLevel))
|
||||||
gConf.setShareBandwidth(bw)
|
gConf.setShareBandwidth(bw)
|
||||||
gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion)
|
gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion)
|
||||||
gLog.Println(LvINFO, "Contact: QQ group 16947733, Email [email protected]")
|
gLog.Println(LvINFO, "Contact: QQ group 16947733, Email [email protected]")
|
||||||
gLog.Println(LvINFO, &gConf)
|
gLog.Println(LvINFO, &gConf)
|
||||||
|
|
||||||
GNetwork = P2PNetworkInstance()
|
GNetwork = P2PNetworkInstance()
|
||||||
if ok := GNetwork.Connect(30000); !ok {
|
if ok := GNetwork.Connect(30000); !ok {
|
||||||
gLog.Println(LvERROR, "P2PNetwork login error")
|
gLog.Println(LvERROR, "P2PNetwork login error")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// gLog.Println(LvINFO, "waiting for connection...")
|
// gLog.Println(LvINFO, "waiting for connection...")
|
||||||
return GNetwork
|
return GNetwork
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunCmd(cmd string) {
|
func RunCmd(cmd string) {
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
baseDir := filepath.Dir(os.Args[0])
|
baseDir := filepath.Dir(os.Args[0])
|
||||||
os.Chdir(baseDir) // for system service
|
os.Chdir(baseDir) // for system service
|
||||||
gLog = NewLogger(baseDir, ProductName, LvINFO, 1024*1024, LogFile|LogConsole)
|
gLog = NewLogger(baseDir, ProductName, LvINFO, 1024*1024, LogFile|LogConsole)
|
||||||
|
|
||||||
parseParams("", cmd)
|
parseParams("", cmd)
|
||||||
setFirewall()
|
setFirewall()
|
||||||
err := setRLimit()
|
err := setRLimit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvINFO, "setRLimit error:", err)
|
gLog.Println(LvINFO, "setRLimit error:", err)
|
||||||
}
|
}
|
||||||
GNetwork = P2PNetworkInstance()
|
GNetwork = P2PNetworkInstance()
|
||||||
if ok := GNetwork.Connect(30000); !ok {
|
if ok := GNetwork.Connect(30000); !ok {
|
||||||
gLog.Println(LvERROR, "P2PNetwork login error")
|
gLog.Println(LvERROR, "P2PNetwork login error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
forever := make(chan bool)
|
forever := make(chan bool)
|
||||||
<-forever
|
<-forever
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetToken(baseDir string) string {
|
func GetToken(baseDir string) string {
|
||||||
os.Chdir(baseDir)
|
os.Chdir(baseDir)
|
||||||
gConf.load()
|
gConf.load()
|
||||||
return fmt.Sprintf("%d", gConf.Network.Token)
|
return fmt.Sprintf("%d", gConf.Network.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Stop() {
|
func Stop() {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-20
@@ -1,20 +1,20 @@
|
|||||||
package openp2p
|
package openp2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/openp2p-cn/wireguard-go/tun"
|
"github.com/openp2p-cn/wireguard-go/tun"
|
||||||
)
|
)
|
||||||
|
|
||||||
var AndroidSDWANConfig chan []byte
|
var AndroidSDWANConfig chan []byte
|
||||||
|
|
||||||
type optun struct {
|
type optun struct {
|
||||||
tunName string
|
tunName string
|
||||||
dev tun.Device
|
dev tun.Device
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *optun) Stop() error {
|
func (t *optun) Stop() error {
|
||||||
t.dev.Close()
|
t.dev.Close()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func init() {
|
func init() {
|
||||||
AndroidSDWANConfig = make(chan []byte, 1)
|
AndroidSDWANConfig = make(chan []byte, 1)
|
||||||
}
|
}
|
||||||
|
|||||||
+85
-85
@@ -1,85 +1,85 @@
|
|||||||
// optun_android.go
|
// optun_android.go
|
||||||
//go:build android
|
//go:build android
|
||||||
// +build android
|
// +build android
|
||||||
|
|
||||||
package openp2p
|
package openp2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
tunIfaceName = "optun"
|
tunIfaceName = "optun"
|
||||||
PIHeaderSize = 0
|
PIHeaderSize = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
var AndroidReadTun chan []byte // TODO: multi channel
|
var AndroidReadTun chan []byte // TODO: multi channel
|
||||||
var AndroidWriteTun chan []byte
|
var AndroidWriteTun chan []byte
|
||||||
|
|
||||||
func (t *optun) Start(localAddr string, detail *SDWANInfo) error {
|
func (t *optun) Start(localAddr string, detail *SDWANInfo) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *optun) Read(bufs [][]byte, sizes []int, offset int) (n int, err error) {
|
func (t *optun) Read(bufs [][]byte, sizes []int, offset int) (n int, err error) {
|
||||||
bufs[0] = <-AndroidReadTun
|
bufs[0] = <-AndroidReadTun
|
||||||
sizes[0] = len(bufs[0])
|
sizes[0] = len(bufs[0])
|
||||||
return 1, nil
|
return 1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *optun) Write(bufs [][]byte, offset int) (int, error) {
|
func (t *optun) Write(bufs [][]byte, offset int) (int, error) {
|
||||||
AndroidWriteTun <- bufs[0]
|
AndroidWriteTun <- bufs[0]
|
||||||
return len(bufs[0]), nil
|
return len(bufs[0]), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func AndroidRead(data []byte, len int) {
|
func AndroidRead(data []byte, len int) {
|
||||||
head := PacketHeader{}
|
head := PacketHeader{}
|
||||||
parseHeader(data, &head)
|
parseHeader(data, &head)
|
||||||
gLog.Printf(LvDev, "AndroidRead tun dst ip=%s,len=%d", net.IP{byte(head.dst >> 24), byte(head.dst >> 16), byte(head.dst >> 8), byte(head.dst)}.String(), len)
|
gLog.Printf(LvDev, "AndroidRead tun dst ip=%s,len=%d", net.IP{byte(head.dst >> 24), byte(head.dst >> 16), byte(head.dst >> 8), byte(head.dst)}.String(), len)
|
||||||
buf := make([]byte, len)
|
buf := make([]byte, len)
|
||||||
copy(buf, data)
|
copy(buf, data)
|
||||||
AndroidReadTun <- buf
|
AndroidReadTun <- buf
|
||||||
}
|
}
|
||||||
|
|
||||||
func AndroidWrite(buf []byte) int {
|
func AndroidWrite(buf []byte) int {
|
||||||
p := <-AndroidWriteTun
|
p := <-AndroidWriteTun
|
||||||
copy(buf, p)
|
copy(buf, p)
|
||||||
return len(p)
|
return len(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAndroidSDWANConfig(buf []byte) int {
|
func GetAndroidSDWANConfig(buf []byte) int {
|
||||||
p := <-AndroidSDWANConfig
|
p := <-AndroidSDWANConfig
|
||||||
copy(buf, p)
|
copy(buf, p)
|
||||||
gLog.Printf(LvINFO, "AndroidSDWANConfig=%s", p)
|
gLog.Printf(LvINFO, "AndroidSDWANConfig=%s", p)
|
||||||
return len(p)
|
return len(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAndroidNodeName() string {
|
func GetAndroidNodeName() string {
|
||||||
gLog.Printf(LvINFO, "GetAndroidNodeName=%s", gConf.Network.Node)
|
gLog.Printf(LvINFO, "GetAndroidNodeName=%s", gConf.Network.Node)
|
||||||
return gConf.Network.Node
|
return gConf.Network.Node
|
||||||
}
|
}
|
||||||
|
|
||||||
func setTunAddr(ifname, localAddr, remoteAddr string, wintun interface{}) error {
|
func setTunAddr(ifname, localAddr, remoteAddr string, wintun interface{}) error {
|
||||||
// TODO:
|
// TODO:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addRoute(dst, gw, ifname string) error {
|
func addRoute(dst, gw, ifname string) error {
|
||||||
// TODO:
|
// TODO:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func delRoute(dst, gw string) error {
|
func delRoute(dst, gw string) error {
|
||||||
// TODO:
|
// TODO:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func delRoutesByGateway(gateway string) error {
|
func delRoutesByGateway(gateway string) error {
|
||||||
// TODO:
|
// TODO:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
AndroidReadTun = make(chan []byte, 1000)
|
AndroidReadTun = make(chan []byte, 1000)
|
||||||
AndroidWriteTun = make(chan []byte, 1000)
|
AndroidWriteTun = make(chan []byte, 1000)
|
||||||
}
|
}
|
||||||
|
|||||||
+133
-133
@@ -1,133 +1,133 @@
|
|||||||
//go:build !android
|
//go:build !android
|
||||||
// +build !android
|
// +build !android
|
||||||
|
|
||||||
// optun_linux.go
|
// optun_linux.go
|
||||||
package openp2p
|
package openp2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/openp2p-cn/wireguard-go/tun"
|
"github.com/openp2p-cn/wireguard-go/tun"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
tunIfaceName = "optun"
|
tunIfaceName = "optun"
|
||||||
PIHeaderSize = 0
|
PIHeaderSize = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
var previousIP = ""
|
var previousIP = ""
|
||||||
|
|
||||||
func (t *optun) Start(localAddr string, detail *SDWANInfo) error {
|
func (t *optun) Start(localAddr string, detail *SDWANInfo) error {
|
||||||
var err error
|
var err error
|
||||||
t.tunName = tunIfaceName
|
t.tunName = tunIfaceName
|
||||||
t.dev, err = tun.CreateTUN(t.tunName, 1420)
|
t.dev, err = tun.CreateTUN(t.tunName, 1420)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *optun) Read(bufs [][]byte, sizes []int, offset int) (n int, err error) {
|
func (t *optun) Read(bufs [][]byte, sizes []int, offset int) (n int, err error) {
|
||||||
return t.dev.Read(bufs, sizes, offset)
|
return t.dev.Read(bufs, sizes, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *optun) Write(bufs [][]byte, offset int) (int, error) {
|
func (t *optun) Write(bufs [][]byte, offset int) (int, error) {
|
||||||
return t.dev.Write(bufs, offset)
|
return t.dev.Write(bufs, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setTunAddr(ifname, localAddr, remoteAddr string, wintun interface{}) error {
|
func setTunAddr(ifname, localAddr, remoteAddr string, wintun interface{}) error {
|
||||||
ifce, err := netlink.LinkByName(ifname)
|
ifce, err := netlink.LinkByName(ifname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
netlink.LinkSetMTU(ifce, 1375)
|
netlink.LinkSetMTU(ifce, 1375)
|
||||||
netlink.LinkSetTxQLen(ifce, 100)
|
netlink.LinkSetTxQLen(ifce, 100)
|
||||||
netlink.LinkSetUp(ifce)
|
netlink.LinkSetUp(ifce)
|
||||||
|
|
||||||
ln, err := netlink.ParseIPNet(localAddr)
|
ln, err := netlink.ParseIPNet(localAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ln.Mask = net.CIDRMask(32, 32)
|
ln.Mask = net.CIDRMask(32, 32)
|
||||||
rn, err := netlink.ParseIPNet(remoteAddr)
|
rn, err := netlink.ParseIPNet(remoteAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rn.Mask = net.CIDRMask(32, 32)
|
rn.Mask = net.CIDRMask(32, 32)
|
||||||
|
|
||||||
addr := &netlink.Addr{
|
addr := &netlink.Addr{
|
||||||
IPNet: ln,
|
IPNet: ln,
|
||||||
Peer: rn,
|
Peer: rn,
|
||||||
}
|
}
|
||||||
if previousIP != "" {
|
if previousIP != "" {
|
||||||
lnDel, err := netlink.ParseIPNet(previousIP)
|
lnDel, err := netlink.ParseIPNet(previousIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
lnDel.Mask = net.CIDRMask(32, 32)
|
lnDel.Mask = net.CIDRMask(32, 32)
|
||||||
|
|
||||||
addrDel := &netlink.Addr{
|
addrDel := &netlink.Addr{
|
||||||
IPNet: lnDel,
|
IPNet: lnDel,
|
||||||
Peer: rn,
|
Peer: rn,
|
||||||
}
|
}
|
||||||
netlink.AddrDel(ifce, addrDel)
|
netlink.AddrDel(ifce, addrDel)
|
||||||
}
|
}
|
||||||
previousIP = localAddr
|
previousIP = localAddr
|
||||||
return netlink.AddrAdd(ifce, addr)
|
return netlink.AddrAdd(ifce, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func addRoute(dst, gw, ifname string) error {
|
func addRoute(dst, gw, ifname string) error {
|
||||||
_, networkid, err := net.ParseCIDR(dst)
|
_, networkid, err := net.ParseCIDR(dst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ipGW := net.ParseIP(gw)
|
ipGW := net.ParseIP(gw)
|
||||||
if ipGW == nil {
|
if ipGW == nil {
|
||||||
return fmt.Errorf("parse gateway %s failed", gw)
|
return fmt.Errorf("parse gateway %s failed", gw)
|
||||||
}
|
}
|
||||||
route := &netlink.Route{
|
route := &netlink.Route{
|
||||||
Dst: networkid,
|
Dst: networkid,
|
||||||
Gw: ipGW,
|
Gw: ipGW,
|
||||||
}
|
}
|
||||||
return netlink.RouteAdd(route)
|
return netlink.RouteAdd(route)
|
||||||
}
|
}
|
||||||
|
|
||||||
func delRoute(dst, gw string) error {
|
func delRoute(dst, gw string) error {
|
||||||
_, networkid, err := net.ParseCIDR(dst)
|
_, networkid, err := net.ParseCIDR(dst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
route := &netlink.Route{
|
route := &netlink.Route{
|
||||||
Dst: networkid,
|
Dst: networkid,
|
||||||
}
|
}
|
||||||
return netlink.RouteDel(route)
|
return netlink.RouteDel(route)
|
||||||
}
|
}
|
||||||
|
|
||||||
func delRoutesByGateway(gateway string) error {
|
func delRoutesByGateway(gateway string) error {
|
||||||
cmd := exec.Command("route", "-n")
|
cmd := exec.Command("route", "-n")
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
lines := strings.Split(string(output), "\n")
|
lines := strings.Split(string(output), "\n")
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
if !strings.Contains(line, gateway) {
|
if !strings.Contains(line, gateway) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fields := strings.Fields(line)
|
fields := strings.Fields(line)
|
||||||
if len(fields) >= 8 && fields[1] == "0.0.0.0" && fields[7] == gateway {
|
if len(fields) >= 8 && fields[1] == "0.0.0.0" && fields[7] == gateway {
|
||||||
delCmd := exec.Command("route", "del", "-net", fields[0], "gw", gateway)
|
delCmd := exec.Command("route", "del", "-net", fields[0], "gw", gateway)
|
||||||
err := delCmd.Run()
|
err := delCmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("Delete route ok: %s %s %s\n", fields[0], fields[1], gateway)
|
fmt.Printf("Delete route ok: %s %s %s\n", fields[0], fields[1], gateway)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
+142
-142
@@ -1,142 +1,142 @@
|
|||||||
package openp2p
|
package openp2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/openp2p-cn/wireguard-go/tun"
|
"github.com/openp2p-cn/wireguard-go/tun"
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
tunIfaceName = "optun"
|
tunIfaceName = "optun"
|
||||||
PIHeaderSize = 0
|
PIHeaderSize = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t *optun) Start(localAddr string, detail *SDWANInfo) error {
|
func (t *optun) Start(localAddr string, detail *SDWANInfo) error {
|
||||||
// check wintun.dll
|
// check wintun.dll
|
||||||
tmpFile := filepath.Dir(os.Args[0]) + "/wintun.dll"
|
tmpFile := filepath.Dir(os.Args[0]) + "/wintun.dll"
|
||||||
fs, err := os.Stat(tmpFile)
|
fs, err := os.Stat(tmpFile)
|
||||||
if err != nil || fs.Size() == 0 {
|
if err != nil || fs.Size() == 0 {
|
||||||
url := fmt.Sprintf("https://openp2p.cn/download/v1/latest/wintun/%s/wintun.dll", runtime.GOARCH)
|
url := fmt.Sprintf("https://openp2p.cn/download/v1/latest/wintun/%s/wintun.dll", runtime.GOARCH)
|
||||||
err = downloadFile(url, "", tmpFile)
|
err = downloadFile(url, "", tmpFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.Remove(tmpFile)
|
os.Remove(tmpFile)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t.tunName = tunIfaceName
|
t.tunName = tunIfaceName
|
||||||
|
|
||||||
uuid := &windows.GUID{
|
uuid := &windows.GUID{
|
||||||
Data1: 0xf411e821,
|
Data1: 0xf411e821,
|
||||||
Data2: 0xb310,
|
Data2: 0xb310,
|
||||||
Data3: 0x4567,
|
Data3: 0x4567,
|
||||||
Data4: [8]byte{0x80, 0x42, 0x83, 0x7e, 0xf4, 0x56, 0xce, 0x13},
|
Data4: [8]byte{0x80, 0x42, 0x83, 0x7e, 0xf4, 0x56, 0xce, 0x13},
|
||||||
}
|
}
|
||||||
t.dev, err = tun.CreateTUNWithRequestedGUID(t.tunName, uuid, 1420)
|
t.dev, err = tun.CreateTUNWithRequestedGUID(t.tunName, uuid, 1420)
|
||||||
if err != nil { // retry
|
if err != nil { // retry
|
||||||
t.dev, err = tun.CreateTUNWithRequestedGUID(t.tunName, uuid, 1420)
|
t.dev, err = tun.CreateTUNWithRequestedGUID(t.tunName, uuid, 1420)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *optun) Read(bufs [][]byte, sizes []int, offset int) (n int, err error) {
|
func (t *optun) Read(bufs [][]byte, sizes []int, offset int) (n int, err error) {
|
||||||
return t.dev.Read(bufs, sizes, offset)
|
return t.dev.Read(bufs, sizes, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *optun) Write(bufs [][]byte, offset int) (int, error) {
|
func (t *optun) Write(bufs [][]byte, offset int) (int, error) {
|
||||||
return t.dev.Write(bufs, offset)
|
return t.dev.Write(bufs, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setTunAddr(ifname, localAddr, remoteAddr string, wintun interface{}) error {
|
func setTunAddr(ifname, localAddr, remoteAddr string, wintun interface{}) error {
|
||||||
nativeTunDevice := wintun.(*tun.NativeTun)
|
nativeTunDevice := wintun.(*tun.NativeTun)
|
||||||
link := winipcfg.LUID(nativeTunDevice.LUID())
|
link := winipcfg.LUID(nativeTunDevice.LUID())
|
||||||
ip, err := netip.ParsePrefix(localAddr)
|
ip, err := netip.ParsePrefix(localAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvERROR, "ParsePrefix error:%s, luid:%d,localAddr:%s", err, nativeTunDevice.LUID(), localAddr)
|
gLog.Printf(LvERROR, "ParsePrefix error:%s, luid:%d,localAddr:%s", err, nativeTunDevice.LUID(), localAddr)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = link.SetIPAddresses([]netip.Prefix{ip})
|
err = link.SetIPAddresses([]netip.Prefix{ip})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvERROR, "SetIPAddresses error:%s, netip.Prefix:%+v", err, []netip.Prefix{ip})
|
gLog.Printf(LvERROR, "SetIPAddresses error:%s, netip.Prefix:%+v", err, []netip.Prefix{ip})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addRoute(dst, gw, ifname string) error {
|
func addRoute(dst, gw, ifname string) error {
|
||||||
_, dstNet, err := net.ParseCIDR(dst)
|
_, dstNet, err := net.ParseCIDR(dst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
i, err := net.InterfaceByName(ifname)
|
i, err := net.InterfaceByName(ifname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
params := make([]string, 0)
|
params := make([]string, 0)
|
||||||
params = append(params, "add")
|
params = append(params, "add")
|
||||||
params = append(params, dstNet.IP.String())
|
params = append(params, dstNet.IP.String())
|
||||||
params = append(params, "mask")
|
params = append(params, "mask")
|
||||||
params = append(params, net.IP(dstNet.Mask).String())
|
params = append(params, net.IP(dstNet.Mask).String())
|
||||||
params = append(params, gw)
|
params = append(params, gw)
|
||||||
params = append(params, "if")
|
params = append(params, "if")
|
||||||
params = append(params, strconv.Itoa(i.Index))
|
params = append(params, strconv.Itoa(i.Index))
|
||||||
// gLogger.Println(LevelINFO, "windows add route params:", params)
|
// gLogger.Println(LevelINFO, "windows add route params:", params)
|
||||||
execCommand("route", true, params...)
|
execCommand("route", true, params...)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func delRoute(dst, gw string) error {
|
func delRoute(dst, gw string) error {
|
||||||
_, dstNet, err := net.ParseCIDR(dst)
|
_, dstNet, err := net.ParseCIDR(dst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
params := make([]string, 0)
|
params := make([]string, 0)
|
||||||
params = append(params, "delete")
|
params = append(params, "delete")
|
||||||
params = append(params, dstNet.IP.String())
|
params = append(params, dstNet.IP.String())
|
||||||
params = append(params, "mask")
|
params = append(params, "mask")
|
||||||
params = append(params, net.IP(dstNet.Mask).String())
|
params = append(params, net.IP(dstNet.Mask).String())
|
||||||
params = append(params, gw)
|
params = append(params, gw)
|
||||||
// gLogger.Println(LevelINFO, "windows delete route params:", params)
|
// gLogger.Println(LevelINFO, "windows delete route params:", params)
|
||||||
execCommand("route", true, params...)
|
execCommand("route", true, params...)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func delRoutesByGateway(gateway string) error {
|
func delRoutesByGateway(gateway string) error {
|
||||||
cmd := exec.Command("route", "print", "-4")
|
cmd := exec.Command("route", "print", "-4")
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
lines := strings.Split(string(output), "\n")
|
lines := strings.Split(string(output), "\n")
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
if !strings.Contains(line, gateway) {
|
if !strings.Contains(line, gateway) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fields := strings.Fields(line)
|
fields := strings.Fields(line)
|
||||||
if len(fields) >= 5 {
|
if len(fields) >= 5 {
|
||||||
cmd := exec.Command("route", "delete", fields[0], "mask", fields[1], gateway)
|
cmd := exec.Command("route", "delete", fields[0], "mask", fields[1], gateway)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Delete route error:", err)
|
fmt.Println("Delete route error:", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("Delete route ok: %s %s %s\n", fields[0], fields[1], gateway)
|
fmt.Printf("Delete route ok: %s %s %s\n", fields[0], fields[1], gateway)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-14
@@ -138,7 +138,7 @@ func (app *p2pApp) checkDirectTunnel() error {
|
|||||||
app.config.retryNum = 1
|
app.config.retryNum = 1
|
||||||
}
|
}
|
||||||
if app.config.retryNum > 0 { // first time not show reconnect log
|
if app.config.retryNum > 0 { // first time not show reconnect log
|
||||||
gLog.Printf(LvINFO, "detect app %s appid:%d disconnect, reconnecting the %d times...", app.config.PeerNode, app.id, app.config.retryNum)
|
gLog.Printf(LvINFO, "detect app %s appid:%d disconnect, reconnecting the %d times...", app.config.LogPeerNode(), app.id, app.config.retryNum)
|
||||||
}
|
}
|
||||||
app.config.retryNum++
|
app.config.retryNum++
|
||||||
app.config.retryTime = time.Now()
|
app.config.retryTime = time.Now()
|
||||||
@@ -149,7 +149,7 @@ func (app *p2pApp) checkDirectTunnel() error {
|
|||||||
app.config.errMsg = err.Error()
|
app.config.errMsg = err.Error()
|
||||||
if err == ErrPeerOffline && app.config.retryNum > 2 { // stop retry, waiting for online
|
if err == ErrPeerOffline && app.config.retryNum > 2 { // stop retry, waiting for online
|
||||||
app.config.retryNum = retryLimit
|
app.config.retryNum = retryLimit
|
||||||
gLog.Printf(LvINFO, " %s offline, it will auto reconnect when peer node online", app.config.PeerNode)
|
gLog.Printf(LvINFO, " %s offline, it will auto reconnect when peer node online", app.config.LogPeerNode())
|
||||||
}
|
}
|
||||||
if err == ErrBuildTunnelBusy {
|
if err == ErrBuildTunnelBusy {
|
||||||
app.config.retryNum--
|
app.config.retryNum--
|
||||||
@@ -174,7 +174,7 @@ func (app *p2pApp) buildDirectTunnel() error {
|
|||||||
pn := GNetwork
|
pn := GNetwork
|
||||||
initErr := pn.requestPeerInfo(&app.config)
|
initErr := pn.requestPeerInfo(&app.config)
|
||||||
if initErr != nil {
|
if initErr != nil {
|
||||||
gLog.Printf(LvERROR, "%s init error:%s", app.config.PeerNode, initErr)
|
gLog.Printf(LvERROR, "%s init error:%s", app.config.LogPeerNode(), initErr)
|
||||||
return initErr
|
return initErr
|
||||||
}
|
}
|
||||||
t, err = pn.addDirectTunnel(app.config, 0)
|
t, err = pn.addDirectTunnel(app.config, 0)
|
||||||
@@ -212,7 +212,7 @@ func (app *p2pApp) buildDirectTunnel() error {
|
|||||||
AppID: app.id,
|
AppID: app.id,
|
||||||
AppKey: app.key,
|
AppKey: app.key,
|
||||||
}
|
}
|
||||||
gLog.Printf(LvDEBUG, "sync appkey direct to %s", app.config.PeerNode)
|
gLog.Printf(LvDEBUG, "sync appkey direct to %s", app.config.LogPeerNode())
|
||||||
pn.push(app.config.PeerNode, MsgPushAPPKey, &syncKeyReq)
|
pn.push(app.config.PeerNode, MsgPushAPPKey, &syncKeyReq)
|
||||||
app.setDirectTunnel(t)
|
app.setDirectTunnel(t)
|
||||||
|
|
||||||
@@ -220,7 +220,7 @@ func (app *p2pApp) buildDirectTunnel() error {
|
|||||||
if app.config.SrcPort == 0 {
|
if app.config.SrcPort == 0 {
|
||||||
req := ServerSideSaveMemApp{From: gConf.Network.Node, Node: gConf.Network.Node, TunnelID: t.id, RelayTunnelID: 0, AppID: app.id}
|
req := ServerSideSaveMemApp{From: gConf.Network.Node, Node: gConf.Network.Node, TunnelID: t.id, RelayTunnelID: 0, AppID: app.id}
|
||||||
pn.push(app.config.PeerNode, MsgPushServerSideSaveMemApp, &req)
|
pn.push(app.config.PeerNode, MsgPushServerSideSaveMemApp, &req)
|
||||||
gLog.Printf(LvDEBUG, "push %s ServerSideSaveMemApp: %s", app.config.PeerNode, prettyJson(req))
|
gLog.Printf(LvDEBUG, "push %s ServerSideSaveMemApp: %s", app.config.LogPeerNode(), prettyJson(req))
|
||||||
}
|
}
|
||||||
gLog.Printf(LvDEBUG, "%s use tunnel %d", app.config.AppName, t.id)
|
gLog.Printf(LvDEBUG, "%s use tunnel %d", app.config.AppName, t.id)
|
||||||
return nil
|
return nil
|
||||||
@@ -244,7 +244,7 @@ func (app *p2pApp) checkRelayTunnel() error {
|
|||||||
app.retryRelayNum = 1
|
app.retryRelayNum = 1
|
||||||
}
|
}
|
||||||
if app.retryRelayNum > 0 { // first time not show reconnect log
|
if app.retryRelayNum > 0 { // first time not show reconnect log
|
||||||
gLog.Printf(LvINFO, "detect app %s appid:%d relay disconnect, reconnecting the %d times...", app.config.PeerNode, app.id, app.retryRelayNum)
|
gLog.Printf(LvINFO, "detect app %s appid:%d relay disconnect, reconnecting the %d times...", app.config.LogPeerNode(), app.id, app.retryRelayNum)
|
||||||
}
|
}
|
||||||
app.setRelayTunnel(nil) // reset relayTunnel
|
app.setRelayTunnel(nil) // reset relayTunnel
|
||||||
app.retryRelayNum++
|
app.retryRelayNum++
|
||||||
@@ -256,7 +256,7 @@ func (app *p2pApp) checkRelayTunnel() error {
|
|||||||
app.errMsg = err.Error()
|
app.errMsg = err.Error()
|
||||||
if err == ErrPeerOffline && app.retryRelayNum > 2 { // stop retry, waiting for online
|
if err == ErrPeerOffline && app.retryRelayNum > 2 { // stop retry, waiting for online
|
||||||
app.retryRelayNum = retryLimit
|
app.retryRelayNum = retryLimit
|
||||||
gLog.Printf(LvINFO, " %s offline, it will auto reconnect when peer node online", app.config.PeerNode)
|
gLog.Printf(LvINFO, " %s offline, it will auto reconnect when peer node online", app.config.LogPeerNode())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if app.Tunnel() != nil {
|
if app.Tunnel() != nil {
|
||||||
@@ -282,7 +282,7 @@ func (app *p2pApp) buildRelayTunnel() error {
|
|||||||
config := app.config
|
config := app.config
|
||||||
initErr := pn.requestPeerInfo(&config)
|
initErr := pn.requestPeerInfo(&config)
|
||||||
if initErr != nil {
|
if initErr != nil {
|
||||||
gLog.Printf(LvERROR, "%s init error:%s", config.PeerNode, initErr)
|
gLog.Printf(LvERROR, "%s init error:%s", config.LogPeerNode(), initErr)
|
||||||
return initErr
|
return initErr
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,7 +318,7 @@ func (app *p2pApp) buildRelayTunnel() error {
|
|||||||
AppID: app.id,
|
AppID: app.id,
|
||||||
AppKey: app.key,
|
AppKey: app.key,
|
||||||
}
|
}
|
||||||
gLog.Printf(LvDEBUG, "sync appkey relay to %s", config.PeerNode)
|
gLog.Printf(LvDEBUG, "sync appkey relay to %s", config.LogPeerNode())
|
||||||
pn.push(config.PeerNode, MsgPushAPPKey, &syncKeyReq)
|
pn.push(config.PeerNode, MsgPushAPPKey, &syncKeyReq)
|
||||||
app.setRelayTunnelID(rtid)
|
app.setRelayTunnelID(rtid)
|
||||||
app.setRelayTunnel(t)
|
app.setRelayTunnel(t)
|
||||||
@@ -330,7 +330,7 @@ func (app *p2pApp) buildRelayTunnel() error {
|
|||||||
if config.SrcPort == 0 {
|
if config.SrcPort == 0 {
|
||||||
req := ServerSideSaveMemApp{From: gConf.Network.Node, Node: relayNode, TunnelID: rtid, RelayTunnelID: t.id, AppID: app.id, RelayMode: relayMode}
|
req := ServerSideSaveMemApp{From: gConf.Network.Node, Node: relayNode, TunnelID: rtid, RelayTunnelID: t.id, AppID: app.id, RelayMode: relayMode}
|
||||||
pn.push(config.PeerNode, MsgPushServerSideSaveMemApp, &req)
|
pn.push(config.PeerNode, MsgPushServerSideSaveMemApp, &req)
|
||||||
gLog.Printf(LvDEBUG, "push %s relay ServerSideSaveMemApp: %s", config.PeerNode, prettyJson(req))
|
gLog.Printf(LvDEBUG, "push %s relay ServerSideSaveMemApp: %s", config.LogPeerNode(), prettyJson(req))
|
||||||
}
|
}
|
||||||
gLog.Printf(LvDEBUG, "%s use tunnel %d", app.config.AppName, t.id)
|
gLog.Printf(LvDEBUG, "%s use tunnel %d", app.config.AppName, t.id)
|
||||||
return nil
|
return nil
|
||||||
@@ -594,8 +594,8 @@ func (app *p2pApp) close() {
|
|||||||
func (app *p2pApp) relayHeartbeatLoop() {
|
func (app *p2pApp) relayHeartbeatLoop() {
|
||||||
app.wg.Add(1)
|
app.wg.Add(1)
|
||||||
defer app.wg.Done()
|
defer app.wg.Done()
|
||||||
gLog.Printf(LvDEBUG, "%s appid:%d relayHeartbeat to rtid:%d start", app.config.PeerNode, app.id, app.rtid)
|
gLog.Printf(LvDEBUG, "%s appid:%d relayHeartbeat to rtid:%d start", app.config.LogPeerNode(), app.id, app.rtid)
|
||||||
defer gLog.Printf(LvDEBUG, "%s appid:%d relayHeartbeat to rtid%d end", app.config.PeerNode, app.id, app.rtid)
|
defer gLog.Printf(LvDEBUG, "%s appid:%d relayHeartbeat to rtid%d end", app.config.LogPeerNode(), app.id, app.rtid)
|
||||||
|
|
||||||
for app.running {
|
for app.running {
|
||||||
if app.RelayTunnel() == nil || !app.RelayTunnel().isRuning() {
|
if app.RelayTunnel() == nil || !app.RelayTunnel().isRuning() {
|
||||||
@@ -606,11 +606,11 @@ func (app *p2pApp) relayHeartbeatLoop() {
|
|||||||
AppID: app.id}
|
AppID: app.id}
|
||||||
err := app.RelayTunnel().WriteMessage(app.rtid, MsgP2P, MsgRelayHeartbeat, &req)
|
err := app.RelayTunnel().WriteMessage(app.rtid, MsgP2P, MsgRelayHeartbeat, &req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvERROR, "%s appid:%d rtid:%d write relay tunnel heartbeat error %s", app.config.PeerNode, app.id, app.rtid, err)
|
gLog.Printf(LvERROR, "%s appid:%d rtid:%d write relay tunnel heartbeat error %s", app.config.LogPeerNode(), app.id, app.rtid, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// TODO: debug relay heartbeat
|
// TODO: debug relay heartbeat
|
||||||
gLog.Printf(LvDEBUG, "%s appid:%d rtid:%d write relay tunnel heartbeat ok", app.config.PeerNode, app.id, app.rtid)
|
gLog.Printf(LvDEBUG, "%s appid:%d rtid:%d write relay tunnel heartbeat ok", app.config.LogPeerNode(), app.id, app.rtid)
|
||||||
time.Sleep(TunnelHeartbeatTime)
|
time.Sleep(TunnelHeartbeatTime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+976
-978
@@ -1,978 +1,976 @@
|
|||||||
package openp2p
|
package openp2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
v4l *v4Listener
|
v4l *v4Listener
|
||||||
instance *P2PNetwork
|
instance *P2PNetwork
|
||||||
onceP2PNetwork sync.Once
|
onceP2PNetwork sync.Once
|
||||||
onceV4Listener sync.Once
|
onceV4Listener sync.Once
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
retryLimit = 20
|
retryLimit = 20
|
||||||
retryInterval = 10 * time.Second
|
retryInterval = 10 * time.Second
|
||||||
DefaultLoginMaxDelaySeconds = 60
|
DefaultLoginMaxDelaySeconds = 60
|
||||||
)
|
)
|
||||||
|
|
||||||
// golang not support float64 const
|
// golang not support float64 const
|
||||||
var (
|
var (
|
||||||
ma10 float64 = 1.0 / 10
|
ma10 float64 = 1.0 / 10
|
||||||
ma5 float64 = 1.0 / 5
|
ma5 float64 = 1.0 / 5
|
||||||
)
|
)
|
||||||
|
|
||||||
type NodeData struct {
|
type NodeData struct {
|
||||||
NodeID uint64
|
NodeID uint64
|
||||||
Data []byte
|
Data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type P2PNetwork struct {
|
type P2PNetwork struct {
|
||||||
conn *websocket.Conn
|
conn *websocket.Conn
|
||||||
online bool
|
online bool
|
||||||
running bool
|
running bool
|
||||||
restartCh chan bool
|
restartCh chan bool
|
||||||
wgReconnect sync.WaitGroup
|
wgReconnect sync.WaitGroup
|
||||||
writeMtx sync.Mutex
|
writeMtx sync.Mutex
|
||||||
reqGatewayMtx sync.Mutex
|
reqGatewayMtx sync.Mutex
|
||||||
hbTime time.Time
|
hbTime time.Time
|
||||||
// for sync server time
|
// for sync server time
|
||||||
t1 int64 // nanoSeconds
|
t1 int64 // nanoSeconds
|
||||||
preRtt int64 // nanoSeconds
|
preRtt int64 // nanoSeconds
|
||||||
dt int64 // client faster then server dt nanoSeconds
|
dt int64 // client faster then server dt nanoSeconds
|
||||||
ddtma int64
|
ddtma int64
|
||||||
ddt int64 // differential of dt
|
ddt int64 // differential of dt
|
||||||
msgMap sync.Map //key: nodeID
|
msgMap sync.Map //key: nodeID
|
||||||
// msgMap map[uint64]chan pushMsg //key: nodeID
|
// msgMap map[uint64]chan pushMsg //key: nodeID
|
||||||
allTunnels sync.Map // key: tid
|
allTunnels sync.Map // key: tid
|
||||||
apps sync.Map //key: config.ID(); value: *p2pApp
|
apps sync.Map //key: config.ID(); value: *p2pApp
|
||||||
limiter *SpeedLimiter
|
limiter *SpeedLimiter
|
||||||
nodeData chan *NodeData
|
nodeData chan *NodeData
|
||||||
sdwan *p2pSDWAN
|
sdwan *p2pSDWAN
|
||||||
tunnelCloseCh chan *P2PTunnel
|
tunnelCloseCh chan *P2PTunnel
|
||||||
loginMaxDelaySeconds int
|
loginMaxDelaySeconds int
|
||||||
}
|
}
|
||||||
|
|
||||||
type msgCtx struct {
|
type msgCtx struct {
|
||||||
data []byte
|
data []byte
|
||||||
ts time.Time
|
ts time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func P2PNetworkInstance() *P2PNetwork {
|
func P2PNetworkInstance() *P2PNetwork {
|
||||||
if instance == nil {
|
if instance == nil {
|
||||||
onceP2PNetwork.Do(func() {
|
onceP2PNetwork.Do(func() {
|
||||||
instance = &P2PNetwork{
|
instance = &P2PNetwork{
|
||||||
restartCh: make(chan bool, 1),
|
restartCh: make(chan bool, 1),
|
||||||
tunnelCloseCh: make(chan *P2PTunnel, 100),
|
tunnelCloseCh: make(chan *P2PTunnel, 100),
|
||||||
nodeData: make(chan *NodeData, 10000),
|
nodeData: make(chan *NodeData, 10000),
|
||||||
online: false,
|
online: false,
|
||||||
running: true,
|
running: true,
|
||||||
limiter: newSpeedLimiter(gConf.Network.ShareBandwidth*1024*1024/8, 1),
|
limiter: newSpeedLimiter(gConf.Network.ShareBandwidth*1024*1024/8, 1),
|
||||||
dt: 0,
|
dt: 0,
|
||||||
ddt: 0,
|
ddt: 0,
|
||||||
loginMaxDelaySeconds: DefaultLoginMaxDelaySeconds,
|
loginMaxDelaySeconds: DefaultLoginMaxDelaySeconds,
|
||||||
}
|
}
|
||||||
instance.msgMap.Store(uint64(0), make(chan msgCtx, 50)) // for gateway
|
instance.msgMap.Store(uint64(0), make(chan msgCtx, 50)) // for gateway
|
||||||
instance.StartSDWAN()
|
instance.StartSDWAN()
|
||||||
instance.init()
|
instance.init()
|
||||||
go instance.run()
|
go instance.run()
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
instance.refreshIPv6()
|
instance.refreshIPv6()
|
||||||
time.Sleep(time.Hour)
|
time.Sleep(time.Hour)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
cleanTempFiles()
|
cleanTempFiles()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return instance
|
return instance
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pn *P2PNetwork) run() {
|
func (pn *P2PNetwork) run() {
|
||||||
heartbeatTimer := time.NewTicker(NetworkHeartbeatTime)
|
heartbeatTimer := time.NewTicker(NetworkHeartbeatTime)
|
||||||
pn.t1 = time.Now().UnixNano()
|
pn.t1 = time.Now().UnixNano()
|
||||||
pn.write(MsgHeartbeat, 0, "")
|
pn.write(MsgHeartbeat, 0, "")
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-heartbeatTimer.C:
|
case <-heartbeatTimer.C:
|
||||||
pn.t1 = time.Now().UnixNano()
|
pn.t1 = time.Now().UnixNano()
|
||||||
pn.write(MsgHeartbeat, 0, "")
|
pn.write(MsgHeartbeat, 0, "")
|
||||||
case <-pn.restartCh:
|
case <-pn.restartCh:
|
||||||
gLog.Printf(LvDEBUG, "got restart channel")
|
gLog.Printf(LvDEBUG, "got restart channel")
|
||||||
pn.online = false
|
pn.online = false
|
||||||
pn.wgReconnect.Wait() // wait read/autorunapp goroutine end
|
pn.wgReconnect.Wait() // wait read/autorunapp goroutine end
|
||||||
delay := ClientAPITimeout + time.Duration(rand.Int()%pn.loginMaxDelaySeconds)*time.Second
|
delay := ClientAPITimeout + time.Duration(rand.Int()%pn.loginMaxDelaySeconds)*time.Second
|
||||||
time.Sleep(delay)
|
time.Sleep(delay)
|
||||||
err := pn.init()
|
err := pn.init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "P2PNetwork init error:", err)
|
gLog.Println(LvERROR, "P2PNetwork init error:", err)
|
||||||
}
|
}
|
||||||
gConf.retryAllApp()
|
gConf.retryAllApp()
|
||||||
case t := <-pn.tunnelCloseCh:
|
case t := <-pn.tunnelCloseCh:
|
||||||
gLog.Printf(LvDEBUG, "got tunnelCloseCh %s", t.config.PeerNode)
|
gLog.Printf(LvDEBUG, "got tunnelCloseCh %s", t.config.LogPeerNode())
|
||||||
pn.apps.Range(func(id, i interface{}) bool {
|
pn.apps.Range(func(id, i interface{}) bool {
|
||||||
app := i.(*p2pApp)
|
app := i.(*p2pApp)
|
||||||
if app.DirectTunnel() == t {
|
if app.DirectTunnel() == t {
|
||||||
app.setDirectTunnel(nil)
|
app.setDirectTunnel(nil)
|
||||||
}
|
}
|
||||||
if app.RelayTunnel() == t {
|
if app.RelayTunnel() == t {
|
||||||
app.setRelayTunnel(nil)
|
app.setRelayTunnel(nil)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pn *P2PNetwork) NotifyTunnelClose(t *P2PTunnel) bool {
|
func (pn *P2PNetwork) NotifyTunnelClose(t *P2PTunnel) bool {
|
||||||
select {
|
select {
|
||||||
case pn.tunnelCloseCh <- t:
|
case pn.tunnelCloseCh <- t:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pn *P2PNetwork) Connect(timeout int) bool {
|
func (pn *P2PNetwork) Connect(timeout int) bool {
|
||||||
// waiting for heartbeat
|
// waiting for heartbeat
|
||||||
for i := 0; i < (timeout / 1000); i++ {
|
for i := 0; i < (timeout / 1000); i++ {
|
||||||
if pn.hbTime.After(time.Now().Add(-NetworkHeartbeatTime)) {
|
if pn.hbTime.After(time.Now().Add(-NetworkHeartbeatTime)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pn *P2PNetwork) runAll() {
|
func (pn *P2PNetwork) runAll() {
|
||||||
gConf.mtx.Lock() // lock for copy gConf.Apps and the modification of config(it's pointer)
|
gConf.mtx.Lock() // lock for copy gConf.Apps and the modification of config(it's pointer)
|
||||||
defer gConf.mtx.Unlock()
|
defer gConf.mtx.Unlock()
|
||||||
allApps := gConf.Apps // read a copy, other thread will modify the gConf.Apps
|
allApps := gConf.Apps // read a copy, other thread will modify the gConf.Apps
|
||||||
for _, config := range allApps {
|
for _, config := range allApps {
|
||||||
if config.AppName == "" {
|
if config.AppName == "" {
|
||||||
config.AppName = fmt.Sprintf("%d", config.ID())
|
config.AppName = fmt.Sprintf("%d", config.ID())
|
||||||
}
|
}
|
||||||
if config.Enabled == 0 {
|
if config.Enabled == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, ok := pn.apps.Load(config.ID()); ok {
|
if _, ok := pn.apps.Load(config.ID()); ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
config.peerToken = gConf.Network.Token
|
config.peerToken = gConf.Network.Token
|
||||||
gConf.mtx.Unlock() // AddApp will take a period of time, let outside modify gConf
|
gConf.mtx.Unlock() // AddApp will take a period of time, let outside modify gConf
|
||||||
pn.AddApp(*config)
|
pn.AddApp(*config)
|
||||||
gConf.mtx.Lock()
|
gConf.mtx.Lock()
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pn *P2PNetwork) autorunApp() {
|
func (pn *P2PNetwork) autorunApp() {
|
||||||
gLog.Println(LvINFO, "autorunApp start")
|
gLog.Println(LvINFO, "autorunApp start")
|
||||||
pn.wgReconnect.Add(1)
|
pn.wgReconnect.Add(1)
|
||||||
defer pn.wgReconnect.Done()
|
defer pn.wgReconnect.Done()
|
||||||
for pn.running && pn.online {
|
for pn.running && pn.online {
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
pn.runAll()
|
pn.runAll()
|
||||||
}
|
}
|
||||||
gLog.Println(LvINFO, "autorunApp end")
|
gLog.Println(LvINFO, "autorunApp end")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pn *P2PNetwork) addRelayTunnel(config AppConfig) (*P2PTunnel, uint64, string, error) {
|
func (pn *P2PNetwork) addRelayTunnel(config AppConfig) (*P2PTunnel, uint64, string, error) {
|
||||||
gLog.Printf(LvINFO, "addRelayTunnel to %s start", config.PeerNode)
|
gLog.Printf(LvINFO, "addRelayTunnel to %s start", config.LogPeerNode())
|
||||||
defer gLog.Printf(LvINFO, "addRelayTunnel to %s end", config.PeerNode)
|
defer gLog.Printf(LvINFO, "addRelayTunnel to %s end", config.LogPeerNode())
|
||||||
relayConfig := AppConfig{
|
relayConfig := AppConfig{
|
||||||
PeerNode: config.RelayNode,
|
PeerNode: config.RelayNode,
|
||||||
peerToken: config.peerToken}
|
peerToken: config.peerToken,
|
||||||
relayMode := "private"
|
relayMode: "private"}
|
||||||
if relayConfig.PeerNode == "" {
|
if relayConfig.PeerNode == "" {
|
||||||
// find existing relay tunnel
|
// find existing relay tunnel
|
||||||
pn.apps.Range(func(id, i interface{}) bool {
|
pn.apps.Range(func(id, i interface{}) bool {
|
||||||
app := i.(*p2pApp)
|
app := i.(*p2pApp)
|
||||||
if app.config.PeerNode != config.PeerNode {
|
if app.config.PeerNode != config.PeerNode {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if app.RelayTunnel() == nil {
|
if app.RelayTunnel() == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
relayConfig.PeerNode = app.RelayTunnel().config.PeerNode
|
relayConfig.PeerNode = app.RelayTunnel().config.PeerNode
|
||||||
gLog.Printf(LvDEBUG, "found existing relay tunnel %s", relayConfig.PeerNode)
|
gLog.Printf(LvDEBUG, "found existing relay tunnel %s", relayConfig.LogPeerNode())
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
if relayConfig.PeerNode == "" { // request relay node
|
if relayConfig.PeerNode == "" { // request relay node
|
||||||
pn.reqGatewayMtx.Lock()
|
pn.reqGatewayMtx.Lock()
|
||||||
pn.write(MsgRelay, MsgRelayNodeReq, &RelayNodeReq{config.PeerNode})
|
pn.write(MsgRelay, MsgRelayNodeReq, &RelayNodeReq{config.PeerNode})
|
||||||
head, body := pn.read("", MsgRelay, MsgRelayNodeRsp, ClientAPITimeout)
|
head, body := pn.read("", MsgRelay, MsgRelayNodeRsp, ClientAPITimeout)
|
||||||
pn.reqGatewayMtx.Unlock()
|
pn.reqGatewayMtx.Unlock()
|
||||||
if head == nil {
|
if head == nil {
|
||||||
return nil, 0, "", errors.New("read MsgRelayNodeRsp error")
|
return nil, 0, "", errors.New("read MsgRelayNodeRsp error")
|
||||||
}
|
}
|
||||||
rsp := RelayNodeRsp{}
|
rsp := RelayNodeRsp{}
|
||||||
if err := json.Unmarshal(body, &rsp); err != nil {
|
if err := json.Unmarshal(body, &rsp); err != nil {
|
||||||
return nil, 0, "", errors.New("unmarshal MsgRelayNodeRsp error")
|
return nil, 0, "", errors.New("unmarshal MsgRelayNodeRsp error")
|
||||||
}
|
}
|
||||||
if rsp.RelayName == "" || rsp.RelayToken == 0 {
|
if rsp.RelayName == "" || rsp.RelayToken == 0 {
|
||||||
gLog.Printf(LvERROR, "MsgRelayNodeReq error")
|
gLog.Printf(LvERROR, "MsgRelayNodeReq error")
|
||||||
return nil, 0, "", errors.New("MsgRelayNodeReq error")
|
return nil, 0, "", errors.New("MsgRelayNodeReq error")
|
||||||
}
|
}
|
||||||
gLog.Printf(LvDEBUG, "got relay node:%s", rsp.RelayName)
|
gLog.Printf(LvDEBUG, "got relay node:%s", relayConfig.LogPeerNode())
|
||||||
|
|
||||||
relayConfig.PeerNode = rsp.RelayName
|
relayConfig.PeerNode = rsp.RelayName
|
||||||
relayConfig.peerToken = rsp.RelayToken
|
relayConfig.peerToken = rsp.RelayToken
|
||||||
relayMode = rsp.Mode
|
relayConfig.relayMode = rsp.Mode
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
t, err := pn.addDirectTunnel(relayConfig, 0)
|
t, err := pn.addDirectTunnel(relayConfig, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "direct connect error:", err)
|
gLog.Println(LvERROR, "direct connect error:", err)
|
||||||
return nil, 0, "", ErrConnectRelayNode // relay offline will stop retry
|
return nil, 0, "", ErrConnectRelayNode // relay offline will stop retry
|
||||||
}
|
}
|
||||||
// notify peer addRelayTunnel
|
// notify peer addRelayTunnel
|
||||||
req := AddRelayTunnelReq{
|
req := AddRelayTunnelReq{
|
||||||
From: gConf.Network.Node,
|
From: gConf.Network.Node,
|
||||||
RelayName: relayConfig.PeerNode,
|
RelayName: relayConfig.PeerNode,
|
||||||
RelayToken: relayConfig.peerToken,
|
RelayToken: relayConfig.peerToken,
|
||||||
RelayMode: relayMode,
|
RelayMode: relayConfig.relayMode,
|
||||||
RelayTunnelID: t.id,
|
RelayTunnelID: t.id,
|
||||||
}
|
}
|
||||||
gLog.Printf(LvDEBUG, "push %s the relay node(%s)", config.PeerNode, relayConfig.PeerNode)
|
gLog.Printf(LvDEBUG, "push %s the relay node(%s)", config.LogPeerNode(), relayConfig.LogPeerNode())
|
||||||
pn.push(config.PeerNode, MsgPushAddRelayTunnelReq, &req)
|
pn.push(config.PeerNode, MsgPushAddRelayTunnelReq, &req)
|
||||||
|
|
||||||
// wait relay ready
|
// wait relay ready
|
||||||
head, body := pn.read(config.PeerNode, MsgPush, MsgPushAddRelayTunnelRsp, PeerAddRelayTimeount)
|
head, body := pn.read(config.PeerNode, MsgPush, MsgPushAddRelayTunnelRsp, PeerAddRelayTimeount)
|
||||||
if head == nil {
|
if head == nil {
|
||||||
gLog.Printf(LvERROR, "read MsgPushAddRelayTunnelRsp error")
|
gLog.Printf(LvERROR, "read MsgPushAddRelayTunnelRsp error")
|
||||||
return nil, 0, "", errors.New("read MsgPushAddRelayTunnelRsp error")
|
return nil, 0, "", errors.New("read MsgPushAddRelayTunnelRsp error")
|
||||||
}
|
}
|
||||||
rspID := TunnelMsg{}
|
rspID := TunnelMsg{}
|
||||||
if err = json.Unmarshal(body, &rspID); err != nil {
|
if err = json.Unmarshal(body, &rspID); err != nil {
|
||||||
gLog.Println(LvDEBUG, ErrPeerConnectRelay)
|
gLog.Println(LvDEBUG, ErrPeerConnectRelay)
|
||||||
return nil, 0, "", ErrPeerConnectRelay
|
return nil, 0, "", ErrPeerConnectRelay
|
||||||
}
|
}
|
||||||
return t, rspID.ID, relayMode, err
|
return t, rspID.ID, relayConfig.relayMode, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// use *AppConfig to save status
|
// use *AppConfig to save status
|
||||||
func (pn *P2PNetwork) AddApp(config AppConfig) error {
|
func (pn *P2PNetwork) AddApp(config AppConfig) error {
|
||||||
gLog.Printf(LvINFO, "addApp %s to %s:%s:%d start", config.AppName, config.PeerNode, config.DstHost, config.DstPort)
|
gLog.Printf(LvINFO, "addApp %s to %s:%s:%d start", config.AppName, config.LogPeerNode(), config.DstHost, config.DstPort)
|
||||||
defer gLog.Printf(LvINFO, "addApp %s to %s:%s:%d end", config.AppName, config.PeerNode, config.DstHost, config.DstPort)
|
defer gLog.Printf(LvINFO, "addApp %s to %s:%s:%d end", config.AppName, config.LogPeerNode(), config.DstHost, config.DstPort)
|
||||||
if !pn.online {
|
if !pn.online {
|
||||||
return errors.New("P2PNetwork offline")
|
return errors.New("P2PNetwork offline")
|
||||||
}
|
}
|
||||||
if _, ok := pn.msgMap.Load(NodeNameToID(config.PeerNode)); !ok {
|
if _, ok := pn.msgMap.Load(NodeNameToID(config.PeerNode)); !ok {
|
||||||
pn.msgMap.Store(NodeNameToID(config.PeerNode), make(chan msgCtx, 50))
|
pn.msgMap.Store(NodeNameToID(config.PeerNode), make(chan msgCtx, 50))
|
||||||
}
|
}
|
||||||
// check if app already exist?
|
// check if app already exist?
|
||||||
if _, ok := pn.apps.Load(config.ID()); ok {
|
if _, ok := pn.apps.Load(config.ID()); ok {
|
||||||
return errors.New("P2PApp already exist")
|
return errors.New("P2PApp already exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
app := p2pApp{
|
app := p2pApp{
|
||||||
// tunnel: t,
|
// tunnel: t,
|
||||||
id: rand.Uint64(),
|
id: rand.Uint64(),
|
||||||
key: rand.Uint64(),
|
key: rand.Uint64(),
|
||||||
config: config,
|
config: config,
|
||||||
iptree: NewIPTree(config.Whitelist),
|
iptree: NewIPTree(config.Whitelist),
|
||||||
running: true,
|
running: true,
|
||||||
hbTimeRelay: time.Now(),
|
hbTimeRelay: time.Now(),
|
||||||
}
|
}
|
||||||
if _, ok := pn.msgMap.Load(NodeNameToID(config.PeerNode)); !ok {
|
if _, ok := pn.msgMap.Load(NodeNameToID(config.PeerNode)); !ok {
|
||||||
pn.msgMap.Store(NodeNameToID(config.PeerNode), make(chan msgCtx, 50))
|
pn.msgMap.Store(NodeNameToID(config.PeerNode), make(chan msgCtx, 50))
|
||||||
}
|
}
|
||||||
pn.apps.Store(config.ID(), &app)
|
pn.apps.Store(config.ID(), &app)
|
||||||
gLog.Printf(LvDEBUG, "Store app %d", config.ID())
|
gLog.Printf(LvDEBUG, "Store app %d", config.ID())
|
||||||
go app.checkP2PTunnel()
|
go app.checkP2PTunnel()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pn *P2PNetwork) DeleteApp(config AppConfig) {
|
func (pn *P2PNetwork) DeleteApp(config AppConfig) {
|
||||||
gLog.Printf(LvINFO, "DeleteApp %s to %s:%s:%d start", config.AppName, config.PeerNode, config.DstHost, config.DstPort)
|
gLog.Printf(LvINFO, "DeleteApp %s to %s:%s:%d start", config.AppName, config.LogPeerNode(), config.DstHost, config.DstPort)
|
||||||
defer gLog.Printf(LvINFO, "DeleteApp %s to %s:%s:%d end", config.AppName, config.PeerNode, config.DstHost, config.DstPort)
|
defer gLog.Printf(LvINFO, "DeleteApp %s to %s:%s:%d end", config.AppName, config.LogPeerNode(), config.DstHost, config.DstPort)
|
||||||
// close the apps of this config
|
// close the apps of this config
|
||||||
i, ok := pn.apps.Load(config.ID())
|
i, ok := pn.apps.Load(config.ID())
|
||||||
if ok {
|
if ok {
|
||||||
app := i.(*p2pApp)
|
app := i.(*p2pApp)
|
||||||
gLog.Printf(LvINFO, "app %s exist, delete it", app.config.AppName)
|
gLog.Printf(LvINFO, "app %s exist, delete it", app.config.AppName)
|
||||||
app.close()
|
app.close()
|
||||||
pn.apps.Delete(config.ID())
|
pn.apps.Delete(config.ID())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pn *P2PNetwork) findTunnel(peerNode string) (t *P2PTunnel) {
|
func (pn *P2PNetwork) findTunnel(peerNode string) (t *P2PTunnel) {
|
||||||
t = nil
|
t = nil
|
||||||
// find existing tunnel to peer
|
// find existing tunnel to peer
|
||||||
pn.allTunnels.Range(func(id, i interface{}) bool {
|
pn.allTunnels.Range(func(id, i interface{}) bool {
|
||||||
tmpt := i.(*P2PTunnel)
|
tmpt := i.(*P2PTunnel)
|
||||||
if tmpt.config.PeerNode == peerNode {
|
if tmpt.config.PeerNode == peerNode {
|
||||||
gLog.Println(LvINFO, "tunnel already exist ", peerNode)
|
gLog.Println(LvINFO, "tunnel already exist ", peerNode)
|
||||||
isActive := tmpt.checkActive()
|
isActive := tmpt.checkActive()
|
||||||
// inactive, close it
|
// inactive, close it
|
||||||
if !isActive {
|
if !isActive {
|
||||||
gLog.Println(LvINFO, "but it's not active, close it ", peerNode)
|
gLog.Println(LvINFO, "but it's not active, close it ", peerNode)
|
||||||
tmpt.close()
|
tmpt.close()
|
||||||
} else {
|
} else {
|
||||||
t = tmpt
|
t = tmpt
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunnel, err error) {
|
func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunnel, err error) {
|
||||||
gLog.Printf(LvDEBUG, "addDirectTunnel %s%d to %s:%s:%d tid:%d start", config.Protocol, config.SrcPort, config.PeerNode, config.DstHost, config.DstPort, tid)
|
gLog.Printf(LvDEBUG, "addDirectTunnel %s%d to %s:%s:%d tid:%d start", config.Protocol, config.SrcPort, config.LogPeerNode(), config.DstHost, config.DstPort, tid)
|
||||||
defer gLog.Printf(LvDEBUG, "addDirectTunnel %s%d to %s:%s:%d tid:%d end", config.Protocol, config.SrcPort, config.PeerNode, config.DstHost, config.DstPort, tid)
|
defer gLog.Printf(LvDEBUG, "addDirectTunnel %s%d to %s:%s:%d tid:%d end", config.Protocol, config.SrcPort, config.LogPeerNode(), config.DstHost, config.DstPort, tid)
|
||||||
isClient := false
|
isClient := false
|
||||||
// client side tid=0, assign random uint64
|
// client side tid=0, assign random uint64
|
||||||
if tid == 0 {
|
if tid == 0 {
|
||||||
tid = rand.Uint64()
|
tid = rand.Uint64()
|
||||||
isClient = true
|
isClient = true
|
||||||
}
|
}
|
||||||
if _, ok := pn.msgMap.Load(NodeNameToID(config.PeerNode)); !ok {
|
if _, ok := pn.msgMap.Load(NodeNameToID(config.PeerNode)); !ok {
|
||||||
pn.msgMap.Store(NodeNameToID(config.PeerNode), make(chan msgCtx, 50))
|
pn.msgMap.Store(NodeNameToID(config.PeerNode), make(chan msgCtx, 50))
|
||||||
}
|
}
|
||||||
|
|
||||||
// server side
|
// server side
|
||||||
if !isClient {
|
if !isClient {
|
||||||
t, err = pn.newTunnel(config, tid, isClient)
|
t, err = pn.newTunnel(config, tid, isClient)
|
||||||
return t, err // always return
|
return t, err // always return
|
||||||
}
|
}
|
||||||
// client side
|
// client side
|
||||||
// peer info
|
// peer info
|
||||||
initErr := pn.requestPeerInfo(&config)
|
initErr := pn.requestPeerInfo(&config)
|
||||||
if initErr != nil {
|
if initErr != nil {
|
||||||
gLog.Printf(LvERROR, "%s init error:%s", config.PeerNode, initErr)
|
gLog.Printf(LvERROR, "%s init error:%s", config.LogPeerNode(), initErr)
|
||||||
|
|
||||||
return nil, initErr
|
return nil, initErr
|
||||||
}
|
}
|
||||||
gLog.Printf(LvDEBUG, "config.peerNode=%s,config.peerVersion=%s,config.peerIP=%s,config.peerLanIP=%s,gConf.Network.publicIP=%s,config.peerIPv6=%s,config.hasIPv4=%d,config.hasUPNPorNATPMP=%d,gConf.Network.hasIPv4=%d,gConf.Network.hasUPNPorNATPMP=%d,config.peerNatType=%d,gConf.Network.natType=%d,",
|
gLog.Printf(LvDEBUG, "config.peerNode=%s,config.peerVersion=%s,config.peerIP=%s,config.peerLanIP=%s,gConf.Network.publicIP=%s,config.peerIPv6=%s,config.hasIPv4=%d,config.hasUPNPorNATPMP=%d,gConf.Network.hasIPv4=%d,gConf.Network.hasUPNPorNATPMP=%d,config.peerNatType=%d,gConf.Network.natType=%d,",
|
||||||
config.PeerNode, config.peerVersion, config.peerIP, config.peerLanIP, gConf.Network.publicIP, config.peerIPv6, config.hasIPv4, config.hasUPNPorNATPMP, gConf.Network.hasIPv4, gConf.Network.hasUPNPorNATPMP, config.peerNatType, gConf.Network.natType)
|
config.LogPeerNode(), config.peerVersion, config.peerIP, config.peerLanIP, gConf.Network.publicIP, config.peerIPv6, config.hasIPv4, config.hasUPNPorNATPMP, gConf.Network.hasIPv4, gConf.Network.hasUPNPorNATPMP, config.peerNatType, gConf.Network.natType)
|
||||||
// try Intranet
|
// try Intranet
|
||||||
if config.peerIP == gConf.Network.publicIP && compareVersion(config.peerVersion, SupportIntranetVersion) >= 0 { // old version client has no peerLanIP
|
if config.peerIP == gConf.Network.publicIP && compareVersion(config.peerVersion, SupportIntranetVersion) >= 0 { // old version client has no peerLanIP
|
||||||
gLog.Println(LvINFO, "try Intranet")
|
gLog.Println(LvINFO, "try Intranet")
|
||||||
config.linkMode = LinkModeIntranet
|
config.linkMode = LinkModeIntranet
|
||||||
config.isUnderlayServer = 0
|
config.isUnderlayServer = 0
|
||||||
if t, err = pn.newTunnel(config, tid, isClient); err == nil {
|
if t, err = pn.newTunnel(config, tid, isClient); err == nil {
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// try TCP6
|
// try TCP6
|
||||||
if IsIPv6(config.peerIPv6) && IsIPv6(gConf.IPv6()) {
|
if IsIPv6(config.peerIPv6) && IsIPv6(gConf.IPv6()) {
|
||||||
gLog.Println(LvINFO, "try TCP6")
|
gLog.Println(LvINFO, "try TCP6")
|
||||||
config.linkMode = LinkModeTCP6
|
config.linkMode = LinkModeTCP6
|
||||||
config.isUnderlayServer = 0
|
config.isUnderlayServer = 0
|
||||||
if t, err = pn.newTunnel(config, tid, isClient); err == nil {
|
if t, err = pn.newTunnel(config, tid, isClient); err == nil {
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// try UDP6? maybe no
|
// try UDP6? maybe no
|
||||||
|
|
||||||
// try TCP4
|
// try TCP4
|
||||||
if config.hasIPv4 == 1 || gConf.Network.hasIPv4 == 1 || config.hasUPNPorNATPMP == 1 || gConf.Network.hasUPNPorNATPMP == 1 {
|
if config.hasIPv4 == 1 || gConf.Network.hasIPv4 == 1 || config.hasUPNPorNATPMP == 1 || gConf.Network.hasUPNPorNATPMP == 1 {
|
||||||
gLog.Println(LvINFO, "try TCP4")
|
gLog.Println(LvINFO, "try TCP4")
|
||||||
config.linkMode = LinkModeTCP4
|
config.linkMode = LinkModeTCP4
|
||||||
if gConf.Network.hasIPv4 == 1 || gConf.Network.hasUPNPorNATPMP == 1 {
|
if gConf.Network.hasIPv4 == 1 || gConf.Network.hasUPNPorNATPMP == 1 {
|
||||||
config.isUnderlayServer = 1
|
config.isUnderlayServer = 1
|
||||||
} else {
|
} else {
|
||||||
config.isUnderlayServer = 0
|
config.isUnderlayServer = 0
|
||||||
}
|
}
|
||||||
if t, err = pn.newTunnel(config, tid, isClient); err == nil {
|
if t, err = pn.newTunnel(config, tid, isClient); err == nil {
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// try UDP4? maybe no
|
// try UDP4? maybe no
|
||||||
var primaryPunchFunc func() (*P2PTunnel, error)
|
var primaryPunchFunc func() (*P2PTunnel, error)
|
||||||
var secondaryPunchFunc func() (*P2PTunnel, error)
|
var secondaryPunchFunc func() (*P2PTunnel, error)
|
||||||
funcUDP := func() (t *P2PTunnel, err error) {
|
funcUDP := func() (t *P2PTunnel, err error) {
|
||||||
if config.PunchPriority&PunchPriorityUDPDisable != 0 {
|
if config.PunchPriority&PunchPriorityUDPDisable != 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// try UDPPunch
|
// try UDPPunch
|
||||||
for i := 0; i < Cone2ConeUDPPunchMaxRetry; i++ { // when both 2 nats has restrict firewall, simultaneous punching needs to be very precise, it takes a few tries
|
for i := 0; i < Cone2ConeUDPPunchMaxRetry; i++ { // when both 2 nats has restrict firewall, simultaneous punching needs to be very precise, it takes a few tries
|
||||||
if config.peerNatType == NATCone || gConf.Network.natType == NATCone {
|
if config.peerNatType == NATCone || gConf.Network.natType == NATCone {
|
||||||
gLog.Println(LvINFO, "try UDP4 Punch")
|
gLog.Println(LvINFO, "try UDP4 Punch")
|
||||||
config.linkMode = LinkModeUDPPunch
|
config.linkMode = LinkModeUDPPunch
|
||||||
config.isUnderlayServer = 0
|
config.isUnderlayServer = 0
|
||||||
if t, err = pn.newTunnel(config, tid, isClient); err == nil {
|
if t, err = pn.newTunnel(config, tid, isClient); err == nil {
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !(config.peerNatType == NATCone && gConf.Network.natType == NATCone) { // not cone2cone, no more try
|
if !(config.peerNatType == NATCone && gConf.Network.natType == NATCone) { // not cone2cone, no more try
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
funcTCP := func() (t *P2PTunnel, err error) {
|
funcTCP := func() (t *P2PTunnel, err error) {
|
||||||
if config.PunchPriority&PunchPriorityTCPDisable != 0 {
|
if config.PunchPriority&PunchPriorityTCPDisable != 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// try TCPPunch
|
// try TCPPunch
|
||||||
for i := 0; i < Cone2ConeTCPPunchMaxRetry; i++ { // when both 2 nats has restrict firewall, simultaneous punching needs to be very precise, it takes a few tries
|
for i := 0; i < Cone2ConeTCPPunchMaxRetry; i++ { // when both 2 nats has restrict firewall, simultaneous punching needs to be very precise, it takes a few tries
|
||||||
if config.peerNatType == NATCone || gConf.Network.natType == NATCone {
|
if config.peerNatType == NATCone || gConf.Network.natType == NATCone {
|
||||||
gLog.Println(LvINFO, "try TCP4 Punch")
|
gLog.Println(LvINFO, "try TCP4 Punch")
|
||||||
config.linkMode = LinkModeTCPPunch
|
config.linkMode = LinkModeTCPPunch
|
||||||
config.isUnderlayServer = 0
|
config.isUnderlayServer = 0
|
||||||
if t, err = pn.newTunnel(config, tid, isClient); err == nil {
|
if t, err = pn.newTunnel(config, tid, isClient); err == nil {
|
||||||
gLog.Println(LvINFO, "TCP4 Punch ok")
|
gLog.Println(LvINFO, "TCP4 Punch ok")
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if config.PunchPriority&PunchPriorityTCPFirst != 0 {
|
if config.PunchPriority&PunchPriorityTCPFirst != 0 {
|
||||||
primaryPunchFunc = funcTCP
|
primaryPunchFunc = funcTCP
|
||||||
secondaryPunchFunc = funcUDP
|
secondaryPunchFunc = funcUDP
|
||||||
} else {
|
} else {
|
||||||
primaryPunchFunc = funcTCP
|
primaryPunchFunc = funcTCP
|
||||||
secondaryPunchFunc = funcUDP
|
secondaryPunchFunc = funcUDP
|
||||||
}
|
}
|
||||||
if t, err = primaryPunchFunc(); t != nil && err == nil {
|
if t, err = primaryPunchFunc(); t != nil && err == nil {
|
||||||
return t, err
|
return t, err
|
||||||
}
|
}
|
||||||
if t, err = secondaryPunchFunc(); t != nil && err == nil {
|
if t, err = secondaryPunchFunc(); t != nil && err == nil {
|
||||||
return t, err
|
return t, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: s2s won't return err
|
// TODO: s2s won't return err
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pn *P2PNetwork) newTunnel(config AppConfig, tid uint64, isClient bool) (t *P2PTunnel, err error) {
|
func (pn *P2PNetwork) newTunnel(config AppConfig, tid uint64, isClient bool) (t *P2PTunnel, err error) {
|
||||||
if isClient { // only client side find existing tunnel
|
if isClient { // only client side find existing tunnel
|
||||||
if existTunnel := pn.findTunnel(config.PeerNode); existTunnel != nil {
|
if existTunnel := pn.findTunnel(config.PeerNode); existTunnel != nil {
|
||||||
return existTunnel, nil
|
return existTunnel, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t = &P2PTunnel{pn: pn,
|
t = &P2PTunnel{pn: pn,
|
||||||
config: config,
|
config: config,
|
||||||
id: tid,
|
id: tid,
|
||||||
writeData: make(chan []byte, WriteDataChanSize),
|
writeData: make(chan []byte, WriteDataChanSize),
|
||||||
writeDataSmall: make(chan []byte, WriteDataChanSize/30),
|
writeDataSmall: make(chan []byte, WriteDataChanSize/30),
|
||||||
}
|
}
|
||||||
t.initPort()
|
t.initPort()
|
||||||
if isClient {
|
if isClient {
|
||||||
if err = t.connect(); err != nil {
|
if err = t.connect(); err != nil {
|
||||||
gLog.Println(LvERROR, "p2pTunnel connect error:", err)
|
gLog.Println(LvERROR, "p2pTunnel connect error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err = t.listen(); err != nil {
|
if err = t.listen(); err != nil {
|
||||||
gLog.Println(LvERROR, "p2pTunnel listen error:", err)
|
gLog.Println(LvERROR, "p2pTunnel listen error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// store it when success
|
// store it when success
|
||||||
gLog.Printf(LvDEBUG, "store tunnel %d", tid)
|
gLog.Printf(LvDEBUG, "store tunnel %d", tid)
|
||||||
pn.allTunnels.Store(tid, t)
|
pn.allTunnels.Store(tid, t)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (pn *P2PNetwork) init() error {
|
func (pn *P2PNetwork) init() error {
|
||||||
gLog.Println(LvINFO, "P2PNetwork init start")
|
gLog.Println(LvINFO, "P2PNetwork init start")
|
||||||
defer gLog.Println(LvINFO, "P2PNetwork init end")
|
defer gLog.Println(LvINFO, "P2PNetwork init end")
|
||||||
pn.wgReconnect.Add(1)
|
pn.wgReconnect.Add(1)
|
||||||
defer pn.wgReconnect.Done()
|
defer pn.wgReconnect.Done()
|
||||||
var err error
|
var err error
|
||||||
for {
|
for {
|
||||||
// detect nat type
|
// detect nat type
|
||||||
gConf.Network.publicIP, gConf.Network.natType, err = getNATType(gConf.Network.ServerHost, gConf.Network.UDPPort1, gConf.Network.UDPPort2)
|
gConf.Network.publicIP, gConf.Network.natType, err = getNATType(gConf.Network.ServerHost, gConf.Network.UDPPort1, gConf.Network.UDPPort2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvDEBUG, "detect NAT type error:", err)
|
gLog.Println(LvDEBUG, "detect NAT type error:", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if gConf.Network.hasIPv4 == 0 && gConf.Network.hasUPNPorNATPMP == 0 { // if already has ipv4 or upnp no need test again
|
if gConf.Network.hasIPv4 == 0 && gConf.Network.hasUPNPorNATPMP == 0 { // if already has ipv4 or upnp no need test again
|
||||||
gConf.Network.hasIPv4, gConf.Network.hasUPNPorNATPMP = publicIPTest(gConf.Network.publicIP, gConf.Network.TCPPort)
|
gConf.Network.hasIPv4, gConf.Network.hasUPNPorNATPMP = publicIPTest(gConf.Network.publicIP, gConf.Network.TCPPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
// for testcase
|
// for testcase
|
||||||
if strings.Contains(gConf.Network.Node, "openp2pS2STest") {
|
if strings.Contains(gConf.Network.Node, "openp2pS2STest") {
|
||||||
gConf.Network.natType = NATSymmetric
|
gConf.Network.natType = NATSymmetric
|
||||||
gConf.Network.hasIPv4 = 0
|
gConf.Network.hasIPv4 = 0
|
||||||
gConf.Network.hasUPNPorNATPMP = 0
|
gConf.Network.hasUPNPorNATPMP = 0
|
||||||
gLog.Println(LvINFO, "openp2pS2STest debug")
|
gLog.Println(LvINFO, "openp2pS2STest debug")
|
||||||
|
|
||||||
}
|
}
|
||||||
if strings.Contains(gConf.Network.Node, "openp2pC2CTest") {
|
if strings.Contains(gConf.Network.Node, "openp2pC2CTest") {
|
||||||
gConf.Network.natType = NATCone
|
gConf.Network.natType = NATCone
|
||||||
gConf.Network.hasIPv4 = 0
|
gConf.Network.hasIPv4 = 0
|
||||||
gConf.Network.hasUPNPorNATPMP = 0
|
gConf.Network.hasUPNPorNATPMP = 0
|
||||||
gLog.Println(LvINFO, "openp2pC2CTest debug")
|
gLog.Println(LvINFO, "openp2pC2CTest debug")
|
||||||
}
|
}
|
||||||
|
|
||||||
if gConf.Network.hasIPv4 == 1 || gConf.Network.hasUPNPorNATPMP == 1 {
|
if gConf.Network.hasIPv4 == 1 || gConf.Network.hasUPNPorNATPMP == 1 {
|
||||||
onceV4Listener.Do(func() {
|
onceV4Listener.Do(func() {
|
||||||
v4l = &v4Listener{port: gConf.Network.TCPPort}
|
v4l = &v4Listener{port: gConf.Network.TCPPort}
|
||||||
go v4l.start()
|
go v4l.start()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
gLog.Printf(LvINFO, "hasIPv4:%d, UPNP:%d, NAT type:%d, publicIP:%s", gConf.Network.hasIPv4, gConf.Network.hasUPNPorNATPMP, gConf.Network.natType, gConf.Network.publicIP)
|
gLog.Printf(LvINFO, "hasIPv4:%d, UPNP:%d, NAT type:%d, publicIP:%s", gConf.Network.hasIPv4, gConf.Network.hasUPNPorNATPMP, gConf.Network.natType, gConf.Network.publicIP)
|
||||||
gatewayURL := fmt.Sprintf("%s:%d", gConf.Network.ServerHost, gConf.Network.ServerPort)
|
gatewayURL := fmt.Sprintf("%s:%d", gConf.Network.ServerHost, gConf.Network.ServerPort)
|
||||||
uri := "/api/v1/login"
|
uri := "/api/v1/login"
|
||||||
caCertPool, errCert := x509.SystemCertPool()
|
caCertPool, errCert := x509.SystemCertPool()
|
||||||
if errCert != nil {
|
if errCert != nil {
|
||||||
gLog.Println(LvERROR, "Failed to load system root CAs:", errCert)
|
gLog.Println(LvERROR, "Failed to load system root CAs:", errCert)
|
||||||
} else {
|
} else {
|
||||||
caCertPool = x509.NewCertPool()
|
caCertPool = x509.NewCertPool()
|
||||||
}
|
}
|
||||||
caCertPool.AppendCertsFromPEM([]byte(rootCA))
|
caCertPool.AppendCertsFromPEM([]byte(rootCA))
|
||||||
caCertPool.AppendCertsFromPEM([]byte(ISRGRootX1))
|
caCertPool.AppendCertsFromPEM([]byte(ISRGRootX1))
|
||||||
config := tls.Config{
|
config := tls.Config{
|
||||||
RootCAs: caCertPool,
|
RootCAs: caCertPool,
|
||||||
InsecureSkipVerify: false} // let's encrypt root cert "DST Root CA X3" expired at 2021/09/29. many old system(windows server 2008 etc) will not trust our cert
|
InsecureSkipVerify: false} // let's encrypt root cert "DST Root CA X3" expired at 2021/09/29. many old system(windows server 2008 etc) will not trust our cert
|
||||||
websocket.DefaultDialer.TLSClientConfig = &config
|
websocket.DefaultDialer.TLSClientConfig = &config
|
||||||
websocket.DefaultDialer.HandshakeTimeout = ClientAPITimeout
|
websocket.DefaultDialer.HandshakeTimeout = ClientAPITimeout
|
||||||
u := url.URL{Scheme: "wss", Host: gatewayURL, Path: uri}
|
u := url.URL{Scheme: "wss", Host: gatewayURL, Path: uri}
|
||||||
q := u.Query()
|
q := u.Query()
|
||||||
q.Add("node", gConf.Network.Node)
|
q.Add("node", gConf.Network.Node)
|
||||||
q.Add("token", fmt.Sprintf("%d", gConf.Network.Token))
|
q.Add("token", fmt.Sprintf("%d", gConf.Network.Token))
|
||||||
q.Add("version", OpenP2PVersion)
|
q.Add("version", OpenP2PVersion)
|
||||||
q.Add("nattype", fmt.Sprintf("%d", gConf.Network.natType))
|
q.Add("nattype", fmt.Sprintf("%d", gConf.Network.natType))
|
||||||
q.Add("sharebandwidth", fmt.Sprintf("%d", gConf.Network.ShareBandwidth))
|
q.Add("sharebandwidth", fmt.Sprintf("%d", gConf.Network.ShareBandwidth))
|
||||||
u.RawQuery = q.Encode()
|
u.RawQuery = q.Encode()
|
||||||
var ws *websocket.Conn
|
var ws *websocket.Conn
|
||||||
ws, _, err = websocket.DefaultDialer.Dial(u.String(), nil)
|
ws, _, err = websocket.DefaultDialer.Dial(u.String(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "Dial error:", err)
|
gLog.Println(LvERROR, "Dial error:", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
pn.running = true
|
pn.running = true
|
||||||
pn.online = true
|
pn.online = true
|
||||||
pn.conn = ws
|
pn.conn = ws
|
||||||
localAddr := strings.Split(ws.LocalAddr().String(), ":")
|
localAddr := strings.Split(ws.LocalAddr().String(), ":")
|
||||||
if len(localAddr) == 2 {
|
if len(localAddr) == 2 {
|
||||||
gConf.Network.localIP = localAddr[0]
|
gConf.Network.localIP = localAddr[0]
|
||||||
} else {
|
} else {
|
||||||
err = errors.New("get local ip failed")
|
err = errors.New("get local ip failed")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
go pn.readLoop()
|
go pn.readLoop()
|
||||||
gConf.Network.mac = getmac(gConf.Network.localIP)
|
gConf.Network.mac = getmac(gConf.Network.localIP)
|
||||||
gConf.Network.os = getOsName()
|
gConf.Network.os = getOsName()
|
||||||
go func() {
|
go func() {
|
||||||
req := ReportBasic{
|
req := ReportBasic{
|
||||||
Mac: gConf.Network.mac,
|
Mac: gConf.Network.mac,
|
||||||
LanIP: gConf.Network.localIP,
|
LanIP: gConf.Network.localIP,
|
||||||
OS: gConf.Network.os,
|
OS: gConf.Network.os,
|
||||||
HasIPv4: gConf.Network.hasIPv4,
|
HasIPv4: gConf.Network.hasIPv4,
|
||||||
HasUPNPorNATPMP: gConf.Network.hasUPNPorNATPMP,
|
HasUPNPorNATPMP: gConf.Network.hasUPNPorNATPMP,
|
||||||
Version: OpenP2PVersion,
|
Version: OpenP2PVersion,
|
||||||
}
|
}
|
||||||
rsp := netInfo()
|
rsp := netInfo()
|
||||||
gLog.Println(LvDEBUG, "netinfo:", rsp)
|
gLog.Println(LvDEBUG, "netinfo:", rsp)
|
||||||
if rsp != nil && rsp.Country != "" {
|
if rsp != nil && rsp.Country != "" {
|
||||||
if IsIPv6(rsp.IP.String()) {
|
if IsIPv6(rsp.IP.String()) {
|
||||||
gConf.setIPv6(rsp.IP.String())
|
gConf.setIPv6(rsp.IP.String())
|
||||||
}
|
}
|
||||||
req.NetInfo = *rsp
|
req.NetInfo = *rsp
|
||||||
} else {
|
} else {
|
||||||
pn.refreshIPv6()
|
pn.refreshIPv6()
|
||||||
}
|
}
|
||||||
req.IPv6 = gConf.IPv6()
|
req.IPv6 = gConf.IPv6()
|
||||||
pn.write(MsgReport, MsgReportBasic, &req)
|
pn.write(MsgReport, MsgReportBasic, &req)
|
||||||
}()
|
}()
|
||||||
go pn.autorunApp()
|
go pn.autorunApp()
|
||||||
pn.write(MsgSDWAN, MsgSDWANInfoReq, nil)
|
pn.write(MsgSDWAN, MsgSDWANInfoReq, nil)
|
||||||
gLog.Println(LvDEBUG, "P2PNetwork init ok")
|
gLog.Println(LvDEBUG, "P2PNetwork init ok")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// init failed, retry
|
// init failed, retry
|
||||||
pn.close()
|
pn.close()
|
||||||
gLog.Println(LvERROR, "P2PNetwork init error:", err)
|
gLog.Println(LvERROR, "P2PNetwork init error:", err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pn *P2PNetwork) handleMessage(msg []byte) {
|
func (pn *P2PNetwork) handleMessage(msg []byte) {
|
||||||
head := openP2PHeader{}
|
head := openP2PHeader{}
|
||||||
err := binary.Read(bytes.NewReader(msg[:openP2PHeaderSize]), binary.LittleEndian, &head)
|
err := binary.Read(bytes.NewReader(msg[:openP2PHeaderSize]), binary.LittleEndian, &head)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "handleMessage error:", err)
|
gLog.Println(LvERROR, "handleMessage error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch head.MainType {
|
switch head.MainType {
|
||||||
case MsgLogin:
|
case MsgLogin:
|
||||||
// gLog.Println(LevelINFO,string(msg))
|
// gLog.Println(LevelINFO,string(msg))
|
||||||
rsp := LoginRsp{}
|
rsp := LoginRsp{}
|
||||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &rsp); err != nil {
|
if err = json.Unmarshal(msg[openP2PHeaderSize:], &rsp); err != nil {
|
||||||
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(rsp), err)
|
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(rsp), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if rsp.Error != 0 {
|
if rsp.Error != 0 {
|
||||||
gLog.Printf(LvERROR, "login error:%d, detail:%s", rsp.Error, rsp.Detail)
|
gLog.Printf(LvERROR, "login error:%d, detail:%s", rsp.Error, rsp.Detail)
|
||||||
pn.running = false
|
pn.running = false
|
||||||
} else {
|
} else {
|
||||||
gConf.Network.Token = rsp.Token
|
gConf.setToken(rsp.Token)
|
||||||
gConf.Network.User = rsp.User
|
gConf.setUser(rsp.User)
|
||||||
gConf.setToken(rsp.Token)
|
if len(rsp.Node) >= MinNodeNameLen {
|
||||||
gConf.setUser(rsp.User)
|
gConf.setNode(rsp.Node)
|
||||||
if len(rsp.Node) >= MinNodeNameLen {
|
}
|
||||||
gConf.setNode(rsp.Node)
|
if rsp.LoginMaxDelay > 0 {
|
||||||
}
|
pn.loginMaxDelaySeconds = rsp.LoginMaxDelay
|
||||||
if rsp.LoginMaxDelay > 0 {
|
}
|
||||||
pn.loginMaxDelaySeconds = rsp.LoginMaxDelay
|
gLog.Printf(LvINFO, "login ok. user=%s,node=%s", rsp.User, rsp.Node)
|
||||||
}
|
}
|
||||||
gLog.Printf(LvINFO, "login ok. user=%s,node=%s", rsp.User, rsp.Node)
|
case MsgHeartbeat:
|
||||||
}
|
gLog.Printf(LvDev, "P2PNetwork heartbeat ok")
|
||||||
case MsgHeartbeat:
|
pn.hbTime = time.Now()
|
||||||
gLog.Printf(LvDev, "P2PNetwork heartbeat ok")
|
rtt := pn.hbTime.UnixNano() - pn.t1
|
||||||
pn.hbTime = time.Now()
|
if rtt > int64(PunchTsDelay) || (pn.preRtt > 0 && rtt > pn.preRtt*5) {
|
||||||
rtt := pn.hbTime.UnixNano() - pn.t1
|
gLog.Printf(LvINFO, "rtt=%d too large ignore", rtt)
|
||||||
if rtt > int64(PunchTsDelay) || (pn.preRtt > 0 && rtt > pn.preRtt*5) {
|
return // invalid hb rsp
|
||||||
gLog.Printf(LvINFO, "rtt=%d too large ignore", rtt)
|
}
|
||||||
return // invalid hb rsp
|
pn.preRtt = rtt
|
||||||
}
|
t2 := int64(binary.LittleEndian.Uint64(msg[openP2PHeaderSize : openP2PHeaderSize+8]))
|
||||||
pn.preRtt = rtt
|
thisdt := pn.t1 + rtt/2 - t2
|
||||||
t2 := int64(binary.LittleEndian.Uint64(msg[openP2PHeaderSize : openP2PHeaderSize+8]))
|
newdt := thisdt
|
||||||
thisdt := pn.t1 + rtt/2 - t2
|
if pn.dt != 0 {
|
||||||
newdt := thisdt
|
ddt := thisdt - pn.dt
|
||||||
if pn.dt != 0 {
|
pn.ddt = ddt
|
||||||
ddt := thisdt - pn.dt
|
if pn.ddtma == 0 {
|
||||||
pn.ddt = ddt
|
pn.ddtma = pn.ddt
|
||||||
if pn.ddtma == 0 {
|
} else {
|
||||||
pn.ddtma = pn.ddt
|
pn.ddtma = int64(float64(pn.ddtma)*(1-ma10) + float64(pn.ddt)*ma10) // avoid int64 overflow
|
||||||
} else {
|
newdt = pn.dt + pn.ddtma
|
||||||
pn.ddtma = int64(float64(pn.ddtma)*(1-ma10) + float64(pn.ddt)*ma10) // avoid int64 overflow
|
}
|
||||||
newdt = pn.dt + pn.ddtma
|
}
|
||||||
}
|
pn.dt = newdt
|
||||||
}
|
gLog.Printf(LvDEBUG, "synctime thisdt=%dms dt=%dms ddt=%dns ddtma=%dns rtt=%dms ", thisdt/int64(time.Millisecond), pn.dt/int64(time.Millisecond), pn.ddt, pn.ddtma, rtt/int64(time.Millisecond))
|
||||||
pn.dt = newdt
|
case MsgPush:
|
||||||
gLog.Printf(LvDEBUG, "synctime thisdt=%dms dt=%dms ddt=%dns ddtma=%dns rtt=%dms ", thisdt/int64(time.Millisecond), pn.dt/int64(time.Millisecond), pn.ddt, pn.ddtma, rtt/int64(time.Millisecond))
|
handlePush(head.SubType, msg)
|
||||||
case MsgPush:
|
case MsgSDWAN:
|
||||||
handlePush(head.SubType, msg)
|
handleSDWAN(head.SubType, msg)
|
||||||
case MsgSDWAN:
|
default:
|
||||||
handleSDWAN(head.SubType, msg)
|
i, ok := pn.msgMap.Load(uint64(0))
|
||||||
default:
|
if ok {
|
||||||
i, ok := pn.msgMap.Load(uint64(0))
|
ch := i.(chan msgCtx)
|
||||||
if ok {
|
ch <- msgCtx{data: msg, ts: time.Now()}
|
||||||
ch := i.(chan msgCtx)
|
}
|
||||||
ch <- msgCtx{data: msg, ts: time.Now()}
|
|
||||||
}
|
return
|
||||||
|
}
|
||||||
return
|
}
|
||||||
}
|
|
||||||
}
|
func (pn *P2PNetwork) readLoop() {
|
||||||
|
gLog.Printf(LvDEBUG, "P2PNetwork readLoop start")
|
||||||
func (pn *P2PNetwork) readLoop() {
|
pn.wgReconnect.Add(1)
|
||||||
gLog.Printf(LvDEBUG, "P2PNetwork readLoop start")
|
defer pn.wgReconnect.Done()
|
||||||
pn.wgReconnect.Add(1)
|
for pn.running {
|
||||||
defer pn.wgReconnect.Done()
|
pn.conn.SetReadDeadline(time.Now().Add(NetworkHeartbeatTime + 10*time.Second))
|
||||||
for pn.running {
|
_, msg, err := pn.conn.ReadMessage()
|
||||||
pn.conn.SetReadDeadline(time.Now().Add(NetworkHeartbeatTime + 10*time.Second))
|
if err != nil {
|
||||||
_, msg, err := pn.conn.ReadMessage()
|
gLog.Printf(LvERROR, "P2PNetwork read error:%s", err)
|
||||||
if err != nil {
|
pn.close()
|
||||||
gLog.Printf(LvERROR, "P2PNetwork read error:%s", err)
|
break
|
||||||
pn.close()
|
}
|
||||||
break
|
pn.handleMessage(msg)
|
||||||
}
|
}
|
||||||
pn.handleMessage(msg)
|
gLog.Printf(LvDEBUG, "P2PNetwork readLoop end")
|
||||||
}
|
}
|
||||||
gLog.Printf(LvDEBUG, "P2PNetwork readLoop end")
|
|
||||||
}
|
func (pn *P2PNetwork) write(mainType uint16, subType uint16, packet interface{}) error {
|
||||||
|
if !pn.online {
|
||||||
func (pn *P2PNetwork) write(mainType uint16, subType uint16, packet interface{}) error {
|
return errors.New("P2P network offline")
|
||||||
if !pn.online {
|
}
|
||||||
return errors.New("P2P network offline")
|
msg, err := newMessage(mainType, subType, packet)
|
||||||
}
|
if err != nil {
|
||||||
msg, err := newMessage(mainType, subType, packet)
|
return err
|
||||||
if err != nil {
|
}
|
||||||
return err
|
pn.writeMtx.Lock()
|
||||||
}
|
defer pn.writeMtx.Unlock()
|
||||||
pn.writeMtx.Lock()
|
if err = pn.conn.WriteMessage(websocket.BinaryMessage, msg); err != nil {
|
||||||
defer pn.writeMtx.Unlock()
|
gLog.Printf(LvERROR, "write msgType %d,%d error:%s", mainType, subType, err)
|
||||||
if err = pn.conn.WriteMessage(websocket.BinaryMessage, msg); err != nil {
|
pn.close()
|
||||||
gLog.Printf(LvERROR, "write msgType %d,%d error:%s", mainType, subType, err)
|
}
|
||||||
pn.close()
|
return err
|
||||||
}
|
}
|
||||||
return err
|
|
||||||
}
|
func (pn *P2PNetwork) relay(to uint64, body []byte) error {
|
||||||
|
i, ok := pn.allTunnels.Load(to)
|
||||||
func (pn *P2PNetwork) relay(to uint64, body []byte) error {
|
if !ok {
|
||||||
i, ok := pn.allTunnels.Load(to)
|
return ErrRelayTunnelNotFound
|
||||||
if !ok {
|
}
|
||||||
return ErrRelayTunnelNotFound
|
tunnel := i.(*P2PTunnel)
|
||||||
}
|
if tunnel.config.shareBandwidth > 0 {
|
||||||
tunnel := i.(*P2PTunnel)
|
pn.limiter.Add(len(body), true)
|
||||||
if tunnel.config.shareBandwidth > 0 {
|
}
|
||||||
pn.limiter.Add(len(body), true)
|
var err error
|
||||||
}
|
if err = tunnel.conn.WriteBuffer(body); err != nil {
|
||||||
var err error
|
gLog.Printf(LvERROR, "relay to %d len=%d error:%s", to, len(body), err)
|
||||||
if err = tunnel.conn.WriteBuffer(body); err != nil {
|
}
|
||||||
gLog.Printf(LvERROR, "relay to %d len=%d error:%s", to, len(body), err)
|
return err
|
||||||
}
|
}
|
||||||
return err
|
|
||||||
}
|
func (pn *P2PNetwork) push(to string, subType uint16, packet interface{}) error {
|
||||||
|
// gLog.Printf(LvDEBUG, "push msgType %d to %s", subType, to)
|
||||||
func (pn *P2PNetwork) push(to string, subType uint16, packet interface{}) error {
|
if !pn.online {
|
||||||
gLog.Printf(LvDEBUG, "push msgType %d to %s", subType, to)
|
return errors.New("client offline")
|
||||||
if !pn.online {
|
}
|
||||||
return errors.New("client offline")
|
pushHead := PushHeader{}
|
||||||
}
|
pushHead.From = gConf.nodeID()
|
||||||
pushHead := PushHeader{}
|
pushHead.To = NodeNameToID(to)
|
||||||
pushHead.From = gConf.nodeID()
|
pushHeadBuf := new(bytes.Buffer)
|
||||||
pushHead.To = NodeNameToID(to)
|
err := binary.Write(pushHeadBuf, binary.LittleEndian, pushHead)
|
||||||
pushHeadBuf := new(bytes.Buffer)
|
if err != nil {
|
||||||
err := binary.Write(pushHeadBuf, binary.LittleEndian, pushHead)
|
return err
|
||||||
if err != nil {
|
}
|
||||||
return err
|
data, err := json.Marshal(packet)
|
||||||
}
|
if err != nil {
|
||||||
data, err := json.Marshal(packet)
|
return err
|
||||||
if err != nil {
|
}
|
||||||
return err
|
// gLog.Println(LevelINFO,"write packet:", string(data))
|
||||||
}
|
pushMsg := append(encodeHeader(MsgPush, subType, uint32(len(data)+PushHeaderSize)), pushHeadBuf.Bytes()...)
|
||||||
// gLog.Println(LevelINFO,"write packet:", string(data))
|
pushMsg = append(pushMsg, data...)
|
||||||
pushMsg := append(encodeHeader(MsgPush, subType, uint32(len(data)+PushHeaderSize)), pushHeadBuf.Bytes()...)
|
pn.writeMtx.Lock()
|
||||||
pushMsg = append(pushMsg, data...)
|
defer pn.writeMtx.Unlock()
|
||||||
pn.writeMtx.Lock()
|
if err = pn.conn.WriteMessage(websocket.BinaryMessage, pushMsg); err != nil {
|
||||||
defer pn.writeMtx.Unlock()
|
gLog.Printf(LvERROR, "push to %s error:%s", to, err)
|
||||||
if err = pn.conn.WriteMessage(websocket.BinaryMessage, pushMsg); err != nil {
|
pn.close()
|
||||||
gLog.Printf(LvERROR, "push to %s error:%s", to, err)
|
}
|
||||||
pn.close()
|
return err
|
||||||
}
|
}
|
||||||
return err
|
|
||||||
}
|
func (pn *P2PNetwork) close() {
|
||||||
|
if pn.running {
|
||||||
func (pn *P2PNetwork) close() {
|
if pn.conn != nil {
|
||||||
if pn.running {
|
pn.conn.Close()
|
||||||
if pn.conn != nil {
|
}
|
||||||
pn.conn.Close()
|
pn.running = false
|
||||||
}
|
}
|
||||||
pn.running = false
|
select {
|
||||||
}
|
case pn.restartCh <- true:
|
||||||
select {
|
default:
|
||||||
case pn.restartCh <- true:
|
}
|
||||||
default:
|
}
|
||||||
}
|
|
||||||
}
|
func (pn *P2PNetwork) read(node string, mainType uint16, subType uint16, timeout time.Duration) (head *openP2PHeader, body []byte) {
|
||||||
|
var nodeID uint64
|
||||||
func (pn *P2PNetwork) read(node string, mainType uint16, subType uint16, timeout time.Duration) (head *openP2PHeader, body []byte) {
|
if node == "" {
|
||||||
var nodeID uint64
|
nodeID = 0
|
||||||
if node == "" {
|
} else {
|
||||||
nodeID = 0
|
nodeID = NodeNameToID(node)
|
||||||
} else {
|
}
|
||||||
nodeID = NodeNameToID(node)
|
i, ok := pn.msgMap.Load(nodeID)
|
||||||
}
|
if !ok {
|
||||||
i, ok := pn.msgMap.Load(nodeID)
|
gLog.Printf(LvERROR, "read msg error: %s not found", node)
|
||||||
if !ok {
|
return
|
||||||
gLog.Printf(LvERROR, "read msg error: %s not found", node)
|
}
|
||||||
return
|
ch := i.(chan msgCtx)
|
||||||
}
|
for {
|
||||||
ch := i.(chan msgCtx)
|
select {
|
||||||
for {
|
case <-time.After(timeout):
|
||||||
select {
|
gLog.Printf(LvERROR, "read msg error %d:%d timeout", mainType, subType)
|
||||||
case <-time.After(timeout):
|
return
|
||||||
gLog.Printf(LvERROR, "read msg error %d:%d timeout", mainType, subType)
|
case msg := <-ch:
|
||||||
return
|
head = &openP2PHeader{}
|
||||||
case msg := <-ch:
|
err := binary.Read(bytes.NewReader(msg.data[:openP2PHeaderSize]), binary.LittleEndian, head)
|
||||||
head = &openP2PHeader{}
|
if err != nil {
|
||||||
err := binary.Read(bytes.NewReader(msg.data[:openP2PHeaderSize]), binary.LittleEndian, head)
|
gLog.Println(LvERROR, "read msg error:", err)
|
||||||
if err != nil {
|
break
|
||||||
gLog.Println(LvERROR, "read msg error:", err)
|
}
|
||||||
break
|
if time.Since(msg.ts) > ReadMsgTimeout {
|
||||||
}
|
gLog.Printf(LvDEBUG, "read msg error expired %d:%d", head.MainType, head.SubType)
|
||||||
if time.Since(msg.ts) > ReadMsgTimeout {
|
continue
|
||||||
gLog.Printf(LvDEBUG, "read msg error expired %d:%d", head.MainType, head.SubType)
|
}
|
||||||
continue
|
if head.MainType != mainType || head.SubType != subType {
|
||||||
}
|
gLog.Printf(LvDEBUG, "read msg error type %d:%d, requeue it", head.MainType, head.SubType)
|
||||||
if head.MainType != mainType || head.SubType != subType {
|
ch <- msg
|
||||||
gLog.Printf(LvDEBUG, "read msg error type %d:%d, requeue it", head.MainType, head.SubType)
|
time.Sleep(time.Second)
|
||||||
ch <- msg
|
continue
|
||||||
time.Sleep(time.Second)
|
}
|
||||||
continue
|
if mainType == MsgPush {
|
||||||
}
|
body = msg.data[openP2PHeaderSize+PushHeaderSize:]
|
||||||
if mainType == MsgPush {
|
} else {
|
||||||
body = msg.data[openP2PHeaderSize+PushHeaderSize:]
|
body = msg.data[openP2PHeaderSize:]
|
||||||
} else {
|
}
|
||||||
body = msg.data[openP2PHeaderSize:]
|
return
|
||||||
}
|
}
|
||||||
return
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
func (pn *P2PNetwork) updateAppHeartbeat(appID uint64) {
|
||||||
|
pn.apps.Range(func(id, i interface{}) bool {
|
||||||
func (pn *P2PNetwork) updateAppHeartbeat(appID uint64) {
|
app := i.(*p2pApp)
|
||||||
pn.apps.Range(func(id, i interface{}) bool {
|
if app.id == appID {
|
||||||
app := i.(*p2pApp)
|
app.updateHeartbeat()
|
||||||
if app.id == appID {
|
}
|
||||||
app.updateHeartbeat()
|
return true
|
||||||
}
|
})
|
||||||
return true
|
}
|
||||||
})
|
|
||||||
}
|
// ipv6 will expired need to refresh.
|
||||||
|
func (pn *P2PNetwork) refreshIPv6() {
|
||||||
// ipv6 will expired need to refresh.
|
for i := 0; i < 2; i++ {
|
||||||
func (pn *P2PNetwork) refreshIPv6() {
|
client := &http.Client{Timeout: time.Second * 10}
|
||||||
for i := 0; i < 2; i++ {
|
r, err := client.Get("http://ipv6.ddnspod.com/")
|
||||||
client := &http.Client{Timeout: time.Second * 10}
|
if err != nil {
|
||||||
r, err := client.Get("http://ipv6.ddnspod.com/")
|
gLog.Println(LvDEBUG, "refreshIPv6 error:", err)
|
||||||
if err != nil {
|
continue
|
||||||
gLog.Println(LvDEBUG, "refreshIPv6 error:", err)
|
}
|
||||||
continue
|
defer r.Body.Close()
|
||||||
}
|
buf := make([]byte, 1024)
|
||||||
defer r.Body.Close()
|
n, err := r.Body.Read(buf)
|
||||||
buf := make([]byte, 1024)
|
if n <= 0 {
|
||||||
n, err := r.Body.Read(buf)
|
gLog.Println(LvINFO, "refreshIPv6 error:", err, n)
|
||||||
if n <= 0 {
|
continue
|
||||||
gLog.Println(LvINFO, "refreshIPv6 error:", err, n)
|
}
|
||||||
continue
|
if IsIPv6(string(buf[:n])) {
|
||||||
}
|
gConf.setIPv6(string(buf[:n]))
|
||||||
if IsIPv6(string(buf[:n])) {
|
}
|
||||||
gConf.setIPv6(string(buf[:n]))
|
break
|
||||||
}
|
}
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
func (pn *P2PNetwork) requestPeerInfo(config *AppConfig) error {
|
||||||
|
// request peer info
|
||||||
func (pn *P2PNetwork) requestPeerInfo(config *AppConfig) error {
|
// TODO: multi-thread issue
|
||||||
// request peer info
|
pn.reqGatewayMtx.Lock()
|
||||||
// TODO: multi-thread issue
|
pn.write(MsgQuery, MsgQueryPeerInfoReq, &QueryPeerInfoReq{config.peerToken, config.PeerNode})
|
||||||
pn.reqGatewayMtx.Lock()
|
head, body := pn.read("", MsgQuery, MsgQueryPeerInfoRsp, ClientAPITimeout)
|
||||||
pn.write(MsgQuery, MsgQueryPeerInfoReq, &QueryPeerInfoReq{config.peerToken, config.PeerNode})
|
pn.reqGatewayMtx.Unlock()
|
||||||
head, body := pn.read("", MsgQuery, MsgQueryPeerInfoRsp, ClientAPITimeout)
|
if head == nil {
|
||||||
pn.reqGatewayMtx.Unlock()
|
gLog.Println(LvERROR, "requestPeerInfo error")
|
||||||
if head == nil {
|
return ErrNetwork // network error, should not be ErrPeerOffline
|
||||||
gLog.Println(LvERROR, "requestPeerInfo error")
|
}
|
||||||
return ErrNetwork // network error, should not be ErrPeerOffline
|
rsp := QueryPeerInfoRsp{}
|
||||||
}
|
if err := json.Unmarshal(body, &rsp); err != nil {
|
||||||
rsp := QueryPeerInfoRsp{}
|
return ErrMsgFormat
|
||||||
if err := json.Unmarshal(body, &rsp); err != nil {
|
}
|
||||||
return ErrMsgFormat
|
if rsp.Online == 0 {
|
||||||
}
|
return ErrPeerOffline
|
||||||
if rsp.Online == 0 {
|
}
|
||||||
return ErrPeerOffline
|
if compareVersion(rsp.Version, LeastSupportVersion) < 0 {
|
||||||
}
|
return ErrVersionNotCompatible
|
||||||
if compareVersion(rsp.Version, LeastSupportVersion) < 0 {
|
}
|
||||||
return ErrVersionNotCompatible
|
config.peerVersion = rsp.Version
|
||||||
}
|
config.peerLanIP = rsp.LanIP
|
||||||
config.peerVersion = rsp.Version
|
config.hasIPv4 = rsp.HasIPv4
|
||||||
config.peerLanIP = rsp.LanIP
|
config.peerIP = rsp.IPv4
|
||||||
config.hasIPv4 = rsp.HasIPv4
|
config.peerIPv6 = rsp.IPv6
|
||||||
config.peerIP = rsp.IPv4
|
config.hasUPNPorNATPMP = rsp.HasUPNPorNATPMP
|
||||||
config.peerIPv6 = rsp.IPv6
|
config.peerNatType = rsp.NatType
|
||||||
config.hasUPNPorNATPMP = rsp.HasUPNPorNATPMP
|
///
|
||||||
config.peerNatType = rsp.NatType
|
return nil
|
||||||
///
|
}
|
||||||
return nil
|
|
||||||
}
|
func (pn *P2PNetwork) StartSDWAN() {
|
||||||
|
// request peer info
|
||||||
func (pn *P2PNetwork) StartSDWAN() {
|
pn.sdwan = &p2pSDWAN{}
|
||||||
// request peer info
|
}
|
||||||
pn.sdwan = &p2pSDWAN{}
|
|
||||||
}
|
func (pn *P2PNetwork) ConnectNode(node string) error {
|
||||||
|
if gConf.nodeID() < NodeNameToID(node) {
|
||||||
func (pn *P2PNetwork) ConnectNode(node string) error {
|
return errors.New("only the bigger nodeid connect")
|
||||||
if gConf.nodeID() < NodeNameToID(node) {
|
}
|
||||||
return errors.New("only the bigger nodeid connect")
|
peerNodeID := fmt.Sprintf("%d", NodeNameToID(node))
|
||||||
}
|
config := AppConfig{Enabled: 1}
|
||||||
peerNodeID := fmt.Sprintf("%d", NodeNameToID(node))
|
config.AppName = peerNodeID
|
||||||
config := AppConfig{Enabled: 1}
|
config.SrcPort = 0
|
||||||
config.AppName = peerNodeID
|
config.PeerNode = node
|
||||||
config.SrcPort = 0
|
sdwan := gConf.getSDWAN()
|
||||||
config.PeerNode = node
|
config.PunchPriority = int(sdwan.PunchPriority)
|
||||||
sdwan := gConf.getSDWAN()
|
if node != sdwan.CentralNode && gConf.Network.Node != sdwan.CentralNode { // neither is centralnode
|
||||||
config.PunchPriority = int(sdwan.PunchPriority)
|
config.RelayNode = sdwan.CentralNode
|
||||||
if node != sdwan.CentralNode && gConf.Network.Node != sdwan.CentralNode { // neither is centralnode
|
config.ForceRelay = int(sdwan.ForceRelay)
|
||||||
config.RelayNode = sdwan.CentralNode
|
if sdwan.Mode == SDWANModeCentral {
|
||||||
config.ForceRelay = int(sdwan.ForceRelay)
|
config.ForceRelay = 1
|
||||||
if sdwan.Mode == SDWANModeCentral {
|
}
|
||||||
config.ForceRelay = 1
|
}
|
||||||
}
|
|
||||||
}
|
gConf.add(config, true)
|
||||||
|
return nil
|
||||||
gConf.add(config, true)
|
}
|
||||||
return nil
|
|
||||||
}
|
func (pn *P2PNetwork) WriteNode(nodeID uint64, buff []byte) error {
|
||||||
|
i, ok := pn.apps.Load(nodeID)
|
||||||
func (pn *P2PNetwork) WriteNode(nodeID uint64, buff []byte) error {
|
if !ok {
|
||||||
i, ok := pn.apps.Load(nodeID)
|
return errors.New("peer not found")
|
||||||
if !ok {
|
}
|
||||||
return errors.New("peer not found")
|
var err error
|
||||||
}
|
app := i.(*p2pApp)
|
||||||
var err error
|
if app.Tunnel() == nil {
|
||||||
app := i.(*p2pApp)
|
return errors.New("peer tunnel nil")
|
||||||
if app.Tunnel() == nil {
|
}
|
||||||
return errors.New("peer tunnel nil")
|
// TODO: move to app.write
|
||||||
}
|
gLog.Printf(LvDev, "%d tunnel write node data bodylen=%d, relay=%t", app.Tunnel().id, len(buff), !app.isDirect())
|
||||||
// TODO: move to app.write
|
if app.isDirect() { // direct
|
||||||
gLog.Printf(LvDev, "%d tunnel write node data bodylen=%d, relay=%t", app.Tunnel().id, len(buff), !app.isDirect())
|
app.Tunnel().asyncWriteNodeData(MsgP2P, MsgNodeData, buff)
|
||||||
if app.isDirect() { // direct
|
} else { // relay
|
||||||
app.Tunnel().asyncWriteNodeData(MsgP2P, MsgNodeData, buff)
|
fromNodeIDHead := new(bytes.Buffer)
|
||||||
} else { // relay
|
binary.Write(fromNodeIDHead, binary.LittleEndian, gConf.nodeID())
|
||||||
fromNodeIDHead := new(bytes.Buffer)
|
all := app.RelayHead().Bytes()
|
||||||
binary.Write(fromNodeIDHead, binary.LittleEndian, gConf.nodeID())
|
all = append(all, encodeHeader(MsgP2P, MsgRelayNodeData, uint32(len(buff)+overlayHeaderSize))...)
|
||||||
all := app.RelayHead().Bytes()
|
all = append(all, fromNodeIDHead.Bytes()...)
|
||||||
all = append(all, encodeHeader(MsgP2P, MsgRelayNodeData, uint32(len(buff)+overlayHeaderSize))...)
|
all = append(all, buff...)
|
||||||
all = append(all, fromNodeIDHead.Bytes()...)
|
app.Tunnel().asyncWriteNodeData(MsgP2P, MsgRelayData, all)
|
||||||
all = append(all, buff...)
|
}
|
||||||
app.Tunnel().asyncWriteNodeData(MsgP2P, MsgRelayData, all)
|
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
return err
|
|
||||||
}
|
func (pn *P2PNetwork) WriteBroadcast(buff []byte) error {
|
||||||
|
///
|
||||||
func (pn *P2PNetwork) WriteBroadcast(buff []byte) error {
|
pn.apps.Range(func(id, i interface{}) bool {
|
||||||
///
|
// newDestIP := net.ParseIP("10.2.3.2")
|
||||||
pn.apps.Range(func(id, i interface{}) bool {
|
// copy(buff[16:20], newDestIP.To4())
|
||||||
// newDestIP := net.ParseIP("10.2.3.2")
|
// binary.BigEndian.PutUint16(buff[10:12], 0) // set checksum=0 for calc checksum
|
||||||
// copy(buff[16:20], newDestIP.To4())
|
// ipChecksum := calculateChecksum(buff[0:20])
|
||||||
// binary.BigEndian.PutUint16(buff[10:12], 0) // set checksum=0 for calc checksum
|
// binary.BigEndian.PutUint16(buff[10:12], ipChecksum)
|
||||||
// ipChecksum := calculateChecksum(buff[0:20])
|
// binary.BigEndian.PutUint16(buff[26:28], 0x082e)
|
||||||
// binary.BigEndian.PutUint16(buff[10:12], ipChecksum)
|
app := i.(*p2pApp)
|
||||||
// binary.BigEndian.PutUint16(buff[26:28], 0x082e)
|
if app.Tunnel() == nil {
|
||||||
app := i.(*p2pApp)
|
return true
|
||||||
if app.Tunnel() == nil {
|
}
|
||||||
return true
|
if app.config.SrcPort != 0 { // normal portmap app
|
||||||
}
|
return true
|
||||||
if app.config.SrcPort != 0 { // normal portmap app
|
}
|
||||||
return true
|
if app.config.peerIP == gConf.Network.publicIP { // mostly in a lan
|
||||||
}
|
return true
|
||||||
if app.config.peerIP == gConf.Network.publicIP { // mostly in a lan
|
}
|
||||||
return true
|
if app.isDirect() { // direct
|
||||||
}
|
app.Tunnel().conn.WriteBytes(MsgP2P, MsgNodeData, buff)
|
||||||
if app.isDirect() { // direct
|
} else { // relay
|
||||||
app.Tunnel().conn.WriteBytes(MsgP2P, MsgNodeData, buff)
|
fromNodeIDHead := new(bytes.Buffer)
|
||||||
} else { // relay
|
binary.Write(fromNodeIDHead, binary.LittleEndian, gConf.nodeID())
|
||||||
fromNodeIDHead := new(bytes.Buffer)
|
all := app.RelayHead().Bytes()
|
||||||
binary.Write(fromNodeIDHead, binary.LittleEndian, gConf.nodeID())
|
all = append(all, encodeHeader(MsgP2P, MsgRelayNodeData, uint32(len(buff)+overlayHeaderSize))...)
|
||||||
all := app.RelayHead().Bytes()
|
all = append(all, fromNodeIDHead.Bytes()...)
|
||||||
all = append(all, encodeHeader(MsgP2P, MsgRelayNodeData, uint32(len(buff)+overlayHeaderSize))...)
|
all = append(all, buff...)
|
||||||
all = append(all, fromNodeIDHead.Bytes()...)
|
app.Tunnel().conn.WriteBytes(MsgP2P, MsgRelayData, all)
|
||||||
all = append(all, buff...)
|
}
|
||||||
app.Tunnel().conn.WriteBytes(MsgP2P, MsgRelayData, all)
|
return true
|
||||||
}
|
})
|
||||||
return true
|
return nil
|
||||||
})
|
}
|
||||||
return nil
|
|
||||||
}
|
func (pn *P2PNetwork) ReadNode(tm time.Duration) *NodeData {
|
||||||
|
select {
|
||||||
func (pn *P2PNetwork) ReadNode(tm time.Duration) *NodeData {
|
case nd := <-pn.nodeData:
|
||||||
select {
|
return nd
|
||||||
case nd := <-pn.nodeData:
|
case <-time.After(tm):
|
||||||
return nd
|
}
|
||||||
case <-time.After(tm):
|
return nil
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
+806
-806
@@ -1,806 +1,806 @@
|
|||||||
package openp2p
|
package openp2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const WriteDataChanSize int = 3000
|
const WriteDataChanSize int = 3000
|
||||||
|
|
||||||
var buildTunnelMtx sync.Mutex
|
var buildTunnelMtx sync.Mutex
|
||||||
|
|
||||||
type P2PTunnel struct {
|
type P2PTunnel struct {
|
||||||
pn *P2PNetwork
|
pn *P2PNetwork
|
||||||
conn underlay
|
conn underlay
|
||||||
hbTime time.Time
|
hbTime time.Time
|
||||||
hbMtx sync.Mutex
|
hbMtx sync.Mutex
|
||||||
config AppConfig
|
config AppConfig
|
||||||
la *net.UDPAddr // local hole address
|
la *net.UDPAddr // local hole address
|
||||||
ra *net.UDPAddr // remote hole address
|
ra *net.UDPAddr // remote hole address
|
||||||
overlayConns sync.Map // both TCP and UDP
|
overlayConns sync.Map // both TCP and UDP
|
||||||
id uint64 // client side alloc rand.uint64 = server side
|
id uint64 // client side alloc rand.uint64 = server side
|
||||||
running bool
|
running bool
|
||||||
runMtx sync.Mutex
|
runMtx sync.Mutex
|
||||||
tunnelServer bool // different from underlayServer
|
tunnelServer bool // different from underlayServer
|
||||||
coneLocalPort int
|
coneLocalPort int
|
||||||
coneNatPort int
|
coneNatPort int
|
||||||
linkModeWeb string // use config.linkmode
|
linkModeWeb string // use config.linkmode
|
||||||
punchTs uint64
|
punchTs uint64
|
||||||
writeData chan []byte
|
writeData chan []byte
|
||||||
writeDataSmall chan []byte
|
writeDataSmall chan []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) initPort() {
|
func (t *P2PTunnel) initPort() {
|
||||||
t.running = true
|
t.running = true
|
||||||
localPort := int(rand.Uint32()%15000 + 50000) // if the process has bug, will add many upnp port. use specify p2p port by param
|
localPort := int(rand.Uint32()%15000 + 50000) // if the process has bug, will add many upnp port. use specify p2p port by param
|
||||||
if t.config.linkMode == LinkModeTCP6 || t.config.linkMode == LinkModeTCP4 || t.config.linkMode == LinkModeIntranet {
|
if t.config.linkMode == LinkModeTCP6 || t.config.linkMode == LinkModeTCP4 || t.config.linkMode == LinkModeIntranet {
|
||||||
t.coneLocalPort = gConf.Network.TCPPort
|
t.coneLocalPort = gConf.Network.TCPPort
|
||||||
t.coneNatPort = gConf.Network.TCPPort // symmetric doesn't need coneNatPort
|
t.coneNatPort = gConf.Network.TCPPort // symmetric doesn't need coneNatPort
|
||||||
}
|
}
|
||||||
if t.config.linkMode == LinkModeUDPPunch {
|
if t.config.linkMode == LinkModeUDPPunch {
|
||||||
// prepare one random cone hole manually
|
// prepare one random cone hole manually
|
||||||
_, natPort, _ := natTest(gConf.Network.ServerHost, gConf.Network.UDPPort1, localPort)
|
_, natPort, _ := natTest(gConf.Network.ServerHost, gConf.Network.UDPPort1, localPort)
|
||||||
t.coneLocalPort = localPort
|
t.coneLocalPort = localPort
|
||||||
t.coneNatPort = natPort
|
t.coneNatPort = natPort
|
||||||
}
|
}
|
||||||
if t.config.linkMode == LinkModeTCPPunch {
|
if t.config.linkMode == LinkModeTCPPunch {
|
||||||
// prepare one random cone hole by system automatically
|
// prepare one random cone hole by system automatically
|
||||||
_, natPort, localPort2 := natTCP(gConf.Network.ServerHost, IfconfigPort1)
|
_, natPort, localPort2 := natTCP(gConf.Network.ServerHost, IfconfigPort1)
|
||||||
t.coneLocalPort = localPort2
|
t.coneLocalPort = localPort2
|
||||||
t.coneNatPort = natPort
|
t.coneNatPort = natPort
|
||||||
}
|
}
|
||||||
t.la = &net.UDPAddr{IP: net.ParseIP(gConf.Network.localIP), Port: t.coneLocalPort}
|
t.la = &net.UDPAddr{IP: net.ParseIP(gConf.Network.localIP), Port: t.coneLocalPort}
|
||||||
gLog.Printf(LvDEBUG, "prepare punching port %d:%d", t.coneLocalPort, t.coneNatPort)
|
gLog.Printf(LvDEBUG, "prepare punching port %d:%d", t.coneLocalPort, t.coneNatPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) connect() error {
|
func (t *P2PTunnel) connect() error {
|
||||||
gLog.Printf(LvDEBUG, "start p2pTunnel to %s ", t.config.PeerNode)
|
gLog.Printf(LvDEBUG, "start p2pTunnel to %s ", t.config.LogPeerNode())
|
||||||
t.tunnelServer = false
|
t.tunnelServer = false
|
||||||
appKey := uint64(0)
|
appKey := uint64(0)
|
||||||
req := PushConnectReq{
|
req := PushConnectReq{
|
||||||
Token: t.config.peerToken,
|
Token: t.config.peerToken,
|
||||||
From: gConf.Network.Node,
|
From: gConf.Network.Node,
|
||||||
FromIP: gConf.Network.publicIP,
|
FromIP: gConf.Network.publicIP,
|
||||||
ConeNatPort: t.coneNatPort,
|
ConeNatPort: t.coneNatPort,
|
||||||
NatType: gConf.Network.natType,
|
NatType: gConf.Network.natType,
|
||||||
HasIPv4: gConf.Network.hasIPv4,
|
HasIPv4: gConf.Network.hasIPv4,
|
||||||
IPv6: gConf.IPv6(),
|
IPv6: gConf.IPv6(),
|
||||||
HasUPNPorNATPMP: gConf.Network.hasUPNPorNATPMP,
|
HasUPNPorNATPMP: gConf.Network.hasUPNPorNATPMP,
|
||||||
ID: t.id,
|
ID: t.id,
|
||||||
AppKey: appKey,
|
AppKey: appKey,
|
||||||
Version: OpenP2PVersion,
|
Version: OpenP2PVersion,
|
||||||
LinkMode: t.config.linkMode,
|
LinkMode: t.config.linkMode,
|
||||||
IsUnderlayServer: t.config.isUnderlayServer ^ 1, // peer
|
IsUnderlayServer: t.config.isUnderlayServer ^ 1, // peer
|
||||||
UnderlayProtocol: t.config.UnderlayProtocol,
|
UnderlayProtocol: t.config.UnderlayProtocol,
|
||||||
}
|
}
|
||||||
if req.Token == 0 { // no relay token
|
if req.Token == 0 { // no relay token
|
||||||
req.Token = gConf.Network.Token
|
req.Token = gConf.Network.Token
|
||||||
}
|
}
|
||||||
t.pn.push(t.config.PeerNode, MsgPushConnectReq, req)
|
t.pn.push(t.config.PeerNode, MsgPushConnectReq, req)
|
||||||
head, body := t.pn.read(t.config.PeerNode, MsgPush, MsgPushConnectRsp, UnderlayConnectTimeout*3)
|
head, body := t.pn.read(t.config.PeerNode, MsgPush, MsgPushConnectRsp, UnderlayConnectTimeout*3)
|
||||||
if head == nil {
|
if head == nil {
|
||||||
return errors.New("connect error")
|
return errors.New("connect error")
|
||||||
}
|
}
|
||||||
rsp := PushConnectRsp{}
|
rsp := PushConnectRsp{}
|
||||||
if err := json.Unmarshal(body, &rsp); err != nil {
|
if err := json.Unmarshal(body, &rsp); err != nil {
|
||||||
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(rsp), err)
|
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(rsp), err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// gLog.Println(LevelINFO, rsp)
|
// gLog.Println(LevelINFO, rsp)
|
||||||
if rsp.Error != 0 {
|
if rsp.Error != 0 {
|
||||||
return errors.New(rsp.Detail)
|
return errors.New(rsp.Detail)
|
||||||
}
|
}
|
||||||
t.config.peerNatType = rsp.NatType
|
t.config.peerNatType = rsp.NatType
|
||||||
t.config.hasIPv4 = rsp.HasIPv4
|
t.config.hasIPv4 = rsp.HasIPv4
|
||||||
t.config.peerIPv6 = rsp.IPv6
|
t.config.peerIPv6 = rsp.IPv6
|
||||||
t.config.hasUPNPorNATPMP = rsp.HasUPNPorNATPMP
|
t.config.hasUPNPorNATPMP = rsp.HasUPNPorNATPMP
|
||||||
t.config.peerVersion = rsp.Version
|
t.config.peerVersion = rsp.Version
|
||||||
t.config.peerConeNatPort = rsp.ConeNatPort
|
t.config.peerConeNatPort = rsp.ConeNatPort
|
||||||
t.config.peerIP = rsp.FromIP
|
t.config.peerIP = rsp.FromIP
|
||||||
t.punchTs = rsp.PunchTs
|
t.punchTs = rsp.PunchTs
|
||||||
err := t.start()
|
err := t.start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "handshake error:", err)
|
gLog.Println(LvERROR, "handshake error:", err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) isRuning() bool {
|
func (t *P2PTunnel) isRuning() bool {
|
||||||
t.runMtx.Lock()
|
t.runMtx.Lock()
|
||||||
defer t.runMtx.Unlock()
|
defer t.runMtx.Unlock()
|
||||||
return t.running
|
return t.running
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) setRun(running bool) {
|
func (t *P2PTunnel) setRun(running bool) {
|
||||||
t.runMtx.Lock()
|
t.runMtx.Lock()
|
||||||
defer t.runMtx.Unlock()
|
defer t.runMtx.Unlock()
|
||||||
t.running = running
|
t.running = running
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) isActive() bool {
|
func (t *P2PTunnel) isActive() bool {
|
||||||
if !t.isRuning() || t.conn == nil {
|
if !t.isRuning() || t.conn == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
t.hbMtx.Lock()
|
t.hbMtx.Lock()
|
||||||
defer t.hbMtx.Unlock()
|
defer t.hbMtx.Unlock()
|
||||||
res := time.Now().Before(t.hbTime.Add(TunnelHeartbeatTime * 2))
|
res := time.Now().Before(t.hbTime.Add(TunnelHeartbeatTime * 2))
|
||||||
if !res {
|
if !res {
|
||||||
gLog.Printf(LvDEBUG, "%d tunnel isActive false", t.id)
|
gLog.Printf(LvDEBUG, "%d tunnel isActive false", t.id)
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) checkActive() bool {
|
func (t *P2PTunnel) checkActive() bool {
|
||||||
if !t.isActive() {
|
if !t.isActive() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
hbt := time.Now()
|
hbt := time.Now()
|
||||||
t.conn.WriteBytes(MsgP2P, MsgTunnelHeartbeat, nil)
|
t.conn.WriteBytes(MsgP2P, MsgTunnelHeartbeat, nil)
|
||||||
isActive := false
|
isActive := false
|
||||||
// wait at most 5s
|
// wait at most 5s
|
||||||
for i := 0; i < 50 && !isActive; i++ {
|
for i := 0; i < 50 && !isActive; i++ {
|
||||||
t.hbMtx.Lock()
|
t.hbMtx.Lock()
|
||||||
if t.hbTime.After(hbt) {
|
if t.hbTime.After(hbt) {
|
||||||
isActive = true
|
isActive = true
|
||||||
}
|
}
|
||||||
t.hbMtx.Unlock()
|
t.hbMtx.Unlock()
|
||||||
time.Sleep(time.Millisecond * 100)
|
time.Sleep(time.Millisecond * 100)
|
||||||
}
|
}
|
||||||
gLog.Printf(LvINFO, "checkActive %t. hbtime=%d", isActive, t.hbTime)
|
gLog.Printf(LvINFO, "checkActive %t. hbtime=%d", isActive, t.hbTime)
|
||||||
return isActive
|
return isActive
|
||||||
}
|
}
|
||||||
|
|
||||||
// call when user delete tunnel
|
// call when user delete tunnel
|
||||||
func (t *P2PTunnel) close() {
|
func (t *P2PTunnel) close() {
|
||||||
t.pn.NotifyTunnelClose(t)
|
t.pn.NotifyTunnelClose(t)
|
||||||
if !t.running {
|
if !t.running {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t.setRun(false)
|
t.setRun(false)
|
||||||
if t.conn != nil {
|
if t.conn != nil {
|
||||||
t.conn.Close()
|
t.conn.Close()
|
||||||
}
|
}
|
||||||
t.pn.allTunnels.Delete(t.id)
|
t.pn.allTunnels.Delete(t.id)
|
||||||
gLog.Printf(LvINFO, "%d p2ptunnel close %s ", t.id, t.config.PeerNode)
|
gLog.Printf(LvINFO, "%d p2ptunnel close %s ", t.id, t.config.LogPeerNode())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) start() error {
|
func (t *P2PTunnel) start() error {
|
||||||
if t.config.linkMode == LinkModeUDPPunch {
|
if t.config.linkMode == LinkModeUDPPunch {
|
||||||
if err := t.handshake(); err != nil {
|
if err := t.handshake(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err := t.connectUnderlay()
|
err := t.connectUnderlay()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, err)
|
gLog.Println(LvERROR, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) handshake() error {
|
func (t *P2PTunnel) handshake() error {
|
||||||
if t.config.peerConeNatPort > 0 { // only peer is cone should prepare t.ra
|
if t.config.peerConeNatPort > 0 { // only peer is cone should prepare t.ra
|
||||||
var err error
|
var err error
|
||||||
t.ra, err = net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", t.config.peerIP, t.config.peerConeNatPort))
|
t.ra, err = net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", t.config.peerIP, t.config.peerConeNatPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if compareVersion(t.config.peerVersion, SyncServerTimeVersion) < 0 {
|
if compareVersion(t.config.peerVersion, SyncServerTimeVersion) < 0 {
|
||||||
gLog.Printf(LvDEBUG, "peer version %s less than %s", t.config.peerVersion, SyncServerTimeVersion)
|
gLog.Printf(LvDEBUG, "peer version %s less than %s", t.config.peerVersion, SyncServerTimeVersion)
|
||||||
} else {
|
} else {
|
||||||
ts := time.Duration(int64(t.punchTs) + t.pn.dt + t.pn.ddtma*int64(time.Since(t.pn.hbTime)+PunchTsDelay)/int64(NetworkHeartbeatTime) - time.Now().UnixNano())
|
ts := time.Duration(int64(t.punchTs) + t.pn.dt + t.pn.ddtma*int64(time.Since(t.pn.hbTime)+PunchTsDelay)/int64(NetworkHeartbeatTime) - time.Now().UnixNano())
|
||||||
if ts > PunchTsDelay || ts < 0 {
|
if ts > PunchTsDelay || ts < 0 {
|
||||||
ts = PunchTsDelay
|
ts = PunchTsDelay
|
||||||
}
|
}
|
||||||
gLog.Printf(LvDEBUG, "sleep %d ms", ts/time.Millisecond)
|
gLog.Printf(LvDEBUG, "sleep %d ms", ts/time.Millisecond)
|
||||||
time.Sleep(ts)
|
time.Sleep(ts)
|
||||||
}
|
}
|
||||||
gLog.Println(LvDEBUG, "handshake to ", t.config.PeerNode)
|
gLog.Println(LvDEBUG, "handshake to ", t.config.LogPeerNode())
|
||||||
var err error
|
var err error
|
||||||
if gConf.Network.natType == NATCone && t.config.peerNatType == NATCone {
|
if gConf.Network.natType == NATCone && t.config.peerNatType == NATCone {
|
||||||
err = handshakeC2C(t)
|
err = handshakeC2C(t)
|
||||||
} else if t.config.peerNatType == NATSymmetric && gConf.Network.natType == NATSymmetric {
|
} else if t.config.peerNatType == NATSymmetric && gConf.Network.natType == NATSymmetric {
|
||||||
err = ErrorS2S
|
err = ErrorS2S
|
||||||
t.close()
|
t.close()
|
||||||
} else if t.config.peerNatType == NATSymmetric && gConf.Network.natType == NATCone {
|
} else if t.config.peerNatType == NATSymmetric && gConf.Network.natType == NATCone {
|
||||||
err = handshakeC2S(t)
|
err = handshakeC2S(t)
|
||||||
} else if t.config.peerNatType == NATCone && gConf.Network.natType == NATSymmetric {
|
} else if t.config.peerNatType == NATCone && gConf.Network.natType == NATSymmetric {
|
||||||
err = handshakeS2C(t)
|
err = handshakeS2C(t)
|
||||||
} else {
|
} else {
|
||||||
return errors.New("unknown error")
|
return errors.New("unknown error")
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "punch handshake error:", err)
|
gLog.Println(LvERROR, "punch handshake error:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
gLog.Printf(LvDEBUG, "handshake to %s ok", t.config.PeerNode)
|
gLog.Printf(LvDEBUG, "handshake to %s ok", t.config.LogPeerNode())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) connectUnderlay() (err error) {
|
func (t *P2PTunnel) connectUnderlay() (err error) {
|
||||||
switch t.config.linkMode {
|
switch t.config.linkMode {
|
||||||
case LinkModeTCP6:
|
case LinkModeTCP6:
|
||||||
t.conn, err = t.connectUnderlayTCP6()
|
t.conn, err = t.connectUnderlayTCP6()
|
||||||
case LinkModeTCP4:
|
case LinkModeTCP4:
|
||||||
t.conn, err = t.connectUnderlayTCP()
|
t.conn, err = t.connectUnderlayTCP()
|
||||||
case LinkModeTCPPunch:
|
case LinkModeTCPPunch:
|
||||||
if gConf.Network.natType == NATSymmetric || t.config.peerNatType == NATSymmetric {
|
if gConf.Network.natType == NATSymmetric || t.config.peerNatType == NATSymmetric {
|
||||||
t.conn, err = t.connectUnderlayTCPSymmetric()
|
t.conn, err = t.connectUnderlayTCPSymmetric()
|
||||||
} else {
|
} else {
|
||||||
t.conn, err = t.connectUnderlayTCP()
|
t.conn, err = t.connectUnderlayTCP()
|
||||||
}
|
}
|
||||||
case LinkModeIntranet:
|
case LinkModeIntranet:
|
||||||
t.conn, err = t.connectUnderlayTCP()
|
t.conn, err = t.connectUnderlayTCP()
|
||||||
case LinkModeUDPPunch:
|
case LinkModeUDPPunch:
|
||||||
t.conn, err = t.connectUnderlayUDP()
|
t.conn, err = t.connectUnderlayUDP()
|
||||||
|
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if t.conn == nil {
|
if t.conn == nil {
|
||||||
return errors.New("connect underlay error")
|
return errors.New("connect underlay error")
|
||||||
}
|
}
|
||||||
t.setRun(true)
|
t.setRun(true)
|
||||||
go t.readLoop()
|
go t.readLoop()
|
||||||
go t.writeLoop()
|
go t.writeLoop()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) connectUnderlayUDP() (c underlay, err error) {
|
func (t *P2PTunnel) connectUnderlayUDP() (c underlay, err error) {
|
||||||
gLog.Printf(LvDEBUG, "connectUnderlayUDP %s start ", t.config.PeerNode)
|
gLog.Printf(LvDEBUG, "connectUnderlayUDP %s start ", t.config.LogPeerNode())
|
||||||
defer gLog.Printf(LvDEBUG, "connectUnderlayUDP %s end ", t.config.PeerNode)
|
defer gLog.Printf(LvDEBUG, "connectUnderlayUDP %s end ", t.config.LogPeerNode())
|
||||||
var ul underlay
|
var ul underlay
|
||||||
underlayProtocol := t.config.UnderlayProtocol
|
underlayProtocol := t.config.UnderlayProtocol
|
||||||
if underlayProtocol == "" {
|
if underlayProtocol == "" {
|
||||||
underlayProtocol = "quic"
|
underlayProtocol = "quic"
|
||||||
}
|
}
|
||||||
if t.config.isUnderlayServer == 1 {
|
if t.config.isUnderlayServer == 1 {
|
||||||
time.Sleep(time.Millisecond * 10) // punching udp port will need some times in some env
|
time.Sleep(time.Millisecond * 10) // punching udp port will need some times in some env
|
||||||
go t.pn.push(t.config.PeerNode, MsgPushUnderlayConnect, nil)
|
go t.pn.push(t.config.PeerNode, MsgPushUnderlayConnect, nil)
|
||||||
if t.config.UnderlayProtocol == "kcp" {
|
if t.config.UnderlayProtocol == "kcp" {
|
||||||
ul, err = listenKCP(t.la.String(), TunnelIdleTimeout)
|
ul, err = listenKCP(t.la.String(), TunnelIdleTimeout)
|
||||||
} else {
|
} else {
|
||||||
ul, err = listenQuic(t.la.String(), TunnelIdleTimeout)
|
ul, err = listenQuic(t.la.String(), TunnelIdleTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvINFO, "listen %s error:%s", underlayProtocol, err)
|
gLog.Printf(LvINFO, "listen %s error:%s", underlayProtocol, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, buff, err := ul.ReadBuffer()
|
_, buff, err := ul.ReadBuffer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ul.Close()
|
ul.Close()
|
||||||
return nil, fmt.Errorf("read start msg error:%s", err)
|
return nil, fmt.Errorf("read start msg error:%s", err)
|
||||||
}
|
}
|
||||||
if buff != nil {
|
if buff != nil {
|
||||||
gLog.Println(LvDEBUG, string(buff))
|
gLog.Println(LvDEBUG, string(buff))
|
||||||
}
|
}
|
||||||
ul.WriteBytes(MsgP2P, MsgTunnelHandshakeAck, []byte("OpenP2P,hello2"))
|
ul.WriteBytes(MsgP2P, MsgTunnelHandshakeAck, []byte("OpenP2P,hello2"))
|
||||||
gLog.Printf(LvDEBUG, "%s connection ok", underlayProtocol)
|
gLog.Printf(LvDEBUG, "%s connection ok", underlayProtocol)
|
||||||
return ul, nil
|
return ul, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//else
|
//else
|
||||||
conn, errL := net.ListenUDP("udp", t.la)
|
conn, errL := net.ListenUDP("udp", t.la)
|
||||||
if errL != nil {
|
if errL != nil {
|
||||||
time.Sleep(time.Millisecond * 10)
|
time.Sleep(time.Millisecond * 10)
|
||||||
conn, errL = net.ListenUDP("udp", t.la)
|
conn, errL = net.ListenUDP("udp", t.la)
|
||||||
if errL != nil {
|
if errL != nil {
|
||||||
return nil, fmt.Errorf("%s listen error:%s", underlayProtocol, errL)
|
return nil, fmt.Errorf("%s listen error:%s", underlayProtocol, errL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.pn.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, ReadMsgTimeout)
|
t.pn.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, ReadMsgTimeout)
|
||||||
gLog.Printf(LvDEBUG, "%s dial to %s", underlayProtocol, t.ra.String())
|
gLog.Printf(LvDEBUG, "%s dial to %s", underlayProtocol, t.ra.String())
|
||||||
if t.config.UnderlayProtocol == "kcp" {
|
if t.config.UnderlayProtocol == "kcp" {
|
||||||
ul, errL = dialKCP(conn, t.ra, TunnelIdleTimeout)
|
ul, errL = dialKCP(conn, t.ra, TunnelIdleTimeout)
|
||||||
} else {
|
} else {
|
||||||
ul, errL = dialQuic(conn, t.ra, TunnelIdleTimeout)
|
ul, errL = dialQuic(conn, t.ra, TunnelIdleTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
if errL != nil {
|
if errL != nil {
|
||||||
return nil, fmt.Errorf("%s dial to %s error:%s", underlayProtocol, t.ra.String(), errL)
|
return nil, fmt.Errorf("%s dial to %s error:%s", underlayProtocol, t.ra.String(), errL)
|
||||||
}
|
}
|
||||||
handshakeBegin := time.Now()
|
handshakeBegin := time.Now()
|
||||||
ul.WriteBytes(MsgP2P, MsgTunnelHandshake, []byte("OpenP2P,hello"))
|
ul.WriteBytes(MsgP2P, MsgTunnelHandshake, []byte("OpenP2P,hello"))
|
||||||
_, buff, err := ul.ReadBuffer() // TODO: kcp need timeout
|
_, buff, err := ul.ReadBuffer() // TODO: kcp need timeout
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ul.Close()
|
ul.Close()
|
||||||
return nil, fmt.Errorf("read MsgTunnelHandshake error:%s", err)
|
return nil, fmt.Errorf("read MsgTunnelHandshake error:%s", err)
|
||||||
}
|
}
|
||||||
if buff != nil {
|
if buff != nil {
|
||||||
gLog.Println(LvDEBUG, string(buff))
|
gLog.Println(LvDEBUG, string(buff))
|
||||||
}
|
}
|
||||||
|
|
||||||
gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin))
|
gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin))
|
||||||
gLog.Printf(LvINFO, "%s connection ok", underlayProtocol)
|
gLog.Printf(LvINFO, "%s connection ok", underlayProtocol)
|
||||||
t.linkModeWeb = LinkModeUDPPunch
|
t.linkModeWeb = LinkModeUDPPunch
|
||||||
return ul, nil
|
return ul, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) connectUnderlayTCP() (c underlay, err error) {
|
func (t *P2PTunnel) connectUnderlayTCP() (c underlay, err error) {
|
||||||
gLog.Printf(LvDEBUG, "connectUnderlayTCP %s start ", t.config.PeerNode)
|
gLog.Printf(LvDEBUG, "connectUnderlayTCP %s start ", t.config.LogPeerNode())
|
||||||
defer gLog.Printf(LvDEBUG, "connectUnderlayTCP %s end ", t.config.PeerNode)
|
defer gLog.Printf(LvDEBUG, "connectUnderlayTCP %s end ", t.config.LogPeerNode())
|
||||||
var ul *underlayTCP
|
var ul *underlayTCP
|
||||||
peerIP := t.config.peerIP
|
peerIP := t.config.peerIP
|
||||||
if t.config.linkMode == LinkModeIntranet {
|
if t.config.linkMode == LinkModeIntranet {
|
||||||
peerIP = t.config.peerLanIP
|
peerIP = t.config.peerLanIP
|
||||||
}
|
}
|
||||||
// server side
|
// server side
|
||||||
if t.config.isUnderlayServer == 1 {
|
if t.config.isUnderlayServer == 1 {
|
||||||
ul, err = listenTCP(peerIP, t.config.peerConeNatPort, t.coneLocalPort, t.config.linkMode, t)
|
ul, err = listenTCP(peerIP, t.config.peerConeNatPort, t.coneLocalPort, t.config.linkMode, t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("listen TCP error:%s", err)
|
return nil, fmt.Errorf("listen TCP error:%s", err)
|
||||||
}
|
}
|
||||||
gLog.Println(LvINFO, "TCP connection ok")
|
gLog.Println(LvINFO, "TCP connection ok")
|
||||||
t.linkModeWeb = LinkModeIPv4
|
t.linkModeWeb = LinkModeIPv4
|
||||||
if t.config.linkMode == LinkModeIntranet {
|
if t.config.linkMode == LinkModeIntranet {
|
||||||
t.linkModeWeb = LinkModeIntranet
|
t.linkModeWeb = LinkModeIntranet
|
||||||
}
|
}
|
||||||
return ul, nil
|
return ul, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// client side
|
// client side
|
||||||
if t.config.linkMode == LinkModeTCP4 {
|
if t.config.linkMode == LinkModeTCP4 {
|
||||||
t.pn.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, ReadMsgTimeout)
|
t.pn.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, ReadMsgTimeout)
|
||||||
} else { //tcp punch should sleep for punch the same time
|
} else { //tcp punch should sleep for punch the same time
|
||||||
if compareVersion(t.config.peerVersion, SyncServerTimeVersion) < 0 {
|
if compareVersion(t.config.peerVersion, SyncServerTimeVersion) < 0 {
|
||||||
gLog.Printf(LvDEBUG, "peer version %s less than %s", t.config.peerVersion, SyncServerTimeVersion)
|
gLog.Printf(LvDEBUG, "peer version %s less than %s", t.config.peerVersion, SyncServerTimeVersion)
|
||||||
} else {
|
} else {
|
||||||
ts := time.Duration(int64(t.punchTs) + t.pn.dt + t.pn.ddtma*int64(time.Since(t.pn.hbTime)+PunchTsDelay)/int64(NetworkHeartbeatTime) - time.Now().UnixNano())
|
ts := time.Duration(int64(t.punchTs) + t.pn.dt + t.pn.ddtma*int64(time.Since(t.pn.hbTime)+PunchTsDelay)/int64(NetworkHeartbeatTime) - time.Now().UnixNano())
|
||||||
if ts > PunchTsDelay || ts < 0 {
|
if ts > PunchTsDelay || ts < 0 {
|
||||||
ts = PunchTsDelay
|
ts = PunchTsDelay
|
||||||
}
|
}
|
||||||
gLog.Printf(LvDEBUG, "sleep %d ms", ts/time.Millisecond)
|
gLog.Printf(LvDEBUG, "sleep %d ms", ts/time.Millisecond)
|
||||||
time.Sleep(ts)
|
time.Sleep(ts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ul, err = dialTCP(peerIP, t.config.peerConeNatPort, t.coneLocalPort, t.config.linkMode)
|
ul, err = dialTCP(peerIP, t.config.peerConeNatPort, t.coneLocalPort, t.config.linkMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("TCP dial to %s:%d error:%s", t.config.peerIP, t.config.peerConeNatPort, err)
|
return nil, fmt.Errorf("TCP dial to %s:%d error:%s", t.config.peerIP, t.config.peerConeNatPort, err)
|
||||||
}
|
}
|
||||||
handshakeBegin := time.Now()
|
handshakeBegin := time.Now()
|
||||||
tidBuff := new(bytes.Buffer)
|
tidBuff := new(bytes.Buffer)
|
||||||
binary.Write(tidBuff, binary.LittleEndian, t.id)
|
binary.Write(tidBuff, binary.LittleEndian, t.id)
|
||||||
ul.WriteBytes(MsgP2P, MsgTunnelHandshake, tidBuff.Bytes()) // tunnelID
|
ul.WriteBytes(MsgP2P, MsgTunnelHandshake, tidBuff.Bytes()) // tunnelID
|
||||||
_, buff, err := ul.ReadBuffer()
|
_, buff, err := ul.ReadBuffer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("read MsgTunnelHandshake error:%s", err)
|
return nil, fmt.Errorf("read MsgTunnelHandshake error:%s", err)
|
||||||
}
|
}
|
||||||
if buff != nil {
|
if buff != nil {
|
||||||
gLog.Println(LvDEBUG, "hello ", string(buff))
|
gLog.Println(LvDEBUG, "hello ", string(buff))
|
||||||
}
|
}
|
||||||
|
|
||||||
gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin))
|
gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin))
|
||||||
gLog.Println(LvINFO, "TCP connection ok")
|
gLog.Println(LvINFO, "TCP connection ok")
|
||||||
t.linkModeWeb = LinkModeIPv4
|
t.linkModeWeb = LinkModeIPv4
|
||||||
if t.config.linkMode == LinkModeIntranet {
|
if t.config.linkMode == LinkModeIntranet {
|
||||||
t.linkModeWeb = LinkModeIntranet
|
t.linkModeWeb = LinkModeIntranet
|
||||||
}
|
}
|
||||||
return ul, nil
|
return ul, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) connectUnderlayTCPSymmetric() (c underlay, err error) {
|
func (t *P2PTunnel) connectUnderlayTCPSymmetric() (c underlay, err error) {
|
||||||
gLog.Printf(LvDEBUG, "connectUnderlayTCPSymmetric %s start ", t.config.PeerNode)
|
gLog.Printf(LvDEBUG, "connectUnderlayTCPSymmetric %s start ", t.config.LogPeerNode())
|
||||||
defer gLog.Printf(LvDEBUG, "connectUnderlayTCPSymmetric %s end ", t.config.PeerNode)
|
defer gLog.Printf(LvDEBUG, "connectUnderlayTCPSymmetric %s end ", t.config.LogPeerNode())
|
||||||
ts := time.Duration(int64(t.punchTs) + t.pn.dt + t.pn.ddtma*int64(time.Since(t.pn.hbTime)+PunchTsDelay)/int64(NetworkHeartbeatTime) - time.Now().UnixNano())
|
ts := time.Duration(int64(t.punchTs) + t.pn.dt + t.pn.ddtma*int64(time.Since(t.pn.hbTime)+PunchTsDelay)/int64(NetworkHeartbeatTime) - time.Now().UnixNano())
|
||||||
if ts > PunchTsDelay || ts < 0 {
|
if ts > PunchTsDelay || ts < 0 {
|
||||||
ts = PunchTsDelay
|
ts = PunchTsDelay
|
||||||
}
|
}
|
||||||
gLog.Printf(LvDEBUG, "sleep %d ms", ts/time.Millisecond)
|
gLog.Printf(LvDEBUG, "sleep %d ms", ts/time.Millisecond)
|
||||||
time.Sleep(ts)
|
time.Sleep(ts)
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
t.linkModeWeb = LinkModeTCPPunch
|
t.linkModeWeb = LinkModeTCPPunch
|
||||||
gotCh := make(chan *underlayTCP, 1)
|
gotCh := make(chan *underlayTCP, 1)
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
var success atomic.Int32
|
var success atomic.Int32
|
||||||
if t.config.peerNatType == NATSymmetric { // c2s
|
if t.config.peerNatType == NATSymmetric { // c2s
|
||||||
randPorts := rand.Perm(65532)
|
randPorts := rand.Perm(65532)
|
||||||
for i := 0; i < SymmetricHandshakeNum; i++ {
|
for i := 0; i < SymmetricHandshakeNum; i++ {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func(port int) {
|
go func(port int) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
ul, err := dialTCP(t.config.peerIP, port, t.coneLocalPort, LinkModeTCPPunch)
|
ul, err := dialTCP(t.config.peerIP, port, t.coneLocalPort, LinkModeTCPPunch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !success.CompareAndSwap(0, 1) {
|
if !success.CompareAndSwap(0, 1) {
|
||||||
ul.Close() // only cone side close
|
ul.Close() // only cone side close
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = ul.WriteMessage(MsgP2P, MsgPunchHandshakeAck, P2PHandshakeReq{ID: t.id})
|
err = ul.WriteMessage(MsgP2P, MsgPunchHandshakeAck, P2PHandshakeReq{ID: t.id})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ul.Close()
|
ul.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, buff, err := ul.ReadBuffer()
|
_, buff, err := ul.ReadBuffer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvERROR, "utcp.ReadBuffer error:", err)
|
gLog.Printf(LvERROR, "utcp.ReadBuffer error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
req := P2PHandshakeReq{}
|
req := P2PHandshakeReq{}
|
||||||
if err = json.Unmarshal(buff, &req); err != nil {
|
if err = json.Unmarshal(buff, &req); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if req.ID != t.id {
|
if req.ID != t.id {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
gLog.Printf(LvINFO, "handshakeS2C TCP ok. cost %dms", time.Since(startTime)/time.Millisecond)
|
gLog.Printf(LvINFO, "handshakeS2C TCP ok. cost %dms", time.Since(startTime)/time.Millisecond)
|
||||||
|
|
||||||
gotCh <- ul
|
gotCh <- ul
|
||||||
close(gotCh)
|
close(gotCh)
|
||||||
}(randPorts[i] + 2)
|
}(randPorts[i] + 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else { // s2c
|
} else { // s2c
|
||||||
for i := 0; i < SymmetricHandshakeNum; i++ {
|
for i := 0; i < SymmetricHandshakeNum; i++ {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
ul, err := dialTCP(t.config.peerIP, t.config.peerConeNatPort, 0, LinkModeTCPPunch)
|
ul, err := dialTCP(t.config.peerIP, t.config.peerConeNatPort, 0, LinkModeTCPPunch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, buff, err := ul.ReadBuffer()
|
_, buff, err := ul.ReadBuffer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvERROR, "utcp.ReadBuffer error:", err)
|
gLog.Printf(LvERROR, "utcp.ReadBuffer error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
req := P2PHandshakeReq{}
|
req := P2PHandshakeReq{}
|
||||||
if err = json.Unmarshal(buff, &req); err != nil {
|
if err = json.Unmarshal(buff, &req); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if req.ID != t.id {
|
if req.ID != t.id {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = ul.WriteMessage(MsgP2P, MsgPunchHandshakeAck, P2PHandshakeReq{ID: t.id})
|
err = ul.WriteMessage(MsgP2P, MsgPunchHandshakeAck, P2PHandshakeReq{ID: t.id})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ul.Close()
|
ul.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if success.CompareAndSwap(0, 1) {
|
if success.CompareAndSwap(0, 1) {
|
||||||
gotCh <- ul
|
gotCh <- ul
|
||||||
close(gotCh)
|
close(gotCh)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case <-time.After(HandshakeTimeout):
|
case <-time.After(HandshakeTimeout):
|
||||||
return nil, fmt.Errorf("wait tcp handshake timeout")
|
return nil, fmt.Errorf("wait tcp handshake timeout")
|
||||||
case ul := <-gotCh:
|
case ul := <-gotCh:
|
||||||
return ul, nil
|
return ul, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) connectUnderlayTCP6() (c underlay, err error) {
|
func (t *P2PTunnel) connectUnderlayTCP6() (c underlay, err error) {
|
||||||
gLog.Printf(LvDEBUG, "connectUnderlayTCP6 %s start ", t.config.PeerNode)
|
gLog.Printf(LvDEBUG, "connectUnderlayTCP6 %s start ", t.config.LogPeerNode())
|
||||||
defer gLog.Printf(LvDEBUG, "connectUnderlayTCP6 %s end ", t.config.PeerNode)
|
defer gLog.Printf(LvDEBUG, "connectUnderlayTCP6 %s end ", t.config.LogPeerNode())
|
||||||
var ul *underlayTCP6
|
var ul *underlayTCP6
|
||||||
if t.config.isUnderlayServer == 1 {
|
if t.config.isUnderlayServer == 1 {
|
||||||
t.pn.push(t.config.PeerNode, MsgPushUnderlayConnect, nil)
|
t.pn.push(t.config.PeerNode, MsgPushUnderlayConnect, nil)
|
||||||
ul, err = listenTCP6(t.coneNatPort, UnderlayConnectTimeout)
|
ul, err = listenTCP6(t.coneNatPort, UnderlayConnectTimeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("listen TCP6 error:%s", err)
|
return nil, fmt.Errorf("listen TCP6 error:%s", err)
|
||||||
}
|
}
|
||||||
_, buff, err := ul.ReadBuffer()
|
_, buff, err := ul.ReadBuffer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("read start msg error:%s", err)
|
return nil, fmt.Errorf("read start msg error:%s", err)
|
||||||
}
|
}
|
||||||
if buff != nil {
|
if buff != nil {
|
||||||
gLog.Println(LvDEBUG, string(buff))
|
gLog.Println(LvDEBUG, string(buff))
|
||||||
}
|
}
|
||||||
ul.WriteBytes(MsgP2P, MsgTunnelHandshakeAck, []byte("OpenP2P,hello2"))
|
ul.WriteBytes(MsgP2P, MsgTunnelHandshakeAck, []byte("OpenP2P,hello2"))
|
||||||
gLog.Println(LvDEBUG, "TCP6 connection ok")
|
gLog.Println(LvDEBUG, "TCP6 connection ok")
|
||||||
t.linkModeWeb = LinkModeIPv6
|
t.linkModeWeb = LinkModeIPv6
|
||||||
return ul, nil
|
return ul, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//else
|
//else
|
||||||
t.pn.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, ReadMsgTimeout)
|
t.pn.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, ReadMsgTimeout)
|
||||||
gLog.Println(LvDEBUG, "TCP6 dial to ", t.config.peerIPv6)
|
gLog.Println(LvDEBUG, "TCP6 dial to ", t.config.peerIPv6)
|
||||||
ul, err = dialTCP6(t.config.peerIPv6, t.config.peerConeNatPort)
|
ul, err = dialTCP6(t.config.peerIPv6, t.config.peerConeNatPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("TCP6 dial to %s:%d error:%s", t.config.peerIPv6, t.config.peerConeNatPort, err)
|
return nil, fmt.Errorf("TCP6 dial to %s:%d error:%s", t.config.peerIPv6, t.config.peerConeNatPort, err)
|
||||||
}
|
}
|
||||||
handshakeBegin := time.Now()
|
handshakeBegin := time.Now()
|
||||||
ul.WriteBytes(MsgP2P, MsgTunnelHandshake, []byte("OpenP2P,hello"))
|
ul.WriteBytes(MsgP2P, MsgTunnelHandshake, []byte("OpenP2P,hello"))
|
||||||
_, buff, err := ul.ReadBuffer()
|
_, buff, err := ul.ReadBuffer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("read MsgTunnelHandshake error:%s", err)
|
return nil, fmt.Errorf("read MsgTunnelHandshake error:%s", err)
|
||||||
}
|
}
|
||||||
if buff != nil {
|
if buff != nil {
|
||||||
gLog.Println(LvDEBUG, string(buff))
|
gLog.Println(LvDEBUG, string(buff))
|
||||||
}
|
}
|
||||||
|
|
||||||
gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin))
|
gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin))
|
||||||
gLog.Println(LvINFO, "TCP6 connection ok")
|
gLog.Println(LvINFO, "TCP6 connection ok")
|
||||||
t.linkModeWeb = LinkModeIPv6
|
t.linkModeWeb = LinkModeIPv6
|
||||||
return ul, nil
|
return ul, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) readLoop() {
|
func (t *P2PTunnel) readLoop() {
|
||||||
decryptData := make([]byte, ReadBuffLen+PaddingSize) // 16 bytes for padding
|
decryptData := make([]byte, ReadBuffLen+PaddingSize) // 16 bytes for padding
|
||||||
gLog.Printf(LvDEBUG, "%d tunnel readloop start", t.id)
|
gLog.Printf(LvDEBUG, "%d tunnel readloop start", t.id)
|
||||||
for t.isRuning() {
|
for t.isRuning() {
|
||||||
t.conn.SetReadDeadline(time.Now().Add(TunnelHeartbeatTime * 2))
|
t.conn.SetReadDeadline(time.Now().Add(TunnelHeartbeatTime * 2))
|
||||||
head, body, err := t.conn.ReadBuffer()
|
head, body, err := t.conn.ReadBuffer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if t.isRuning() {
|
if t.isRuning() {
|
||||||
gLog.Printf(LvERROR, "%d tunnel read error:%s", t.id, err)
|
gLog.Printf(LvERROR, "%d tunnel read error:%s", t.id, err)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if head.MainType != MsgP2P {
|
if head.MainType != MsgP2P {
|
||||||
gLog.Printf(LvWARN, "%d head.MainType != MsgP2P", t.id)
|
gLog.Printf(LvWARN, "%d head.MainType != MsgP2P", t.id)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// TODO: replace some case implement to functions
|
// TODO: replace some case implement to functions
|
||||||
switch head.SubType {
|
switch head.SubType {
|
||||||
case MsgTunnelHeartbeat:
|
case MsgTunnelHeartbeat:
|
||||||
t.hbMtx.Lock()
|
t.hbMtx.Lock()
|
||||||
t.hbTime = time.Now()
|
t.hbTime = time.Now()
|
||||||
t.hbMtx.Unlock()
|
t.hbMtx.Unlock()
|
||||||
t.conn.WriteBytes(MsgP2P, MsgTunnelHeartbeatAck, nil)
|
t.conn.WriteBytes(MsgP2P, MsgTunnelHeartbeatAck, nil)
|
||||||
gLog.Printf(LvDev, "%d read tunnel heartbeat", t.id)
|
gLog.Printf(LvDev, "%d read tunnel heartbeat", t.id)
|
||||||
case MsgTunnelHeartbeatAck:
|
case MsgTunnelHeartbeatAck:
|
||||||
t.hbMtx.Lock()
|
t.hbMtx.Lock()
|
||||||
t.hbTime = time.Now()
|
t.hbTime = time.Now()
|
||||||
t.hbMtx.Unlock()
|
t.hbMtx.Unlock()
|
||||||
gLog.Printf(LvDev, "%d read tunnel heartbeat ack", t.id)
|
gLog.Printf(LvDev, "%d read tunnel heartbeat ack", t.id)
|
||||||
case MsgOverlayData:
|
case MsgOverlayData:
|
||||||
if len(body) < overlayHeaderSize {
|
if len(body) < overlayHeaderSize {
|
||||||
gLog.Printf(LvWARN, "%d len(body) < overlayHeaderSize", t.id)
|
gLog.Printf(LvWARN, "%d len(body) < overlayHeaderSize", t.id)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
overlayID := binary.LittleEndian.Uint64(body[:8])
|
overlayID := binary.LittleEndian.Uint64(body[:8])
|
||||||
gLog.Printf(LvDev, "%d tunnel read overlay data %d bodylen=%d", t.id, overlayID, head.DataLen)
|
gLog.Printf(LvDev, "%d tunnel read overlay data %d bodylen=%d", t.id, overlayID, head.DataLen)
|
||||||
s, ok := t.overlayConns.Load(overlayID)
|
s, ok := t.overlayConns.Load(overlayID)
|
||||||
if !ok {
|
if !ok {
|
||||||
// debug level, when overlay connection closed, always has some packet not found tunnel
|
// debug level, when overlay connection closed, always has some packet not found tunnel
|
||||||
gLog.Printf(LvDEBUG, "%d tunnel not found overlay connection %d", t.id, overlayID)
|
gLog.Printf(LvDEBUG, "%d tunnel not found overlay connection %d", t.id, overlayID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
overlayConn, ok := s.(*overlayConn)
|
overlayConn, ok := s.(*overlayConn)
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
payload := body[overlayHeaderSize:]
|
payload := body[overlayHeaderSize:]
|
||||||
var err error
|
var err error
|
||||||
if overlayConn.appKey != 0 {
|
if overlayConn.appKey != 0 {
|
||||||
payload, _ = decryptBytes(overlayConn.appKeyBytes, decryptData, body[overlayHeaderSize:], int(head.DataLen-uint32(overlayHeaderSize)))
|
payload, _ = decryptBytes(overlayConn.appKeyBytes, decryptData, body[overlayHeaderSize:], int(head.DataLen-uint32(overlayHeaderSize)))
|
||||||
}
|
}
|
||||||
_, err = overlayConn.Write(payload)
|
_, err = overlayConn.Write(payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "overlay write error:", err)
|
gLog.Println(LvERROR, "overlay write error:", err)
|
||||||
}
|
}
|
||||||
case MsgNodeData:
|
case MsgNodeData:
|
||||||
t.handleNodeData(head, body, false)
|
t.handleNodeData(head, body, false)
|
||||||
case MsgRelayNodeData:
|
case MsgRelayNodeData:
|
||||||
t.handleNodeData(head, body, true)
|
t.handleNodeData(head, body, true)
|
||||||
case MsgRelayData:
|
case MsgRelayData:
|
||||||
if len(body) < 8 {
|
if len(body) < 8 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
tunnelID := binary.LittleEndian.Uint64(body[:8])
|
tunnelID := binary.LittleEndian.Uint64(body[:8])
|
||||||
gLog.Printf(LvDev, "relay data to %d, len=%d", tunnelID, head.DataLen-RelayHeaderSize)
|
gLog.Printf(LvDev, "relay data to %d, len=%d", tunnelID, head.DataLen-RelayHeaderSize)
|
||||||
if err := t.pn.relay(tunnelID, body[RelayHeaderSize:]); err != nil {
|
if err := t.pn.relay(tunnelID, body[RelayHeaderSize:]); err != nil {
|
||||||
gLog.Printf(LvERROR, "%s:%d relay to %d len=%d error:%s", t.config.PeerNode, t.id, tunnelID, len(body), ErrRelayTunnelNotFound)
|
gLog.Printf(LvERROR, "%s:%d relay to %d len=%d error:%s", t.config.LogPeerNode(), t.id, tunnelID, len(body), ErrRelayTunnelNotFound)
|
||||||
}
|
}
|
||||||
case MsgRelayHeartbeat:
|
case MsgRelayHeartbeat:
|
||||||
req := RelayHeartbeat{}
|
req := RelayHeartbeat{}
|
||||||
if err := json.Unmarshal(body, &req); err != nil {
|
if err := json.Unmarshal(body, &req); err != nil {
|
||||||
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// TODO: debug relay heartbeat
|
// TODO: debug relay heartbeat
|
||||||
gLog.Printf(LvDEBUG, "read MsgRelayHeartbeat from rtid:%d,appid:%d", req.RelayTunnelID, req.AppID)
|
gLog.Printf(LvDEBUG, "read MsgRelayHeartbeat from rtid:%d,appid:%d", req.RelayTunnelID, req.AppID)
|
||||||
// update app hbtime
|
// update app hbtime
|
||||||
t.pn.updateAppHeartbeat(req.AppID)
|
t.pn.updateAppHeartbeat(req.AppID)
|
||||||
req.From = gConf.Network.Node
|
req.From = gConf.Network.Node
|
||||||
t.WriteMessage(req.RelayTunnelID, MsgP2P, MsgRelayHeartbeatAck, &req)
|
t.WriteMessage(req.RelayTunnelID, MsgP2P, MsgRelayHeartbeatAck, &req)
|
||||||
case MsgRelayHeartbeatAck:
|
case MsgRelayHeartbeatAck:
|
||||||
req := RelayHeartbeat{}
|
req := RelayHeartbeat{}
|
||||||
err := json.Unmarshal(body, &req)
|
err := json.Unmarshal(body, &req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvERROR, "wrong RelayHeartbeat:%s", err)
|
gLog.Printf(LvERROR, "wrong RelayHeartbeat:%s", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// TODO: debug relay heartbeat
|
// TODO: debug relay heartbeat
|
||||||
gLog.Printf(LvDEBUG, "read MsgRelayHeartbeatAck to appid:%d", req.AppID)
|
gLog.Printf(LvDEBUG, "read MsgRelayHeartbeatAck to appid:%d", req.AppID)
|
||||||
t.pn.updateAppHeartbeat(req.AppID)
|
t.pn.updateAppHeartbeat(req.AppID)
|
||||||
case MsgOverlayConnectReq:
|
case MsgOverlayConnectReq:
|
||||||
req := OverlayConnectReq{}
|
req := OverlayConnectReq{}
|
||||||
if err := json.Unmarshal(body, &req); err != nil {
|
if err := json.Unmarshal(body, &req); err != nil {
|
||||||
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// app connect only accept token(not relay totp token), avoid someone using the share relay node's token
|
// app connect only accept token(not relay totp token), avoid someone using the share relay node's token
|
||||||
if req.Token != gConf.Network.Token {
|
if req.Token != gConf.Network.Token {
|
||||||
gLog.Println(LvERROR, "Access Denied:", req.Token)
|
gLog.Println(LvERROR, "Access Denied:", req.Token)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
overlayID := req.ID
|
overlayID := req.ID
|
||||||
gLog.Printf(LvDEBUG, "App:%d overlayID:%d connect %s:%d", req.AppID, overlayID, req.DstIP, req.DstPort)
|
gLog.Printf(LvDEBUG, "App:%d overlayID:%d connect %s:%d", req.AppID, overlayID, req.DstIP, req.DstPort)
|
||||||
oConn := overlayConn{
|
oConn := overlayConn{
|
||||||
tunnel: t,
|
tunnel: t,
|
||||||
id: overlayID,
|
id: overlayID,
|
||||||
isClient: false,
|
isClient: false,
|
||||||
rtid: req.RelayTunnelID,
|
rtid: req.RelayTunnelID,
|
||||||
appID: req.AppID,
|
appID: req.AppID,
|
||||||
appKey: GetKey(req.AppID),
|
appKey: GetKey(req.AppID),
|
||||||
running: true,
|
running: true,
|
||||||
}
|
}
|
||||||
if req.Protocol == "udp" {
|
if req.Protocol == "udp" {
|
||||||
oConn.connUDP, err = net.DialUDP("udp", nil, &net.UDPAddr{IP: net.ParseIP(req.DstIP), Port: req.DstPort})
|
oConn.connUDP, err = net.DialUDP("udp", nil, &net.UDPAddr{IP: net.ParseIP(req.DstIP), Port: req.DstPort})
|
||||||
} else {
|
} else {
|
||||||
oConn.connTCP, err = net.DialTimeout("tcp", fmt.Sprintf("%s:%d", req.DstIP, req.DstPort), ReadMsgTimeout)
|
oConn.connTCP, err = net.DialTimeout("tcp", fmt.Sprintf("%s:%d", req.DstIP, req.DstPort), ReadMsgTimeout)
|
||||||
|
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, err)
|
gLog.Println(LvERROR, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// calc key bytes for encrypt
|
// calc key bytes for encrypt
|
||||||
if oConn.appKey != 0 {
|
if oConn.appKey != 0 {
|
||||||
encryptKey := make([]byte, AESKeySize)
|
encryptKey := make([]byte, AESKeySize)
|
||||||
binary.LittleEndian.PutUint64(encryptKey, oConn.appKey)
|
binary.LittleEndian.PutUint64(encryptKey, oConn.appKey)
|
||||||
binary.LittleEndian.PutUint64(encryptKey[8:], oConn.appKey)
|
binary.LittleEndian.PutUint64(encryptKey[8:], oConn.appKey)
|
||||||
oConn.appKeyBytes = encryptKey
|
oConn.appKeyBytes = encryptKey
|
||||||
}
|
}
|
||||||
|
|
||||||
t.overlayConns.Store(oConn.id, &oConn)
|
t.overlayConns.Store(oConn.id, &oConn)
|
||||||
go oConn.run()
|
go oConn.run()
|
||||||
case MsgOverlayDisconnectReq:
|
case MsgOverlayDisconnectReq:
|
||||||
req := OverlayDisconnectReq{}
|
req := OverlayDisconnectReq{}
|
||||||
if err := json.Unmarshal(body, &req); err != nil {
|
if err := json.Unmarshal(body, &req); err != nil {
|
||||||
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
overlayID := req.ID
|
overlayID := req.ID
|
||||||
gLog.Printf(LvDEBUG, "%d disconnect overlay connection %d", t.id, overlayID)
|
gLog.Printf(LvDEBUG, "%d disconnect overlay connection %d", t.id, overlayID)
|
||||||
i, ok := t.overlayConns.Load(overlayID)
|
i, ok := t.overlayConns.Load(overlayID)
|
||||||
if ok {
|
if ok {
|
||||||
oConn := i.(*overlayConn)
|
oConn := i.(*overlayConn)
|
||||||
oConn.Close()
|
oConn.Close()
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.close()
|
t.close()
|
||||||
gLog.Printf(LvDEBUG, "%d tunnel readloop end", t.id)
|
gLog.Printf(LvDEBUG, "%d tunnel readloop end", t.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) writeLoop() {
|
func (t *P2PTunnel) writeLoop() {
|
||||||
t.hbMtx.Lock()
|
t.hbMtx.Lock()
|
||||||
t.hbTime = time.Now() // init
|
t.hbTime = time.Now() // init
|
||||||
t.hbMtx.Unlock()
|
t.hbMtx.Unlock()
|
||||||
tc := time.NewTicker(TunnelHeartbeatTime)
|
tc := time.NewTicker(TunnelHeartbeatTime)
|
||||||
defer tc.Stop()
|
defer tc.Stop()
|
||||||
gLog.Printf(LvDEBUG, "%s:%d tunnel writeLoop start", t.config.PeerNode, t.id)
|
gLog.Printf(LvDEBUG, "%s:%d tunnel writeLoop start", t.config.LogPeerNode(), t.id)
|
||||||
defer gLog.Printf(LvDEBUG, "%s:%d tunnel writeLoop end", t.config.PeerNode, t.id)
|
defer gLog.Printf(LvDEBUG, "%s:%d tunnel writeLoop end", t.config.LogPeerNode(), t.id)
|
||||||
for t.isRuning() {
|
for t.isRuning() {
|
||||||
select {
|
select {
|
||||||
case buff := <-t.writeDataSmall:
|
case buff := <-t.writeDataSmall:
|
||||||
t.conn.WriteBuffer(buff)
|
t.conn.WriteBuffer(buff)
|
||||||
// gLog.Printf(LvDEBUG, "write icmp %d", time.Now().Unix())
|
// gLog.Printf(LvDEBUG, "write icmp %d", time.Now().Unix())
|
||||||
default:
|
default:
|
||||||
select {
|
select {
|
||||||
case buff := <-t.writeDataSmall:
|
case buff := <-t.writeDataSmall:
|
||||||
t.conn.WriteBuffer(buff)
|
t.conn.WriteBuffer(buff)
|
||||||
// gLog.Printf(LvDEBUG, "write icmp %d", time.Now().Unix())
|
// gLog.Printf(LvDEBUG, "write icmp %d", time.Now().Unix())
|
||||||
case buff := <-t.writeData:
|
case buff := <-t.writeData:
|
||||||
t.conn.WriteBuffer(buff)
|
t.conn.WriteBuffer(buff)
|
||||||
case <-tc.C:
|
case <-tc.C:
|
||||||
// tunnel send
|
// tunnel send
|
||||||
err := t.conn.WriteBytes(MsgP2P, MsgTunnelHeartbeat, nil)
|
err := t.conn.WriteBytes(MsgP2P, MsgTunnelHeartbeat, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvERROR, "%d write tunnel heartbeat error %s", t.id, err)
|
gLog.Printf(LvERROR, "%d write tunnel heartbeat error %s", t.id, err)
|
||||||
t.close()
|
t.close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
gLog.Printf(LvDev, "%d write tunnel heartbeat ok", t.id)
|
gLog.Printf(LvDev, "%d write tunnel heartbeat ok", t.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) listen() error {
|
func (t *P2PTunnel) listen() error {
|
||||||
// notify client to connect
|
// notify client to connect
|
||||||
rsp := PushConnectRsp{
|
rsp := PushConnectRsp{
|
||||||
Error: 0,
|
Error: 0,
|
||||||
Detail: "connect ok",
|
Detail: "connect ok",
|
||||||
To: t.config.PeerNode,
|
To: t.config.PeerNode,
|
||||||
From: gConf.Network.Node,
|
From: gConf.Network.Node,
|
||||||
NatType: gConf.Network.natType,
|
NatType: gConf.Network.natType,
|
||||||
HasIPv4: gConf.Network.hasIPv4,
|
HasIPv4: gConf.Network.hasIPv4,
|
||||||
// IPv6: gConf.Network.IPv6,
|
// IPv6: gConf.Network.IPv6,
|
||||||
HasUPNPorNATPMP: gConf.Network.hasUPNPorNATPMP,
|
HasUPNPorNATPMP: gConf.Network.hasUPNPorNATPMP,
|
||||||
FromIP: gConf.Network.publicIP,
|
FromIP: gConf.Network.publicIP,
|
||||||
ConeNatPort: t.coneNatPort,
|
ConeNatPort: t.coneNatPort,
|
||||||
ID: t.id,
|
ID: t.id,
|
||||||
PunchTs: uint64(time.Now().UnixNano() + int64(PunchTsDelay) - t.pn.dt),
|
PunchTs: uint64(time.Now().UnixNano() + int64(PunchTsDelay) - t.pn.dt),
|
||||||
Version: OpenP2PVersion,
|
Version: OpenP2PVersion,
|
||||||
}
|
}
|
||||||
t.punchTs = rsp.PunchTs
|
t.punchTs = rsp.PunchTs
|
||||||
// only private node set ipv6
|
// only private node set ipv6
|
||||||
if t.config.fromToken == gConf.Network.Token {
|
if t.config.fromToken == gConf.Network.Token {
|
||||||
rsp.IPv6 = gConf.IPv6()
|
rsp.IPv6 = gConf.IPv6()
|
||||||
}
|
}
|
||||||
|
|
||||||
t.pn.push(t.config.PeerNode, MsgPushConnectRsp, rsp)
|
t.pn.push(t.config.PeerNode, MsgPushConnectRsp, rsp)
|
||||||
gLog.Printf(LvDEBUG, "p2ptunnel wait for connecting")
|
gLog.Printf(LvDEBUG, "p2ptunnel wait for connecting")
|
||||||
t.tunnelServer = true
|
t.tunnelServer = true
|
||||||
return t.start()
|
return t.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) closeOverlayConns(appID uint64) {
|
func (t *P2PTunnel) closeOverlayConns(appID uint64) {
|
||||||
t.overlayConns.Range(func(_, i interface{}) bool {
|
t.overlayConns.Range(func(_, i interface{}) bool {
|
||||||
oConn := i.(*overlayConn)
|
oConn := i.(*overlayConn)
|
||||||
if oConn.appID == appID {
|
if oConn.appID == appID {
|
||||||
oConn.Close()
|
oConn.Close()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) handleNodeData(head *openP2PHeader, body []byte, isRelay bool) {
|
func (t *P2PTunnel) handleNodeData(head *openP2PHeader, body []byte, isRelay bool) {
|
||||||
gLog.Printf(LvDev, "%d tunnel read node data bodylen=%d, relay=%t", t.id, head.DataLen, isRelay)
|
gLog.Printf(LvDev, "%d tunnel read node data bodylen=%d, relay=%t", t.id, head.DataLen, isRelay)
|
||||||
ch := t.pn.nodeData
|
ch := t.pn.nodeData
|
||||||
// if body[9] == 1 { // TODO: deal relay
|
// if body[9] == 1 { // TODO: deal relay
|
||||||
// ch = t.pn.nodeDataSmall
|
// ch = t.pn.nodeDataSmall
|
||||||
// gLog.Printf(LvDEBUG, "read icmp %d", time.Now().Unix())
|
// gLog.Printf(LvDEBUG, "read icmp %d", time.Now().Unix())
|
||||||
// }
|
// }
|
||||||
if isRelay {
|
if isRelay {
|
||||||
fromPeerID := binary.LittleEndian.Uint64(body[:8])
|
fromPeerID := binary.LittleEndian.Uint64(body[:8])
|
||||||
ch <- &NodeData{fromPeerID, body[8:]} // TODO: cache peerNodeID; encrypt/decrypt
|
ch <- &NodeData{fromPeerID, body[8:]} // TODO: cache peerNodeID; encrypt/decrypt
|
||||||
} else {
|
} else {
|
||||||
ch <- &NodeData{NodeNameToID(t.config.PeerNode), body} // TODO: cache peerNodeID; encrypt/decrypt
|
ch <- &NodeData{NodeNameToID(t.config.PeerNode), body} // TODO: cache peerNodeID; encrypt/decrypt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) asyncWriteNodeData(mainType, subType uint16, data []byte) {
|
func (t *P2PTunnel) asyncWriteNodeData(mainType, subType uint16, data []byte) {
|
||||||
writeBytes := append(encodeHeader(mainType, subType, uint32(len(data))), data...)
|
writeBytes := append(encodeHeader(mainType, subType, uint32(len(data))), data...)
|
||||||
// if len(data) < 192 {
|
// if len(data) < 192 {
|
||||||
if data[9] == 1 { // icmp
|
if data[9] == 1 { // icmp
|
||||||
select {
|
select {
|
||||||
case t.writeDataSmall <- writeBytes:
|
case t.writeDataSmall <- writeBytes:
|
||||||
// gLog.Printf(LvWARN, "%s:%d t.writeDataSmall write %d", t.config.PeerNode, t.id, len(t.writeDataSmall))
|
// gLog.Printf(LvWARN, "%s:%d t.writeDataSmall write %d", t.config.PeerNode, t.id, len(t.writeDataSmall))
|
||||||
default:
|
default:
|
||||||
gLog.Printf(LvWARN, "%s:%d t.writeDataSmall is full, drop it", t.config.PeerNode, t.id)
|
gLog.Printf(LvWARN, "%s:%d t.writeDataSmall is full, drop it", t.config.LogPeerNode(), t.id)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
select {
|
select {
|
||||||
case t.writeData <- writeBytes:
|
case t.writeData <- writeBytes:
|
||||||
default:
|
default:
|
||||||
gLog.Printf(LvWARN, "%s:%d t.writeData is full, drop it", t.config.PeerNode, t.id)
|
gLog.Printf(LvWARN, "%s:%d t.writeData is full, drop it", t.config.LogPeerNode(), t.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *P2PTunnel) WriteMessage(rtid uint64, mainType uint16, subType uint16, req interface{}) error {
|
func (t *P2PTunnel) WriteMessage(rtid uint64, mainType uint16, subType uint16, req interface{}) error {
|
||||||
if rtid == 0 {
|
if rtid == 0 {
|
||||||
return t.conn.WriteMessage(mainType, subType, &req)
|
return t.conn.WriteMessage(mainType, subType, &req)
|
||||||
}
|
}
|
||||||
relayHead := new(bytes.Buffer)
|
relayHead := new(bytes.Buffer)
|
||||||
binary.Write(relayHead, binary.LittleEndian, rtid)
|
binary.Write(relayHead, binary.LittleEndian, rtid)
|
||||||
msg, _ := newMessage(mainType, subType, &req)
|
msg, _ := newMessage(mainType, subType, &req)
|
||||||
msgWithHead := append(relayHead.Bytes(), msg...)
|
msgWithHead := append(relayHead.Bytes(), msg...)
|
||||||
return t.conn.WriteBytes(mainType, MsgRelayData, msgWithHead)
|
return t.conn.WriteBytes(mainType, MsgRelayData, msgWithHead)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-1
@@ -10,7 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const OpenP2PVersion = "3.18.4"
|
const OpenP2PVersion = "3.19.0"
|
||||||
const ProductName string = "openp2p"
|
const ProductName string = "openp2p"
|
||||||
const LeastSupportVersion = "3.0.0"
|
const LeastSupportVersion = "3.0.0"
|
||||||
const SyncServerTimeVersion = "3.9.0"
|
const SyncServerTimeVersion = "3.9.0"
|
||||||
@@ -108,6 +108,7 @@ const (
|
|||||||
MsgPushReportGoroutine = 16
|
MsgPushReportGoroutine = 16
|
||||||
MsgPushReportMemApps = 17
|
MsgPushReportMemApps = 17
|
||||||
MsgPushServerSideSaveMemApp = 18
|
MsgPushServerSideSaveMemApp = 18
|
||||||
|
MsgPushCheckRemoteService = 19
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgP2P sub type message
|
// MsgP2P sub type message
|
||||||
@@ -143,6 +144,7 @@ const (
|
|||||||
MsgReportApps
|
MsgReportApps
|
||||||
MsgReportLog
|
MsgReportLog
|
||||||
MsgReportMemApps
|
MsgReportMemApps
|
||||||
|
MsgReportResponse
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -510,6 +512,11 @@ type ServerSideSaveMemApp struct {
|
|||||||
AppID uint64 `json:"appID,omitempty"`
|
AppID uint64 `json:"appID,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CheckRemoteService struct {
|
||||||
|
Host string `json:"host,omitempty"`
|
||||||
|
Port uint32 `json:"port,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
const rootCA = `-----BEGIN CERTIFICATE-----
|
const rootCA = `-----BEGIN CERTIFICATE-----
|
||||||
MIIDhTCCAm0CFHm0cd8dnGCbUW/OcS56jf0gvRk7MA0GCSqGSIb3DQEBCwUAMH4x
|
MIIDhTCCAm0CFHm0cd8dnGCbUW/OcS56jf0gvRk7MA0GCSqGSIb3DQEBCwUAMH4x
|
||||||
CzAJBgNVBAYTAkNOMQswCQYDVQQIDAJHRDETMBEGA1UECgwKb3BlbnAycC5jbjET
|
CzAJBgNVBAYTAkNOMQswCQYDVQQIDAJHRDETMBEGA1UECgwKb3BlbnAycC5jbjET
|
||||||
|
|||||||
+292
-292
@@ -1,292 +1,292 @@
|
|||||||
package openp2p
|
package openp2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PacketHeader struct {
|
type PacketHeader struct {
|
||||||
version int
|
version int
|
||||||
// src uint32
|
// src uint32
|
||||||
// prot uint8
|
// prot uint8
|
||||||
protocol byte
|
protocol byte
|
||||||
dst uint32
|
dst uint32
|
||||||
port uint16
|
port uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseHeader(b []byte, h *PacketHeader) error {
|
func parseHeader(b []byte, h *PacketHeader) error {
|
||||||
if len(b) < 20 {
|
if len(b) < 20 {
|
||||||
return fmt.Errorf("small packet")
|
return fmt.Errorf("small packet")
|
||||||
}
|
}
|
||||||
h.version = int(b[0] >> 4)
|
h.version = int(b[0] >> 4)
|
||||||
h.protocol = byte(b[9])
|
h.protocol = byte(b[9])
|
||||||
if h.version == 4 {
|
if h.version == 4 {
|
||||||
h.dst = binary.BigEndian.Uint32(b[16:20])
|
h.dst = binary.BigEndian.Uint32(b[16:20])
|
||||||
} else if h.version != 6 {
|
} else if h.version != 6 {
|
||||||
return fmt.Errorf("unknown version in ip header:%d", h.version)
|
return fmt.Errorf("unknown version in ip header:%d", h.version)
|
||||||
}
|
}
|
||||||
if h.protocol == 6 || h.protocol == 17 { // TCP or UDP
|
if h.protocol == 6 || h.protocol == 17 { // TCP or UDP
|
||||||
h.port = binary.BigEndian.Uint16(b[22:24])
|
h.port = binary.BigEndian.Uint16(b[22:24])
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type sdwanNode struct {
|
type sdwanNode struct {
|
||||||
name string
|
name string
|
||||||
id uint64
|
id uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type p2pSDWAN struct {
|
type p2pSDWAN struct {
|
||||||
nodeName string
|
nodeName string
|
||||||
tun *optun
|
tun *optun
|
||||||
sysRoute sync.Map // ip:sdwanNode
|
sysRoute sync.Map // ip:sdwanNode
|
||||||
subnet *net.IPNet
|
subnet *net.IPNet
|
||||||
gateway net.IP
|
gateway net.IP
|
||||||
virtualIP *net.IPNet
|
virtualIP *net.IPNet
|
||||||
internalRoute *IPTree
|
internalRoute *IPTree
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *p2pSDWAN) init(name string) error {
|
func (s *p2pSDWAN) init(name string) error {
|
||||||
if gConf.getSDWAN().Gateway == "" {
|
if gConf.getSDWAN().Gateway == "" {
|
||||||
gLog.Println(LvDEBUG, "not in sdwan clear all ")
|
gLog.Println(LvDEBUG, "not in sdwan clear all ")
|
||||||
}
|
}
|
||||||
if s.internalRoute == nil {
|
if s.internalRoute == nil {
|
||||||
s.internalRoute = NewIPTree("")
|
s.internalRoute = NewIPTree("")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.nodeName = name
|
s.nodeName = name
|
||||||
s.gateway, s.subnet, _ = net.ParseCIDR(gConf.getSDWAN().Gateway)
|
s.gateway, s.subnet, _ = net.ParseCIDR(gConf.getSDWAN().Gateway)
|
||||||
for _, node := range gConf.getDelNodes() {
|
for _, node := range gConf.getDelNodes() {
|
||||||
gLog.Println(LvDEBUG, "deal deleted node: ", node.Name)
|
gLog.Println(LvDEBUG, "deal deleted node: ", node.Name)
|
||||||
delRoute(node.IP, s.gateway.String())
|
delRoute(node.IP, s.gateway.String())
|
||||||
s.internalRoute.Del(node.IP, node.IP)
|
s.internalRoute.Del(node.IP, node.IP)
|
||||||
ipNum, _ := inetAtoN(node.IP)
|
ipNum, _ := inetAtoN(node.IP)
|
||||||
s.sysRoute.Delete(ipNum)
|
s.sysRoute.Delete(ipNum)
|
||||||
gConf.delete(AppConfig{SrcPort: 0, PeerNode: node.Name})
|
gConf.delete(AppConfig{SrcPort: 0, PeerNode: node.Name})
|
||||||
GNetwork.DeleteApp(AppConfig{SrcPort: 0, PeerNode: node.Name})
|
GNetwork.DeleteApp(AppConfig{SrcPort: 0, PeerNode: node.Name})
|
||||||
arr := strings.Split(node.Resource, ",")
|
arr := strings.Split(node.Resource, ",")
|
||||||
for _, r := range arr {
|
for _, r := range arr {
|
||||||
_, ipnet, err := net.ParseCIDR(r)
|
_, ipnet, err := net.ParseCIDR(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// fmt.Println("Error parsing CIDR:", err)
|
// fmt.Println("Error parsing CIDR:", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if ipnet.Contains(net.ParseIP(gConf.Network.localIP)) { // local ip and resource in the same lan
|
if ipnet.Contains(net.ParseIP(gConf.Network.localIP)) { // local ip and resource in the same lan
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
minIP := ipnet.IP
|
minIP := ipnet.IP
|
||||||
maxIP := make(net.IP, len(minIP))
|
maxIP := make(net.IP, len(minIP))
|
||||||
copy(maxIP, minIP)
|
copy(maxIP, minIP)
|
||||||
for i := range minIP {
|
for i := range minIP {
|
||||||
maxIP[i] = minIP[i] | ^ipnet.Mask[i]
|
maxIP[i] = minIP[i] | ^ipnet.Mask[i]
|
||||||
}
|
}
|
||||||
s.internalRoute.Del(minIP.String(), maxIP.String())
|
s.internalRoute.Del(minIP.String(), maxIP.String())
|
||||||
delRoute(ipnet.String(), s.gateway.String())
|
delRoute(ipnet.String(), s.gateway.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, node := range gConf.getAddNodes() {
|
for _, node := range gConf.getAddNodes() {
|
||||||
gLog.Println(LvDEBUG, "deal add node: ", node.Name)
|
gLog.Println(LvDEBUG, "deal add node: ", node.Name)
|
||||||
ipNet := &net.IPNet{
|
ipNet := &net.IPNet{
|
||||||
IP: net.ParseIP(node.IP),
|
IP: net.ParseIP(node.IP),
|
||||||
Mask: s.subnet.Mask,
|
Mask: s.subnet.Mask,
|
||||||
}
|
}
|
||||||
if node.Name == s.nodeName {
|
if node.Name == s.nodeName {
|
||||||
s.virtualIP = ipNet
|
s.virtualIP = ipNet
|
||||||
gLog.Println(LvINFO, "start tun ", ipNet.String())
|
gLog.Println(LvINFO, "start tun ", ipNet.String())
|
||||||
err := s.StartTun()
|
err := s.StartTun()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "start tun error:", err)
|
gLog.Println(LvERROR, "start tun error:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
gLog.Println(LvINFO, "start tun ok")
|
gLog.Println(LvINFO, "start tun ok")
|
||||||
allowTunForward()
|
allowTunForward()
|
||||||
addRoute(s.subnet.String(), s.gateway.String(), s.tun.tunName)
|
addRoute(s.subnet.String(), s.gateway.String(), s.tun.tunName)
|
||||||
// addRoute("255.255.255.255/32", s.gateway.String(), s.tun.tunName) // for broadcast
|
// addRoute("255.255.255.255/32", s.gateway.String(), s.tun.tunName) // for broadcast
|
||||||
// addRoute("224.0.0.0/4", s.gateway.String(), s.tun.tunName) // for multicast
|
// addRoute("224.0.0.0/4", s.gateway.String(), s.tun.tunName) // for multicast
|
||||||
initSNATRule(s.subnet.String()) // for network resource
|
initSNATRule(s.subnet.String()) // for network resource
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ip, err := inetAtoN(ipNet.String())
|
ip, err := inetAtoN(ipNet.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.sysRoute.Store(ip, &sdwanNode{name: node.Name, id: NodeNameToID(node.Name)})
|
s.sysRoute.Store(ip, &sdwanNode{name: node.Name, id: NodeNameToID(node.Name)})
|
||||||
s.internalRoute.AddIntIP(ip, ip, &sdwanNode{name: node.Name, id: NodeNameToID(node.Name)})
|
s.internalRoute.AddIntIP(ip, ip, &sdwanNode{name: node.Name, id: NodeNameToID(node.Name)})
|
||||||
}
|
}
|
||||||
for _, node := range gConf.getAddNodes() {
|
for _, node := range gConf.getAddNodes() {
|
||||||
if node.Name == s.nodeName { // not deal resource itself
|
if node.Name == s.nodeName { // not deal resource itself
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if len(node.Resource) > 0 {
|
if len(node.Resource) > 0 {
|
||||||
gLog.Printf(LvINFO, "deal add node: %s resource: %s", node.Name, node.Resource)
|
gLog.Printf(LvINFO, "deal add node: %s resource: %s", node.Name, node.Resource)
|
||||||
arr := strings.Split(node.Resource, ",")
|
arr := strings.Split(node.Resource, ",")
|
||||||
for _, r := range arr {
|
for _, r := range arr {
|
||||||
// add internal route
|
// add internal route
|
||||||
_, ipnet, err := net.ParseCIDR(r)
|
_, ipnet, err := net.ParseCIDR(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error parsing CIDR:", err)
|
fmt.Println("Error parsing CIDR:", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if ipnet.Contains(net.ParseIP(gConf.Network.localIP)) { // local ip and resource in the same lan
|
if ipnet.Contains(net.ParseIP(gConf.Network.localIP)) { // local ip and resource in the same lan
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
minIP := ipnet.IP
|
minIP := ipnet.IP
|
||||||
maxIP := make(net.IP, len(minIP))
|
maxIP := make(net.IP, len(minIP))
|
||||||
copy(maxIP, minIP)
|
copy(maxIP, minIP)
|
||||||
for i := range minIP {
|
for i := range minIP {
|
||||||
maxIP[i] = minIP[i] | ^ipnet.Mask[i]
|
maxIP[i] = minIP[i] | ^ipnet.Mask[i]
|
||||||
}
|
}
|
||||||
s.internalRoute.Add(minIP.String(), maxIP.String(), &sdwanNode{name: node.Name, id: NodeNameToID(node.Name)})
|
s.internalRoute.Add(minIP.String(), maxIP.String(), &sdwanNode{name: node.Name, id: NodeNameToID(node.Name)})
|
||||||
// add sys route
|
// add sys route
|
||||||
addRoute(ipnet.String(), s.gateway.String(), s.tun.tunName)
|
addRoute(ipnet.String(), s.gateway.String(), s.tun.tunName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gConf.retryAllMemApp()
|
gConf.retryAllMemApp()
|
||||||
gLog.Printf(LvINFO, "sdwan init ok")
|
gLog.Printf(LvINFO, "sdwan init ok")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *p2pSDWAN) run() {
|
func (s *p2pSDWAN) run() {
|
||||||
s.sysRoute.Range(func(key, value interface{}) bool {
|
s.sysRoute.Range(func(key, value interface{}) bool {
|
||||||
node := value.(*sdwanNode)
|
node := value.(*sdwanNode)
|
||||||
GNetwork.ConnectNode(node.name)
|
GNetwork.ConnectNode(node.name)
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *p2pSDWAN) readNodeLoop() {
|
func (s *p2pSDWAN) readNodeLoop() {
|
||||||
gLog.Printf(LvDEBUG, "sdwan readNodeLoop start")
|
gLog.Printf(LvDEBUG, "sdwan readNodeLoop start")
|
||||||
defer gLog.Printf(LvDEBUG, "sdwan readNodeLoop end")
|
defer gLog.Printf(LvDEBUG, "sdwan readNodeLoop end")
|
||||||
writeBuff := make([][]byte, 1)
|
writeBuff := make([][]byte, 1)
|
||||||
for {
|
for {
|
||||||
nd := GNetwork.ReadNode(time.Second * 10) // TODO: read multi packet
|
nd := GNetwork.ReadNode(time.Second * 10) // TODO: read multi packet
|
||||||
if nd == nil {
|
if nd == nil {
|
||||||
gLog.Printf(LvDev, "waiting for node data")
|
gLog.Printf(LvDev, "waiting for node data")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
head := PacketHeader{}
|
head := PacketHeader{}
|
||||||
parseHeader(nd.Data, &head)
|
parseHeader(nd.Data, &head)
|
||||||
gLog.Printf(LvDev, "write tun dst ip=%s,len=%d", net.IP{byte(head.dst >> 24), byte(head.dst >> 16), byte(head.dst >> 8), byte(head.dst)}.String(), len(nd.Data))
|
gLog.Printf(LvDev, "write tun dst ip=%s,len=%d", net.IP{byte(head.dst >> 24), byte(head.dst >> 16), byte(head.dst >> 8), byte(head.dst)}.String(), len(nd.Data))
|
||||||
if PIHeaderSize == 0 {
|
if PIHeaderSize == 0 {
|
||||||
writeBuff[0] = nd.Data
|
writeBuff[0] = nd.Data
|
||||||
} else {
|
} else {
|
||||||
writeBuff[0] = make([]byte, PIHeaderSize+len(nd.Data))
|
writeBuff[0] = make([]byte, PIHeaderSize+len(nd.Data))
|
||||||
copy(writeBuff[0][PIHeaderSize:], nd.Data)
|
copy(writeBuff[0][PIHeaderSize:], nd.Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
len, err := s.tun.Write(writeBuff, PIHeaderSize)
|
len, err := s.tun.Write(writeBuff, PIHeaderSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvDEBUG, "write tun dst ip=%s,len=%d,error:%s", net.IP{byte(head.dst >> 24), byte(head.dst >> 16), byte(head.dst >> 8), byte(head.dst)}.String(), len, err)
|
gLog.Printf(LvDEBUG, "write tun dst ip=%s,len=%d,error:%s", net.IP{byte(head.dst >> 24), byte(head.dst >> 16), byte(head.dst >> 8), byte(head.dst)}.String(), len, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isBroadcastOrMulticast(ipUint32 uint32, subnet *net.IPNet) bool {
|
func isBroadcastOrMulticast(ipUint32 uint32, subnet *net.IPNet) bool {
|
||||||
// return ipUint32 == 0xffffffff || (byte(ipUint32) == 0xff) || (ipUint32>>28 == 0xe)
|
// return ipUint32 == 0xffffffff || (byte(ipUint32) == 0xff) || (ipUint32>>28 == 0xe)
|
||||||
return ipUint32 == 0xffffffff || (ipUint32>>28 == 0xe) // 225.255.255.255/32, 224.0.0.0/4
|
return ipUint32 == 0xffffffff || (ipUint32>>28 == 0xe) // 225.255.255.255/32, 224.0.0.0/4
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *p2pSDWAN) routeTunPacket(p []byte, head *PacketHeader) {
|
func (s *p2pSDWAN) routeTunPacket(p []byte, head *PacketHeader) {
|
||||||
var node *sdwanNode
|
var node *sdwanNode
|
||||||
// v, ok := s.routes.Load(ih.dst)
|
// v, ok := s.routes.Load(ih.dst)
|
||||||
v, ok := s.internalRoute.Load(head.dst)
|
v, ok := s.internalRoute.Load(head.dst)
|
||||||
if !ok || v == nil {
|
if !ok || v == nil {
|
||||||
if isBroadcastOrMulticast(head.dst, s.subnet) {
|
if isBroadcastOrMulticast(head.dst, s.subnet) {
|
||||||
gLog.Printf(LvDev, "multicast ip=%s", net.IP{byte(head.dst >> 24), byte(head.dst >> 16), byte(head.dst >> 8), byte(head.dst)}.String())
|
gLog.Printf(LvDev, "multicast ip=%s", net.IP{byte(head.dst >> 24), byte(head.dst >> 16), byte(head.dst >> 8), byte(head.dst)}.String())
|
||||||
GNetwork.WriteBroadcast(p)
|
GNetwork.WriteBroadcast(p)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
node = v.(*sdwanNode)
|
node = v.(*sdwanNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := GNetwork.WriteNode(node.id, p)
|
err := GNetwork.WriteNode(node.id, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvDev, "write packet to %s fail: %s", node.name, err)
|
gLog.Printf(LvDev, "write packet to %s fail: %s", node.name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *p2pSDWAN) readTunLoop() {
|
func (s *p2pSDWAN) readTunLoop() {
|
||||||
gLog.Printf(LvDEBUG, "sdwan readTunLoop start")
|
gLog.Printf(LvDEBUG, "sdwan readTunLoop start")
|
||||||
defer gLog.Printf(LvDEBUG, "sdwan readTunLoop end")
|
defer gLog.Printf(LvDEBUG, "sdwan readTunLoop end")
|
||||||
readBuff := make([][]byte, ReadTunBuffNum)
|
readBuff := make([][]byte, ReadTunBuffNum)
|
||||||
for i := 0; i < ReadTunBuffNum; i++ {
|
for i := 0; i < ReadTunBuffNum; i++ {
|
||||||
readBuff[i] = make([]byte, ReadTunBuffSize+PIHeaderSize)
|
readBuff[i] = make([]byte, ReadTunBuffSize+PIHeaderSize)
|
||||||
}
|
}
|
||||||
readBuffSize := make([]int, ReadTunBuffNum)
|
readBuffSize := make([]int, ReadTunBuffNum)
|
||||||
ih := PacketHeader{}
|
ih := PacketHeader{}
|
||||||
for {
|
for {
|
||||||
n, err := s.tun.Read(readBuff, readBuffSize, PIHeaderSize)
|
n, err := s.tun.Read(readBuff, readBuffSize, PIHeaderSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvERROR, "read tun fail: ", err)
|
gLog.Printf(LvERROR, "read tun fail: ", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
if readBuffSize[i] > ReadTunBuffSize {
|
if readBuffSize[i] > ReadTunBuffSize {
|
||||||
gLog.Printf(LvERROR, "read tun overflow: len=", readBuffSize[i])
|
gLog.Printf(LvERROR, "read tun overflow: len=", readBuffSize[i])
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
parseHeader(readBuff[i][PIHeaderSize:readBuffSize[i]+PIHeaderSize], &ih)
|
parseHeader(readBuff[i][PIHeaderSize:readBuffSize[i]+PIHeaderSize], &ih)
|
||||||
gLog.Printf(LvDev, "read tun dst ip=%s,len=%d", net.IP{byte(ih.dst >> 24), byte(ih.dst >> 16), byte(ih.dst >> 8), byte(ih.dst)}.String(), readBuffSize[0])
|
gLog.Printf(LvDev, "read tun dst ip=%s,len=%d", net.IP{byte(ih.dst >> 24), byte(ih.dst >> 16), byte(ih.dst >> 8), byte(ih.dst)}.String(), readBuffSize[0])
|
||||||
s.routeTunPacket(readBuff[i][PIHeaderSize:readBuffSize[i]+PIHeaderSize], &ih)
|
s.routeTunPacket(readBuff[i][PIHeaderSize:readBuffSize[i]+PIHeaderSize], &ih)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *p2pSDWAN) StartTun() error {
|
func (s *p2pSDWAN) StartTun() error {
|
||||||
sdwan := gConf.getSDWAN()
|
sdwan := gConf.getSDWAN()
|
||||||
if s.tun == nil {
|
if s.tun == nil {
|
||||||
tun := &optun{}
|
tun := &optun{}
|
||||||
err := tun.Start(s.virtualIP.String(), &sdwan)
|
err := tun.Start(s.virtualIP.String(), &sdwan)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "open tun fail:", err)
|
gLog.Println(LvERROR, "open tun fail:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.tun = tun
|
s.tun = tun
|
||||||
go s.readTunLoop()
|
go s.readTunLoop()
|
||||||
go s.readNodeLoop() // multi-thread read will cause packets out of order, resulting in slower speeds
|
go s.readNodeLoop() // multi-thread read will cause packets out of order, resulting in slower speeds
|
||||||
}
|
}
|
||||||
err := setTunAddr(s.tun.tunName, s.virtualIP.String(), sdwan.Gateway, s.tun.dev)
|
err := setTunAddr(s.tun.tunName, s.virtualIP.String(), sdwan.Gateway, s.tun.dev)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvERROR, "setTunAddr error:%s,%s,%s,%s", err, s.tun.tunName, s.virtualIP.String(), sdwan.Gateway)
|
gLog.Printf(LvERROR, "setTunAddr error:%s,%s,%s,%s", err, s.tun.tunName, s.virtualIP.String(), sdwan.Gateway)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleSDWAN(subType uint16, msg []byte) error {
|
func handleSDWAN(subType uint16, msg []byte) error {
|
||||||
gLog.Printf(LvDEBUG, "handle sdwan msg type:%d", subType)
|
gLog.Printf(LvDEBUG, "handle sdwan msg type:%d", subType)
|
||||||
var err error
|
var err error
|
||||||
switch subType {
|
switch subType {
|
||||||
case MsgSDWANInfoRsp:
|
case MsgSDWANInfoRsp:
|
||||||
rsp := SDWANInfo{}
|
rsp := SDWANInfo{}
|
||||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &rsp); err != nil {
|
if err = json.Unmarshal(msg[openP2PHeaderSize:], &rsp); err != nil {
|
||||||
return ErrMsgFormat
|
return ErrMsgFormat
|
||||||
}
|
}
|
||||||
gLog.Println(LvINFO, "sdwan init:", prettyJson(rsp))
|
gLog.Println(LvINFO, "sdwan init:", prettyJson(rsp))
|
||||||
if runtime.GOOS == "android" {
|
if runtime.GOOS == "android" {
|
||||||
AndroidSDWANConfig <- msg[openP2PHeaderSize:]
|
AndroidSDWANConfig <- msg[openP2PHeaderSize:]
|
||||||
}
|
}
|
||||||
// GNetwork.sdwan.detail = &rsp
|
// GNetwork.sdwan.detail = &rsp
|
||||||
gConf.setSDWAN(rsp)
|
gConf.setSDWAN(rsp)
|
||||||
err = GNetwork.sdwan.init(gConf.Network.Node)
|
err = GNetwork.sdwan.init(gConf.Network.Node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "sdwan init fail: ", err)
|
gLog.Println(LvERROR, "sdwan init fail: ", err)
|
||||||
if GNetwork.sdwan.tun != nil {
|
if GNetwork.sdwan.tun != nil {
|
||||||
GNetwork.sdwan.tun.Stop()
|
GNetwork.sdwan.tun.Stop()
|
||||||
GNetwork.sdwan.tun = nil
|
GNetwork.sdwan.tun = nil
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
go GNetwork.sdwan.run()
|
go GNetwork.sdwan.run()
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+239
-239
@@ -1,239 +1,239 @@
|
|||||||
package openp2p
|
package openp2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
"archive/zip"
|
"archive/zip"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func update(host string, port int) error {
|
func update(host string, port int) error {
|
||||||
gLog.Println(LvINFO, "update start")
|
gLog.Println(LvINFO, "update start")
|
||||||
defer gLog.Println(LvINFO, "update end")
|
defer gLog.Println(LvINFO, "update end")
|
||||||
caCertPool, err := x509.SystemCertPool()
|
caCertPool, err := x509.SystemCertPool()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "Failed to load system root CAs:", err)
|
gLog.Println(LvERROR, "Failed to load system root CAs:", err)
|
||||||
} else {
|
} else {
|
||||||
caCertPool = x509.NewCertPool()
|
caCertPool = x509.NewCertPool()
|
||||||
}
|
}
|
||||||
caCertPool.AppendCertsFromPEM([]byte(rootCA))
|
caCertPool.AppendCertsFromPEM([]byte(rootCA))
|
||||||
caCertPool.AppendCertsFromPEM([]byte(ISRGRootX1))
|
caCertPool.AppendCertsFromPEM([]byte(ISRGRootX1))
|
||||||
|
|
||||||
c := http.Client{
|
c := http.Client{
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{RootCAs: caCertPool,
|
TLSClientConfig: &tls.Config{RootCAs: caCertPool,
|
||||||
InsecureSkipVerify: false},
|
InsecureSkipVerify: false},
|
||||||
},
|
},
|
||||||
Timeout: time.Second * 30,
|
Timeout: time.Second * 30,
|
||||||
}
|
}
|
||||||
goos := runtime.GOOS
|
goos := runtime.GOOS
|
||||||
goarch := runtime.GOARCH
|
goarch := runtime.GOARCH
|
||||||
rsp, err := c.Get(fmt.Sprintf("https://%s:%d/api/v1/update?fromver=%s&os=%s&arch=%s&user=%s&node=%s", host, port, OpenP2PVersion, goos, goarch, url.QueryEscape(gConf.Network.User), url.QueryEscape(gConf.Network.Node)))
|
rsp, err := c.Get(fmt.Sprintf("https://%s:%d/api/v1/update?fromver=%s&os=%s&arch=%s&user=%s&node=%s", host, port, OpenP2PVersion, goos, goarch, url.QueryEscape(gConf.Network.User), url.QueryEscape(gConf.Network.Node)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "update:query update list failed:", err)
|
gLog.Println(LvERROR, "update:query update list failed:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer rsp.Body.Close()
|
defer rsp.Body.Close()
|
||||||
if rsp.StatusCode != http.StatusOK {
|
if rsp.StatusCode != http.StatusOK {
|
||||||
gLog.Println(LvERROR, "get update info error:", rsp.Status)
|
gLog.Println(LvERROR, "get update info error:", rsp.Status)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rspBuf, err := ioutil.ReadAll(rsp.Body)
|
rspBuf, err := ioutil.ReadAll(rsp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "update:read update list failed:", err)
|
gLog.Println(LvERROR, "update:read update list failed:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
updateInfo := UpdateInfo{}
|
updateInfo := UpdateInfo{}
|
||||||
if err = json.Unmarshal(rspBuf, &updateInfo); err != nil {
|
if err = json.Unmarshal(rspBuf, &updateInfo); err != nil {
|
||||||
gLog.Println(LvERROR, rspBuf, " update info decode error:", err)
|
gLog.Println(LvERROR, rspBuf, " update info decode error:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if updateInfo.Error != 0 {
|
if updateInfo.Error != 0 {
|
||||||
gLog.Println(LvERROR, "update error:", updateInfo.Error, updateInfo.ErrorDetail)
|
gLog.Println(LvERROR, "update error:", updateInfo.Error, updateInfo.ErrorDetail)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = updateFile(updateInfo.Url, "", "openp2p")
|
err = updateFile(updateInfo.Url, "", "openp2p")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "update: download failed:", err)
|
gLog.Println(LvERROR, "update: download failed:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func downloadFile(url string, checksum string, dstFile string) error {
|
func downloadFile(url string, checksum string, dstFile string) error {
|
||||||
output, err := os.OpenFile(dstFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0776)
|
output, err := os.OpenFile(dstFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0776)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvERROR, "OpenFile %s error:%s", dstFile, err)
|
gLog.Printf(LvERROR, "OpenFile %s error:%s", dstFile, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
caCertPool, err := x509.SystemCertPool()
|
caCertPool, err := x509.SystemCertPool()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Println(LvERROR, "Failed to load system root CAs:", err)
|
gLog.Println(LvERROR, "Failed to load system root CAs:", err)
|
||||||
} else {
|
} else {
|
||||||
caCertPool = x509.NewCertPool()
|
caCertPool = x509.NewCertPool()
|
||||||
}
|
}
|
||||||
caCertPool.AppendCertsFromPEM([]byte(rootCA))
|
caCertPool.AppendCertsFromPEM([]byte(rootCA))
|
||||||
caCertPool.AppendCertsFromPEM([]byte(ISRGRootX1))
|
caCertPool.AppendCertsFromPEM([]byte(ISRGRootX1))
|
||||||
tr := &http.Transport{
|
tr := &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{
|
TLSClientConfig: &tls.Config{
|
||||||
RootCAs: caCertPool,
|
RootCAs: caCertPool,
|
||||||
InsecureSkipVerify: false},
|
InsecureSkipVerify: false},
|
||||||
}
|
}
|
||||||
client := &http.Client{Transport: tr}
|
client := &http.Client{Transport: tr}
|
||||||
response, err := client.Get(url)
|
response, err := client.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvERROR, "download url %s error:%s", url, err)
|
gLog.Printf(LvERROR, "download url %s error:%s", url, err)
|
||||||
output.Close()
|
output.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
n, err := io.Copy(output, response.Body)
|
n, err := io.Copy(output, response.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvERROR, "io.Copy error:%s", err)
|
gLog.Printf(LvERROR, "io.Copy error:%s", err)
|
||||||
output.Close()
|
output.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
output.Sync()
|
output.Sync()
|
||||||
output.Close()
|
output.Close()
|
||||||
gLog.Println(LvINFO, "download ", url, " ok")
|
gLog.Println(LvINFO, "download ", url, " ok")
|
||||||
gLog.Printf(LvINFO, "size: %d bytes", n)
|
gLog.Printf(LvINFO, "size: %d bytes", n)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateFile(url string, checksum string, dst string) error {
|
func updateFile(url string, checksum string, dst string) error {
|
||||||
gLog.Println(LvINFO, "download ", url)
|
gLog.Println(LvINFO, "download ", url)
|
||||||
tmpFile := filepath.Dir(os.Args[0]) + "/openp2p.tmp"
|
tmpFile := filepath.Dir(os.Args[0]) + "/openp2p.tmp"
|
||||||
err := downloadFile(url, checksum, tmpFile)
|
err := downloadFile(url, checksum, tmpFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
backupFile := os.Args[0] + "0"
|
backupFile := os.Args[0] + "0"
|
||||||
err = os.Rename(os.Args[0], backupFile) // the old daemon process was using the 0 file, so it will prevent override it
|
err = os.Rename(os.Args[0], backupFile) // the old daemon process was using the 0 file, so it will prevent override it
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvINFO, " rename %s error:%s, retry 1", os.Args[0], err)
|
gLog.Printf(LvINFO, " rename %s error:%s, retry 1", os.Args[0], err)
|
||||||
backupFile = os.Args[0] + "1"
|
backupFile = os.Args[0] + "1"
|
||||||
err = os.Rename(os.Args[0], backupFile)
|
err = os.Rename(os.Args[0], backupFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvINFO, " rename %s error:%s", os.Args[0], err)
|
gLog.Printf(LvINFO, " rename %s error:%s", os.Args[0], err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// extract
|
// extract
|
||||||
gLog.Println(LvINFO, "extract files")
|
gLog.Println(LvINFO, "extract files")
|
||||||
err = extract(filepath.Dir(os.Args[0]), tmpFile)
|
err = extract(filepath.Dir(os.Args[0]), tmpFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gLog.Printf(LvERROR, "extract error:%s. revert rename", err)
|
gLog.Printf(LvERROR, "extract error:%s. revert rename", err)
|
||||||
os.Rename(backupFile, os.Args[0])
|
os.Rename(backupFile, os.Args[0])
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
os.Remove(tmpFile)
|
os.Remove(tmpFile)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func extract(dst, src string) (err error) {
|
func extract(dst, src string) (err error) {
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
return unzip(dst, src)
|
return unzip(dst, src)
|
||||||
} else {
|
} else {
|
||||||
return extractTgz(dst, src)
|
return extractTgz(dst, src)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func unzip(dst, src string) (err error) {
|
func unzip(dst, src string) (err error) {
|
||||||
archive, err := zip.OpenReader(src)
|
archive, err := zip.OpenReader(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer archive.Close()
|
defer archive.Close()
|
||||||
|
|
||||||
for _, f := range archive.File {
|
for _, f := range archive.File {
|
||||||
filePath := filepath.Join(dst, f.Name)
|
filePath := filepath.Join(dst, f.Name)
|
||||||
fmt.Println("unzipping file ", filePath)
|
fmt.Println("unzipping file ", filePath)
|
||||||
if f.FileInfo().IsDir() {
|
if f.FileInfo().IsDir() {
|
||||||
fmt.Println("creating directory...")
|
fmt.Println("creating directory...")
|
||||||
os.MkdirAll(filePath, os.ModePerm)
|
os.MkdirAll(filePath, os.ModePerm)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
|
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fileInArchive, err := f.Open()
|
fileInArchive, err := f.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := io.Copy(dstFile, fileInArchive); err != nil {
|
if _, err := io.Copy(dstFile, fileInArchive); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
dstFile.Close()
|
dstFile.Close()
|
||||||
fileInArchive.Close()
|
fileInArchive.Close()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractTgz(dst, src string) error {
|
func extractTgz(dst, src string) error {
|
||||||
gzipStream, err := os.Open(src)
|
gzipStream, err := os.Open(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
uncompressedStream, err := gzip.NewReader(gzipStream)
|
uncompressedStream, err := gzip.NewReader(gzipStream)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tarReader := tar.NewReader(uncompressedStream)
|
tarReader := tar.NewReader(uncompressedStream)
|
||||||
for {
|
for {
|
||||||
header, err := tarReader.Next()
|
header, err := tarReader.Next()
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
switch header.Typeflag {
|
switch header.Typeflag {
|
||||||
case tar.TypeDir:
|
case tar.TypeDir:
|
||||||
if err := os.Mkdir(header.Name, 0755); err != nil {
|
if err := os.Mkdir(header.Name, 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case tar.TypeReg:
|
case tar.TypeReg:
|
||||||
filePath := filepath.Join(dst, header.Name)
|
filePath := filepath.Join(dst, header.Name)
|
||||||
outFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(header.Mode))
|
outFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(header.Mode))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer outFile.Close()
|
defer outFile.Close()
|
||||||
if _, err := io.Copy(outFile, tarReader); err != nil {
|
if _, err := io.Copy(outFile, tarReader); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanTempFiles() {
|
func cleanTempFiles() {
|
||||||
tmpFile := os.Args[0] + "0"
|
tmpFile := os.Args[0] + "0"
|
||||||
if _, err := os.Stat(tmpFile); err == nil {
|
if _, err := os.Stat(tmpFile); err == nil {
|
||||||
if err := os.Remove(tmpFile); err != nil {
|
if err := os.Remove(tmpFile); err != nil {
|
||||||
gLog.Printf(LvDEBUG, " remove %s error:%s", tmpFile, err)
|
gLog.Printf(LvDEBUG, " remove %s error:%s", tmpFile, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tmpFile = os.Args[0] + "1"
|
tmpFile = os.Args[0] + "1"
|
||||||
if _, err := os.Stat(tmpFile); err == nil {
|
if _, err := os.Stat(tmpFile); err == nil {
|
||||||
if err := os.Remove(tmpFile); err != nil {
|
if err := os.Remove(tmpFile); err != nil {
|
||||||
gLog.Printf(LvDEBUG, " remove %s error:%s", tmpFile, err)
|
gLog.Printf(LvDEBUG, " remove %s error:%s", tmpFile, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-14
@@ -1,14 +1,18 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
// On Windows env
|
||||||
op "openp2p/core"
|
// cd lib
|
||||||
)
|
// go build -o openp2p.dll -buildmode=c-shared openp2p.go
|
||||||
import "C"
|
// caller example see example/dll
|
||||||
|
import (
|
||||||
func main() {
|
op "openp2p/core"
|
||||||
}
|
)
|
||||||
|
import "C"
|
||||||
//export RunCmd
|
|
||||||
func RunCmd(cmd *C.char) {
|
func main() {
|
||||||
op.RunCmd(C.GoString(cmd))
|
}
|
||||||
}
|
|
||||||
|
//export RunCmd
|
||||||
|
func RunCmd(cmd *C.char) {
|
||||||
|
op.RunCmd(C.GoString(cmd))
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user