support andoird
This commit is contained in:
@@ -0,0 +1,282 @@
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
|
||||
pushHead := PushHeader{}
|
||||
err := binary.Read(bytes.NewReader(msg[openP2PHeaderSize:openP2PHeaderSize+PushHeaderSize]), binary.LittleEndian, &pushHead)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gLog.Printf(LvDEBUG, "handle push msg type:%d, push header:%+v", subType, pushHead)
|
||||
switch subType {
|
||||
case MsgPushConnectReq: // TODO: handle a msg move to a new function
|
||||
req := PushConnectReq{}
|
||||
err := json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "wrong MsgPushConnectReq:%s", err)
|
||||
return err
|
||||
}
|
||||
gLog.Printf(LvINFO, "%s is connecting...", req.From)
|
||||
gLog.Println(LvDEBUG, "push connect response to ", req.From)
|
||||
if compareVersion(req.Version, LeastSupportVersion) == LESS {
|
||||
gLog.Println(LvERROR, ErrVersionNotCompatible.Error(), ":", req.From)
|
||||
rsp := PushConnectRsp{
|
||||
Error: 10,
|
||||
Detail: ErrVersionNotCompatible.Error(),
|
||||
To: req.From,
|
||||
From: pn.config.Node,
|
||||
}
|
||||
pn.push(req.From, MsgPushConnectRsp, rsp)
|
||||
return ErrVersionNotCompatible
|
||||
}
|
||||
// verify totp token or token
|
||||
if VerifyTOTP(req.Token, pn.config.Token, time.Now().Unix()+(pn.serverTs-pn.localTs)) || // localTs may behind, auto adjust ts
|
||||
VerifyTOTP(req.Token, pn.config.Token, time.Now().Unix()) {
|
||||
gLog.Printf(LvINFO, "Access Granted\n")
|
||||
config := AppConfig{}
|
||||
config.peerNatType = req.NatType
|
||||
config.peerConeNatPort = req.ConeNatPort
|
||||
config.peerIP = req.FromIP
|
||||
config.PeerNode = req.From
|
||||
config.peerVersion = req.Version
|
||||
config.fromToken = req.Token
|
||||
config.peerIPv6 = req.IPv6
|
||||
config.hasIPv4 = req.HasIPv4
|
||||
config.hasUPNPorNATPMP = req.HasUPNPorNATPMP
|
||||
config.linkMode = req.LinkMode
|
||||
config.isUnderlayServer = req.IsUnderlayServer
|
||||
// share relay node will limit bandwidth
|
||||
if req.Token != pn.config.Token {
|
||||
gLog.Printf(LvINFO, "set share bandwidth %d mbps", pn.config.ShareBandwidth)
|
||||
config.shareBandwidth = pn.config.ShareBandwidth
|
||||
}
|
||||
// go pn.AddTunnel(config, req.ID)
|
||||
go pn.addDirectTunnel(config, req.ID)
|
||||
break
|
||||
}
|
||||
gLog.Println(LvERROR, "Access Denied:", req.From)
|
||||
rsp := PushConnectRsp{
|
||||
Error: 1,
|
||||
Detail: fmt.Sprintf("connect to %s error: Access Denied", pn.config.Node),
|
||||
To: req.From,
|
||||
From: pn.config.Node,
|
||||
}
|
||||
pn.push(req.From, MsgPushConnectRsp, rsp)
|
||||
case MsgPushRsp:
|
||||
rsp := PushRsp{}
|
||||
err := json.Unmarshal(msg[openP2PHeaderSize:], &rsp)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "wrong pushRsp:%s", err)
|
||||
return err
|
||||
}
|
||||
if rsp.Error == 0 {
|
||||
gLog.Printf(LvDEBUG, "push ok, detail:%s", rsp.Detail)
|
||||
} else {
|
||||
gLog.Printf(LvERROR, "push error:%d, detail:%s", rsp.Error, rsp.Detail)
|
||||
}
|
||||
case MsgPushAddRelayTunnelReq:
|
||||
req := AddRelayTunnelReq{}
|
||||
err := json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "wrong RelayNodeRsp:%s", err)
|
||||
return err
|
||||
}
|
||||
config := AppConfig{}
|
||||
config.PeerNode = req.RelayName
|
||||
config.peerToken = req.RelayToken
|
||||
go func(r AddRelayTunnelReq) {
|
||||
t, errDt := pn.addDirectTunnel(config, 0)
|
||||
if errDt == nil {
|
||||
// notify peer relay ready
|
||||
msg := TunnelMsg{ID: t.id}
|
||||
pn.push(r.From, MsgPushAddRelayTunnelRsp, msg)
|
||||
}
|
||||
|
||||
}(req)
|
||||
case MsgPushAPPKey:
|
||||
req := APPKeySync{}
|
||||
err := json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "wrong APPKeySync:%s", err)
|
||||
return err
|
||||
}
|
||||
SaveKey(req.AppID, req.AppKey)
|
||||
case MsgPushUpdate:
|
||||
gLog.Println(LvINFO, "MsgPushUpdate")
|
||||
update(pn.config.ServerHost, pn.config.ServerPort) // download new version first, then exec ./openp2p update
|
||||
targetPath := filepath.Join(defaultInstallPath, defaultBinName)
|
||||
args := []string{"update"}
|
||||
env := os.Environ()
|
||||
cmd := exec.Command(targetPath, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Env = env
|
||||
err := cmd.Run()
|
||||
if err == nil {
|
||||
os.Exit(0)
|
||||
}
|
||||
return err
|
||||
case MsgPushRestart:
|
||||
gLog.Println(LvINFO, "MsgPushRestart")
|
||||
os.Exit(0)
|
||||
return err
|
||||
case MsgPushReportApps:
|
||||
gLog.Println(LvINFO, "MsgPushReportApps")
|
||||
req := ReportApps{}
|
||||
gConf.mtx.Lock()
|
||||
defer gConf.mtx.Unlock()
|
||||
for _, config := range gConf.Apps {
|
||||
appActive := 0
|
||||
relayNode := ""
|
||||
relayMode := ""
|
||||
linkMode := LinkModeUDPPunch
|
||||
i, ok := pn.apps.Load(fmt.Sprintf("%s%d", config.Protocol, config.SrcPort))
|
||||
if ok {
|
||||
app := i.(*p2pApp)
|
||||
if app.isActive() {
|
||||
appActive = 1
|
||||
}
|
||||
relayNode = app.relayNode
|
||||
relayMode = app.relayMode
|
||||
linkMode = app.tunnel.linkModeWeb
|
||||
}
|
||||
appInfo := AppInfo{
|
||||
AppName: config.AppName,
|
||||
Error: config.errMsg,
|
||||
Protocol: config.Protocol,
|
||||
SrcPort: config.SrcPort,
|
||||
RelayNode: relayNode,
|
||||
RelayMode: relayMode,
|
||||
LinkMode: linkMode,
|
||||
PeerNode: config.PeerNode,
|
||||
DstHost: config.DstHost,
|
||||
DstPort: config.DstPort,
|
||||
PeerUser: config.PeerUser,
|
||||
PeerIP: config.peerIP,
|
||||
PeerNatType: config.peerNatType,
|
||||
RetryTime: config.retryTime.Local().Format("2006-01-02T15:04:05-0700"),
|
||||
ConnectTime: config.connectTime.Local().Format("2006-01-02T15:04:05-0700"),
|
||||
IsActive: appActive,
|
||||
Enabled: config.Enabled,
|
||||
}
|
||||
req.Apps = append(req.Apps, appInfo)
|
||||
}
|
||||
pn.write(MsgReport, MsgReportApps, &req)
|
||||
case MsgPushReportLog:
|
||||
gLog.Println(LvINFO, "MsgPushReportLog")
|
||||
req := ReportLogReq{}
|
||||
err := json.Unmarshal(msg[openP2PHeaderSize:], &req)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "wrong MsgPushReportLog:%s %s", err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
if req.FileName == "" {
|
||||
req.FileName = "openp2p.log"
|
||||
}
|
||||
f, err := os.Open(filepath.Join("log", req.FileName))
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "read log file error:", err)
|
||||
break
|
||||
}
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if req.Offset == 0 && fi.Size() > 4096 {
|
||||
req.Offset = fi.Size() - 4096
|
||||
}
|
||||
if req.Len <= 0 {
|
||||
req.Len = 4096
|
||||
}
|
||||
f.Seek(req.Offset, 0)
|
||||
if req.Len > 1024*1024 { // too large
|
||||
break
|
||||
}
|
||||
buff := make([]byte, req.Len)
|
||||
readLength, err := f.Read(buff)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "read log content error:", err)
|
||||
break
|
||||
}
|
||||
rsp := ReportLogRsp{}
|
||||
rsp.Content = string(buff[:readLength])
|
||||
rsp.FileName = req.FileName
|
||||
rsp.Total = fi.Size()
|
||||
rsp.Len = req.Len
|
||||
pn.write(MsgReport, MsgPushReportLog, &rsp)
|
||||
case MsgPushEditApp:
|
||||
gLog.Println(LvINFO, "MsgPushEditApp")
|
||||
newApp := AppInfo{}
|
||||
err := json.Unmarshal(msg[openP2PHeaderSize:], &newApp)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "wrong MsgPushEditApp:%s %s", err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
oldConf := AppConfig{Enabled: 1}
|
||||
// protocol0+srcPort0 exist, delApp
|
||||
oldConf.AppName = newApp.AppName
|
||||
oldConf.Protocol = newApp.Protocol0
|
||||
oldConf.SrcPort = newApp.SrcPort0
|
||||
oldConf.PeerNode = newApp.PeerNode
|
||||
oldConf.DstHost = newApp.DstHost
|
||||
oldConf.DstPort = newApp.DstPort
|
||||
|
||||
gConf.delete(oldConf)
|
||||
// AddApp
|
||||
newConf := oldConf
|
||||
newConf.Protocol = newApp.Protocol
|
||||
newConf.SrcPort = newApp.SrcPort
|
||||
gConf.add(newConf, false)
|
||||
gConf.save() // save quickly for the next request reportApplist
|
||||
pn.DeleteApp(oldConf) // DeleteApp may cost some times, execute at the end
|
||||
// autoReconnect will auto AddApp
|
||||
// pn.AddApp(config)
|
||||
// TODO: report result
|
||||
case MsgPushEditNode:
|
||||
gLog.Println(LvINFO, "MsgPushEditNode")
|
||||
req := EditNode{}
|
||||
err := json.Unmarshal(msg[openP2PHeaderSize:], &req)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "wrong MsgPushEditNode:%s %s", err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
gConf.setNode(req.NewName)
|
||||
gConf.setShareBandwidth(req.Bandwidth)
|
||||
gConf.save()
|
||||
// TODO: hot reload
|
||||
os.Exit(0)
|
||||
case MsgPushSwitchApp:
|
||||
gLog.Println(LvINFO, "MsgPushSwitchApp")
|
||||
app := AppInfo{}
|
||||
err := json.Unmarshal(msg[openP2PHeaderSize:], &app)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "wrong MsgPushSwitchApp:%s %s", err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
config := AppConfig{Enabled: app.Enabled, SrcPort: app.SrcPort, Protocol: app.Protocol}
|
||||
gLog.Println(LvINFO, app.AppName, " switch to ", app.Enabled)
|
||||
gConf.switchApp(config, app.Enabled)
|
||||
if app.Enabled == 0 {
|
||||
// disable APP
|
||||
pn.DeleteApp(config)
|
||||
}
|
||||
default:
|
||||
pn.msgMapMtx.Lock()
|
||||
ch := pn.msgMap[pushHead.From]
|
||||
pn.msgMapMtx.Unlock()
|
||||
ch <- msg
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user