3.18.4 virtual private network
This commit is contained in:
+319
-106
@@ -10,48 +10,55 @@ import (
|
||||
"net"
|
||||
"reflect"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
const WriteDataChanSize int = 3000
|
||||
|
||||
var buildTunnelMtx sync.Mutex
|
||||
|
||||
type P2PTunnel struct {
|
||||
pn *P2PNetwork
|
||||
conn underlay
|
||||
hbTime time.Time
|
||||
hbMtx sync.Mutex
|
||||
config AppConfig
|
||||
la *net.UDPAddr // local hole address
|
||||
ra *net.UDPAddr // remote hole address
|
||||
overlayConns sync.Map // both TCP and UDP
|
||||
id uint64
|
||||
running bool
|
||||
runMtx sync.Mutex
|
||||
tunnelServer bool // different from underlayServer
|
||||
coneLocalPort int
|
||||
coneNatPort int
|
||||
linkModeWeb string // use config.linkmode
|
||||
punchTs uint64
|
||||
pn *P2PNetwork
|
||||
conn underlay
|
||||
hbTime time.Time
|
||||
hbMtx sync.Mutex
|
||||
config AppConfig
|
||||
la *net.UDPAddr // local hole address
|
||||
ra *net.UDPAddr // remote hole address
|
||||
overlayConns sync.Map // both TCP and UDP
|
||||
id uint64 // client side alloc rand.uint64 = server side
|
||||
running bool
|
||||
runMtx sync.Mutex
|
||||
tunnelServer bool // different from underlayServer
|
||||
coneLocalPort int
|
||||
coneNatPort int
|
||||
linkModeWeb string // use config.linkmode
|
||||
punchTs uint64
|
||||
writeData chan []byte
|
||||
writeDataSmall chan []byte
|
||||
}
|
||||
|
||||
func (t *P2PTunnel) initPort() {
|
||||
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
|
||||
if t.config.linkMode == LinkModeTCP6 || t.config.linkMode == LinkModeTCP4 {
|
||||
t.coneLocalPort = t.pn.config.TCPPort
|
||||
t.coneNatPort = t.pn.config.TCPPort // symmetric doesn't need coneNatPort
|
||||
if t.config.linkMode == LinkModeTCP6 || t.config.linkMode == LinkModeTCP4 || t.config.linkMode == LinkModeIntranet {
|
||||
t.coneLocalPort = gConf.Network.TCPPort
|
||||
t.coneNatPort = gConf.Network.TCPPort // symmetric doesn't need coneNatPort
|
||||
}
|
||||
if t.config.linkMode == LinkModeUDPPunch {
|
||||
// prepare one random cone hole manually
|
||||
_, natPort, _ := natTest(t.pn.config.ServerHost, t.pn.config.UDPPort1, localPort)
|
||||
_, natPort, _ := natTest(gConf.Network.ServerHost, gConf.Network.UDPPort1, localPort)
|
||||
t.coneLocalPort = localPort
|
||||
t.coneNatPort = natPort
|
||||
}
|
||||
if t.config.linkMode == LinkModeTCPPunch {
|
||||
// prepare one random cone hole by system automatically
|
||||
_, natPort, localPort2 := natTCP(t.pn.config.ServerHost, IfconfigPort1)
|
||||
_, natPort, localPort2 := natTCP(gConf.Network.ServerHost, IfconfigPort1)
|
||||
t.coneLocalPort = localPort2
|
||||
t.coneNatPort = natPort
|
||||
}
|
||||
t.la = &net.UDPAddr{IP: net.ParseIP(t.pn.config.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)
|
||||
}
|
||||
|
||||
@@ -61,21 +68,22 @@ func (t *P2PTunnel) connect() error {
|
||||
appKey := uint64(0)
|
||||
req := PushConnectReq{
|
||||
Token: t.config.peerToken,
|
||||
From: t.pn.config.Node,
|
||||
FromIP: t.pn.config.publicIP,
|
||||
From: gConf.Network.Node,
|
||||
FromIP: gConf.Network.publicIP,
|
||||
ConeNatPort: t.coneNatPort,
|
||||
NatType: t.pn.config.natType,
|
||||
HasIPv4: t.pn.config.hasIPv4,
|
||||
NatType: gConf.Network.natType,
|
||||
HasIPv4: gConf.Network.hasIPv4,
|
||||
IPv6: gConf.IPv6(),
|
||||
HasUPNPorNATPMP: t.pn.config.hasUPNPorNATPMP,
|
||||
HasUPNPorNATPMP: gConf.Network.hasUPNPorNATPMP,
|
||||
ID: t.id,
|
||||
AppKey: appKey,
|
||||
Version: OpenP2PVersion,
|
||||
LinkMode: t.config.linkMode,
|
||||
IsUnderlayServer: t.config.isUnderlayServer ^ 1, // peer
|
||||
UnderlayProtocol: t.config.UnderlayProtocol,
|
||||
}
|
||||
if req.Token == 0 { // no relay token
|
||||
req.Token = t.pn.config.Token
|
||||
req.Token = gConf.Network.Token
|
||||
}
|
||||
t.pn.push(t.config.PeerNode, MsgPushConnectReq, req)
|
||||
head, body := t.pn.read(t.config.PeerNode, MsgPush, MsgPushConnectRsp, UnderlayConnectTimeout*3)
|
||||
@@ -102,7 +110,6 @@ func (t *P2PTunnel) connect() error {
|
||||
err := t.start()
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "handshake error:", err)
|
||||
err = ErrorHandshake
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -125,7 +132,11 @@ func (t *P2PTunnel) isActive() bool {
|
||||
}
|
||||
t.hbMtx.Lock()
|
||||
defer t.hbMtx.Unlock()
|
||||
return time.Now().Before(t.hbTime.Add(TunnelHeartbeatTime * 2))
|
||||
res := time.Now().Before(t.hbTime.Add(TunnelHeartbeatTime * 2))
|
||||
if !res {
|
||||
gLog.Printf(LvDEBUG, "%d tunnel isActive false", t.id)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (t *P2PTunnel) checkActive() bool {
|
||||
@@ -150,8 +161,16 @@ func (t *P2PTunnel) checkActive() bool {
|
||||
|
||||
// call when user delete tunnel
|
||||
func (t *P2PTunnel) close() {
|
||||
t.pn.NotifyTunnelClose(t)
|
||||
if !t.running {
|
||||
return
|
||||
}
|
||||
t.setRun(false)
|
||||
if t.conn != nil {
|
||||
t.conn.Close()
|
||||
}
|
||||
t.pn.allTunnels.Delete(t.id)
|
||||
gLog.Printf(LvINFO, "%d p2ptunnel close %s ", t.id, t.config.PeerNode)
|
||||
}
|
||||
|
||||
func (t *P2PTunnel) start() error {
|
||||
@@ -176,23 +195,26 @@ func (t *P2PTunnel) handshake() error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if compareVersion(t.config.peerVersion, SyncServerTimeVersion) == LESS {
|
||||
if compareVersion(t.config.peerVersion, SyncServerTimeVersion) < 0 {
|
||||
gLog.Printf(LvDEBUG, "peer version %s less than %s", t.config.peerVersion, SyncServerTimeVersion)
|
||||
} 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())
|
||||
if ts > PunchTsDelay || ts < 0 {
|
||||
ts = PunchTsDelay
|
||||
}
|
||||
gLog.Printf(LvDEBUG, "sleep %d ms", ts/time.Millisecond)
|
||||
time.Sleep(ts)
|
||||
}
|
||||
gLog.Println(LvDEBUG, "handshake to ", t.config.PeerNode)
|
||||
var err error
|
||||
if t.pn.config.natType == NATCone && t.config.peerNatType == NATCone {
|
||||
if gConf.Network.natType == NATCone && t.config.peerNatType == NATCone {
|
||||
err = handshakeC2C(t)
|
||||
} else if t.config.peerNatType == NATSymmetric && t.pn.config.natType == NATSymmetric {
|
||||
} else if t.config.peerNatType == NATSymmetric && gConf.Network.natType == NATSymmetric {
|
||||
err = ErrorS2S
|
||||
t.close()
|
||||
} else if t.config.peerNatType == NATSymmetric && t.pn.config.natType == NATCone {
|
||||
} else if t.config.peerNatType == NATSymmetric && gConf.Network.natType == NATCone {
|
||||
err = handshakeC2S(t)
|
||||
} else if t.config.peerNatType == NATCone && t.pn.config.natType == NATSymmetric {
|
||||
} else if t.config.peerNatType == NATCone && gConf.Network.natType == NATSymmetric {
|
||||
err = handshakeS2C(t)
|
||||
} else {
|
||||
return errors.New("unknown error")
|
||||
@@ -212,9 +234,15 @@ func (t *P2PTunnel) connectUnderlay() (err error) {
|
||||
case LinkModeTCP4:
|
||||
t.conn, err = t.connectUnderlayTCP()
|
||||
case LinkModeTCPPunch:
|
||||
if gConf.Network.natType == NATSymmetric || t.config.peerNatType == NATSymmetric {
|
||||
t.conn, err = t.connectUnderlayTCPSymmetric()
|
||||
} else {
|
||||
t.conn, err = t.connectUnderlayTCP()
|
||||
}
|
||||
case LinkModeIntranet:
|
||||
t.conn, err = t.connectUnderlayTCP()
|
||||
case LinkModeUDPPunch:
|
||||
t.conn, err = t.connectUnderlayQuic()
|
||||
t.conn, err = t.connectUnderlayUDP()
|
||||
|
||||
}
|
||||
if err != nil {
|
||||
@@ -225,59 +253,70 @@ func (t *P2PTunnel) connectUnderlay() (err error) {
|
||||
}
|
||||
t.setRun(true)
|
||||
go t.readLoop()
|
||||
go t.heartbeatLoop()
|
||||
go t.writeLoop()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *P2PTunnel) connectUnderlayQuic() (c underlay, err error) {
|
||||
gLog.Println(LvINFO, "connectUnderlayQuic start")
|
||||
defer gLog.Println(LvINFO, "connectUnderlayQuic end")
|
||||
var ul *underlayQUIC
|
||||
func (t *P2PTunnel) connectUnderlayUDP() (c underlay, err error) {
|
||||
gLog.Printf(LvDEBUG, "connectUnderlayUDP %s start ", t.config.PeerNode)
|
||||
defer gLog.Printf(LvDEBUG, "connectUnderlayUDP %s end ", t.config.PeerNode)
|
||||
var ul underlay
|
||||
underlayProtocol := t.config.UnderlayProtocol
|
||||
if underlayProtocol == "" {
|
||||
underlayProtocol = "quic"
|
||||
}
|
||||
if t.config.isUnderlayServer == 1 {
|
||||
time.Sleep(time.Millisecond * 10) // punching udp port will need some times in some env
|
||||
ul, err = listenQuic(t.la.String(), TunnelIdleTimeout)
|
||||
if err != nil {
|
||||
gLog.Println(LvINFO, "listen quic error:", err, ", retry...")
|
||||
go t.pn.push(t.config.PeerNode, MsgPushUnderlayConnect, nil)
|
||||
if t.config.UnderlayProtocol == "kcp" {
|
||||
ul, err = listenKCP(t.la.String(), TunnelIdleTimeout)
|
||||
} else {
|
||||
ul, err = listenQuic(t.la.String(), TunnelIdleTimeout)
|
||||
}
|
||||
t.pn.push(t.config.PeerNode, MsgPushUnderlayConnect, nil)
|
||||
err = ul.Accept()
|
||||
|
||||
if err != nil {
|
||||
ul.CloseListener()
|
||||
return nil, fmt.Errorf("accept quic error:%s", err)
|
||||
gLog.Printf(LvINFO, "listen %s error:%s", underlayProtocol, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, buff, err := ul.ReadBuffer()
|
||||
if err != nil {
|
||||
ul.listener.Close()
|
||||
ul.Close()
|
||||
return nil, fmt.Errorf("read start msg error:%s", err)
|
||||
}
|
||||
if buff != nil {
|
||||
gLog.Println(LvDEBUG, string(buff))
|
||||
}
|
||||
ul.WriteBytes(MsgP2P, MsgTunnelHandshakeAck, []byte("OpenP2P,hello2"))
|
||||
gLog.Println(LvDEBUG, "quic connection ok")
|
||||
gLog.Printf(LvDEBUG, "%s connection ok", underlayProtocol)
|
||||
return ul, nil
|
||||
}
|
||||
|
||||
//else
|
||||
conn, e := net.ListenUDP("udp", t.la)
|
||||
if e != nil {
|
||||
conn, errL := net.ListenUDP("udp", t.la)
|
||||
if errL != nil {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
conn, e = net.ListenUDP("udp", t.la)
|
||||
if e != nil {
|
||||
return nil, fmt.Errorf("quic listen error:%s", e)
|
||||
conn, errL = net.ListenUDP("udp", t.la)
|
||||
if errL != nil {
|
||||
return nil, fmt.Errorf("%s listen error:%s", underlayProtocol, errL)
|
||||
}
|
||||
}
|
||||
t.pn.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, ReadMsgTimeout)
|
||||
gLog.Println(LvDEBUG, "quic dial to ", t.ra.String())
|
||||
ul, e = dialQuic(conn, t.ra, TunnelIdleTimeout)
|
||||
if e != nil {
|
||||
return nil, fmt.Errorf("quic dial to %s error:%s", t.ra.String(), e)
|
||||
gLog.Printf(LvDEBUG, "%s dial to %s", underlayProtocol, t.ra.String())
|
||||
if t.config.UnderlayProtocol == "kcp" {
|
||||
ul, errL = dialKCP(conn, t.ra, TunnelIdleTimeout)
|
||||
} else {
|
||||
ul, errL = dialQuic(conn, t.ra, TunnelIdleTimeout)
|
||||
}
|
||||
|
||||
if errL != nil {
|
||||
return nil, fmt.Errorf("%s dial to %s error:%s", underlayProtocol, t.ra.String(), errL)
|
||||
}
|
||||
handshakeBegin := time.Now()
|
||||
ul.WriteBytes(MsgP2P, MsgTunnelHandshake, []byte("OpenP2P,hello"))
|
||||
_, buff, err := ul.ReadBuffer()
|
||||
if e != nil {
|
||||
ul.listener.Close()
|
||||
_, buff, err := ul.ReadBuffer() // TODO: kcp need timeout
|
||||
if err != nil {
|
||||
ul.Close()
|
||||
return nil, fmt.Errorf("read MsgTunnelHandshake error:%s", err)
|
||||
}
|
||||
if buff != nil {
|
||||
@@ -285,22 +324,30 @@ func (t *P2PTunnel) connectUnderlayQuic() (c underlay, err error) {
|
||||
}
|
||||
|
||||
gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin))
|
||||
gLog.Println(LvDEBUG, "quic connection ok")
|
||||
gLog.Printf(LvINFO, "%s connection ok", underlayProtocol)
|
||||
t.linkModeWeb = LinkModeUDPPunch
|
||||
return ul, nil
|
||||
}
|
||||
|
||||
// websocket
|
||||
func (t *P2PTunnel) connectUnderlayTCP() (c underlay, err error) {
|
||||
gLog.Println(LvDEBUG, "connectUnderlayTCP start")
|
||||
defer gLog.Println(LvDEBUG, "connectUnderlayTCP end")
|
||||
gLog.Printf(LvDEBUG, "connectUnderlayTCP %s start ", t.config.PeerNode)
|
||||
defer gLog.Printf(LvDEBUG, "connectUnderlayTCP %s end ", t.config.PeerNode)
|
||||
var ul *underlayTCP
|
||||
peerIP := t.config.peerIP
|
||||
if t.config.linkMode == LinkModeIntranet {
|
||||
peerIP = t.config.peerLanIP
|
||||
}
|
||||
// server side
|
||||
if t.config.isUnderlayServer == 1 {
|
||||
ul, err = listenTCP(t.config.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 {
|
||||
return nil, fmt.Errorf("listen TCP error:%s", err)
|
||||
}
|
||||
gLog.Println(LvINFO, "TCP connection ok")
|
||||
t.linkModeWeb = LinkModeIPv4
|
||||
if t.config.linkMode == LinkModeIntranet {
|
||||
t.linkModeWeb = LinkModeIntranet
|
||||
}
|
||||
return ul, nil
|
||||
}
|
||||
|
||||
@@ -308,15 +355,18 @@ func (t *P2PTunnel) connectUnderlayTCP() (c underlay, err error) {
|
||||
if t.config.linkMode == LinkModeTCP4 {
|
||||
t.pn.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, ReadMsgTimeout)
|
||||
} else { //tcp punch should sleep for punch the same time
|
||||
if compareVersion(t.config.peerVersion, SyncServerTimeVersion) == LESS {
|
||||
if compareVersion(t.config.peerVersion, SyncServerTimeVersion) < 0 {
|
||||
gLog.Printf(LvDEBUG, "peer version %s less than %s", t.config.peerVersion, SyncServerTimeVersion)
|
||||
} 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())
|
||||
if ts > PunchTsDelay || ts < 0 {
|
||||
ts = PunchTsDelay
|
||||
}
|
||||
gLog.Printf(LvDEBUG, "sleep %d ms", ts/time.Millisecond)
|
||||
time.Sleep(ts)
|
||||
}
|
||||
}
|
||||
ul, err = dialTCP(t.config.peerIP, t.config.peerConeNatPort, t.coneLocalPort, t.config.linkMode)
|
||||
ul, err = dialTCP(peerIP, t.config.peerConeNatPort, t.coneLocalPort, t.config.linkMode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("TCP dial to %s:%d error:%s", t.config.peerIP, t.config.peerConeNatPort, err)
|
||||
}
|
||||
@@ -335,12 +385,109 @@ func (t *P2PTunnel) connectUnderlayTCP() (c underlay, err error) {
|
||||
gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin))
|
||||
gLog.Println(LvINFO, "TCP connection ok")
|
||||
t.linkModeWeb = LinkModeIPv4
|
||||
if t.config.linkMode == LinkModeIntranet {
|
||||
t.linkModeWeb = LinkModeIntranet
|
||||
}
|
||||
return ul, nil
|
||||
}
|
||||
|
||||
func (t *P2PTunnel) connectUnderlayTCPSymmetric() (c underlay, err error) {
|
||||
gLog.Printf(LvDEBUG, "connectUnderlayTCPSymmetric %s start ", t.config.PeerNode)
|
||||
defer gLog.Printf(LvDEBUG, "connectUnderlayTCPSymmetric %s end ", t.config.PeerNode)
|
||||
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 {
|
||||
ts = PunchTsDelay
|
||||
}
|
||||
gLog.Printf(LvDEBUG, "sleep %d ms", ts/time.Millisecond)
|
||||
time.Sleep(ts)
|
||||
startTime := time.Now()
|
||||
t.linkModeWeb = LinkModeTCPPunch
|
||||
gotCh := make(chan *underlayTCP, 1)
|
||||
var wg sync.WaitGroup
|
||||
var success atomic.Int32
|
||||
if t.config.peerNatType == NATSymmetric { // c2s
|
||||
randPorts := rand.Perm(65532)
|
||||
for i := 0; i < SymmetricHandshakeNum; i++ {
|
||||
wg.Add(1)
|
||||
go func(port int) {
|
||||
defer wg.Done()
|
||||
ul, err := dialTCP(t.config.peerIP, port, t.coneLocalPort, LinkModeTCPPunch)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !success.CompareAndSwap(0, 1) {
|
||||
ul.Close() // only cone side close
|
||||
return
|
||||
}
|
||||
err = ul.WriteMessage(MsgP2P, MsgPunchHandshakeAck, P2PHandshakeReq{ID: t.id})
|
||||
if err != nil {
|
||||
ul.Close()
|
||||
return
|
||||
}
|
||||
_, buff, err := ul.ReadBuffer()
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "utcp.ReadBuffer error:", err)
|
||||
return
|
||||
}
|
||||
req := P2PHandshakeReq{}
|
||||
if err = json.Unmarshal(buff, &req); err != nil {
|
||||
return
|
||||
}
|
||||
if req.ID != t.id {
|
||||
return
|
||||
}
|
||||
gLog.Printf(LvINFO, "handshakeS2C TCP ok. cost %dms", time.Since(startTime)/time.Millisecond)
|
||||
|
||||
gotCh <- ul
|
||||
close(gotCh)
|
||||
}(randPorts[i] + 2)
|
||||
}
|
||||
|
||||
} else { // s2c
|
||||
for i := 0; i < SymmetricHandshakeNum; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
ul, err := dialTCP(t.config.peerIP, t.config.peerConeNatPort, 0, LinkModeTCPPunch)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, buff, err := ul.ReadBuffer()
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "utcp.ReadBuffer error:", err)
|
||||
return
|
||||
}
|
||||
req := P2PHandshakeReq{}
|
||||
if err = json.Unmarshal(buff, &req); err != nil {
|
||||
return
|
||||
}
|
||||
if req.ID != t.id {
|
||||
return
|
||||
}
|
||||
err = ul.WriteMessage(MsgP2P, MsgPunchHandshakeAck, P2PHandshakeReq{ID: t.id})
|
||||
if err != nil {
|
||||
ul.Close()
|
||||
return
|
||||
}
|
||||
if success.CompareAndSwap(0, 1) {
|
||||
gotCh <- ul
|
||||
close(gotCh)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
select {
|
||||
case <-time.After(HandshakeTimeout):
|
||||
return nil, fmt.Errorf("wait tcp handshake timeout")
|
||||
case ul := <-gotCh:
|
||||
return ul, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (t *P2PTunnel) connectUnderlayTCP6() (c underlay, err error) {
|
||||
gLog.Println(LvINFO, "connectUnderlayTCP6 start")
|
||||
defer gLog.Println(LvINFO, "connectUnderlayTCP6 end")
|
||||
gLog.Printf(LvDEBUG, "connectUnderlayTCP6 %s start ", t.config.PeerNode)
|
||||
defer gLog.Printf(LvDEBUG, "connectUnderlayTCP6 %s end ", t.config.PeerNode)
|
||||
var ul *underlayTCP6
|
||||
if t.config.isUnderlayServer == 1 {
|
||||
t.pn.push(t.config.PeerNode, MsgPushUnderlayConnect, nil)
|
||||
@@ -350,7 +497,6 @@ func (t *P2PTunnel) connectUnderlayTCP6() (c underlay, err error) {
|
||||
}
|
||||
_, buff, err := ul.ReadBuffer()
|
||||
if err != nil {
|
||||
ul.listener.Close()
|
||||
return nil, fmt.Errorf("read start msg error:%s", err)
|
||||
}
|
||||
if buff != nil {
|
||||
@@ -358,6 +504,7 @@ func (t *P2PTunnel) connectUnderlayTCP6() (c underlay, err error) {
|
||||
}
|
||||
ul.WriteBytes(MsgP2P, MsgTunnelHandshakeAck, []byte("OpenP2P,hello2"))
|
||||
gLog.Println(LvDEBUG, "TCP6 connection ok")
|
||||
t.linkModeWeb = LinkModeIPv6
|
||||
return ul, nil
|
||||
}
|
||||
|
||||
@@ -372,7 +519,6 @@ func (t *P2PTunnel) connectUnderlayTCP6() (c underlay, err error) {
|
||||
ul.WriteBytes(MsgP2P, MsgTunnelHandshake, []byte("OpenP2P,hello"))
|
||||
_, buff, err := ul.ReadBuffer()
|
||||
if err != nil {
|
||||
ul.listener.Close()
|
||||
return nil, fmt.Errorf("read MsgTunnelHandshake error:%s", err)
|
||||
}
|
||||
if buff != nil {
|
||||
@@ -380,7 +526,7 @@ func (t *P2PTunnel) connectUnderlayTCP6() (c underlay, err error) {
|
||||
}
|
||||
|
||||
gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin))
|
||||
gLog.Println(LvDEBUG, "TCP6 connection ok")
|
||||
gLog.Println(LvINFO, "TCP6 connection ok")
|
||||
t.linkModeWeb = LinkModeIPv6
|
||||
return ul, nil
|
||||
}
|
||||
@@ -389,7 +535,7 @@ func (t *P2PTunnel) readLoop() {
|
||||
decryptData := make([]byte, ReadBuffLen+PaddingSize) // 16 bytes for padding
|
||||
gLog.Printf(LvDEBUG, "%d tunnel readloop start", t.id)
|
||||
for t.isRuning() {
|
||||
t.conn.SetReadDeadline(time.Now().Add(TunnelIdleTimeout))
|
||||
t.conn.SetReadDeadline(time.Now().Add(TunnelHeartbeatTime * 2))
|
||||
head, body, err := t.conn.ReadBuffer()
|
||||
if err != nil {
|
||||
if t.isRuning() {
|
||||
@@ -401,23 +547,26 @@ func (t *P2PTunnel) readLoop() {
|
||||
gLog.Printf(LvWARN, "%d head.MainType != MsgP2P", t.id)
|
||||
continue
|
||||
}
|
||||
// TODO: replace some case implement to functions
|
||||
switch head.SubType {
|
||||
case MsgTunnelHeartbeat:
|
||||
t.hbMtx.Lock()
|
||||
t.hbTime = time.Now()
|
||||
t.hbMtx.Unlock()
|
||||
t.conn.WriteBytes(MsgP2P, MsgTunnelHeartbeatAck, nil)
|
||||
gLog.Printf(LvDEBUG, "%d read tunnel heartbeat", t.id)
|
||||
gLog.Printf(LvDev, "%d read tunnel heartbeat", t.id)
|
||||
case MsgTunnelHeartbeatAck:
|
||||
t.hbMtx.Lock()
|
||||
t.hbTime = time.Now()
|
||||
t.hbMtx.Unlock()
|
||||
gLog.Printf(LvDEBUG, "%d read tunnel heartbeat ack", t.id)
|
||||
gLog.Printf(LvDev, "%d read tunnel heartbeat ack", t.id)
|
||||
case MsgOverlayData:
|
||||
if len(body) < overlayHeaderSize {
|
||||
gLog.Printf(LvWARN, "%d len(body) < overlayHeaderSize", t.id)
|
||||
continue
|
||||
}
|
||||
overlayID := binary.LittleEndian.Uint64(body[:8])
|
||||
gLog.Printf(LvDEBUG, "%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)
|
||||
if !ok {
|
||||
// debug level, when overlay connection closed, always has some packet not found tunnel
|
||||
@@ -437,25 +586,31 @@ func (t *P2PTunnel) readLoop() {
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "overlay write error:", err)
|
||||
}
|
||||
case MsgNodeData:
|
||||
t.handleNodeData(head, body, false)
|
||||
case MsgRelayNodeData:
|
||||
t.handleNodeData(head, body, true)
|
||||
case MsgRelayData:
|
||||
if len(body) < 8 {
|
||||
continue
|
||||
}
|
||||
tunnelID := binary.LittleEndian.Uint64(body[:8])
|
||||
gLog.Printf(LvDEBUG, "relay data to %d, len=%d", tunnelID, head.DataLen-RelayHeaderSize)
|
||||
t.pn.relay(tunnelID, body[RelayHeaderSize:])
|
||||
gLog.Printf(LvDev, "relay data to %d, len=%d", tunnelID, head.DataLen-RelayHeaderSize)
|
||||
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)
|
||||
}
|
||||
case MsgRelayHeartbeat:
|
||||
req := RelayHeartbeat{}
|
||||
if err := json.Unmarshal(body, &req); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
||||
continue
|
||||
}
|
||||
// TODO: debug relay heartbeat
|
||||
gLog.Printf(LvDEBUG, "read MsgRelayHeartbeat from rtid:%d,appid:%d", req.RelayTunnelID, req.AppID)
|
||||
relayHead := new(bytes.Buffer)
|
||||
binary.Write(relayHead, binary.LittleEndian, req.RelayTunnelID)
|
||||
msg, _ := newMessage(MsgP2P, MsgRelayHeartbeatAck, &req)
|
||||
msgWithHead := append(relayHead.Bytes(), msg...)
|
||||
t.conn.WriteBytes(MsgP2P, MsgRelayData, msgWithHead)
|
||||
// update app hbtime
|
||||
t.pn.updateAppHeartbeat(req.AppID)
|
||||
req.From = gConf.Network.Node
|
||||
t.WriteMessage(req.RelayTunnelID, MsgP2P, MsgRelayHeartbeatAck, &req)
|
||||
case MsgRelayHeartbeatAck:
|
||||
req := RelayHeartbeat{}
|
||||
err := json.Unmarshal(body, &req)
|
||||
@@ -463,6 +618,7 @@ func (t *P2PTunnel) readLoop() {
|
||||
gLog.Printf(LvERROR, "wrong RelayHeartbeat:%s", err)
|
||||
continue
|
||||
}
|
||||
// TODO: debug relay heartbeat
|
||||
gLog.Printf(LvDEBUG, "read MsgRelayHeartbeatAck to appid:%d", req.AppID)
|
||||
t.pn.updateAppHeartbeat(req.AppID)
|
||||
case MsgOverlayConnectReq:
|
||||
@@ -472,7 +628,7 @@ func (t *P2PTunnel) readLoop() {
|
||||
continue
|
||||
}
|
||||
// app connect only accept token(not relay totp token), avoid someone using the share relay node's token
|
||||
if req.Token != t.pn.config.Token {
|
||||
if req.Token != gConf.Network.Token {
|
||||
gLog.Println(LvERROR, "Access Denied:", req.Token)
|
||||
continue
|
||||
}
|
||||
@@ -525,30 +681,40 @@ func (t *P2PTunnel) readLoop() {
|
||||
default:
|
||||
}
|
||||
}
|
||||
t.setRun(false)
|
||||
t.conn.Close()
|
||||
t.close()
|
||||
gLog.Printf(LvDEBUG, "%d tunnel readloop end", t.id)
|
||||
}
|
||||
|
||||
func (t *P2PTunnel) heartbeatLoop() {
|
||||
func (t *P2PTunnel) writeLoop() {
|
||||
t.hbMtx.Lock()
|
||||
t.hbTime = time.Now() // init
|
||||
t.hbMtx.Unlock()
|
||||
tc := time.NewTicker(TunnelHeartbeatTime)
|
||||
defer tc.Stop()
|
||||
gLog.Printf(LvDEBUG, "%d tunnel heartbeatLoop start", t.id)
|
||||
defer gLog.Printf(LvDEBUG, "%d tunnel heartbeatLoop end", t.id)
|
||||
gLog.Printf(LvDEBUG, "%s:%d tunnel writeLoop start", t.config.PeerNode, t.id)
|
||||
defer gLog.Printf(LvDEBUG, "%s:%d tunnel writeLoop end", t.config.PeerNode, t.id)
|
||||
for t.isRuning() {
|
||||
select {
|
||||
case <-tc.C:
|
||||
// tunnel send
|
||||
err := t.conn.WriteBytes(MsgP2P, MsgTunnelHeartbeat, nil)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "%d write tunnel heartbeat error %s", t.id, err)
|
||||
t.setRun(false)
|
||||
return
|
||||
case buff := <-t.writeDataSmall:
|
||||
t.conn.WriteBuffer(buff)
|
||||
// gLog.Printf(LvDEBUG, "write icmp %d", time.Now().Unix())
|
||||
default:
|
||||
select {
|
||||
case buff := <-t.writeDataSmall:
|
||||
t.conn.WriteBuffer(buff)
|
||||
// gLog.Printf(LvDEBUG, "write icmp %d", time.Now().Unix())
|
||||
case buff := <-t.writeData:
|
||||
t.conn.WriteBuffer(buff)
|
||||
case <-tc.C:
|
||||
// tunnel send
|
||||
err := t.conn.WriteBytes(MsgP2P, MsgTunnelHeartbeat, nil)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "%d write tunnel heartbeat error %s", t.id, err)
|
||||
t.close()
|
||||
return
|
||||
}
|
||||
gLog.Printf(LvDev, "%d write tunnel heartbeat ok", t.id)
|
||||
}
|
||||
gLog.Printf(LvDEBUG, "%d write tunnel heartbeat ok", t.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -559,12 +725,12 @@ func (t *P2PTunnel) listen() error {
|
||||
Error: 0,
|
||||
Detail: "connect ok",
|
||||
To: t.config.PeerNode,
|
||||
From: t.pn.config.Node,
|
||||
NatType: t.pn.config.natType,
|
||||
HasIPv4: t.pn.config.hasIPv4,
|
||||
// IPv6: t.pn.config.IPv6,
|
||||
HasUPNPorNATPMP: t.pn.config.hasUPNPorNATPMP,
|
||||
FromIP: t.pn.config.publicIP,
|
||||
From: gConf.Network.Node,
|
||||
NatType: gConf.Network.natType,
|
||||
HasIPv4: gConf.Network.hasIPv4,
|
||||
// IPv6: gConf.Network.IPv6,
|
||||
HasUPNPorNATPMP: gConf.Network.hasUPNPorNATPMP,
|
||||
FromIP: gConf.Network.publicIP,
|
||||
ConeNatPort: t.coneNatPort,
|
||||
ID: t.id,
|
||||
PunchTs: uint64(time.Now().UnixNano() + int64(PunchTsDelay) - t.pn.dt),
|
||||
@@ -572,7 +738,7 @@ func (t *P2PTunnel) listen() error {
|
||||
}
|
||||
t.punchTs = rsp.PunchTs
|
||||
// only private node set ipv6
|
||||
if t.config.fromToken == t.pn.config.Token {
|
||||
if t.config.fromToken == gConf.Network.Token {
|
||||
rsp.IPv6 = gConf.IPv6()
|
||||
}
|
||||
|
||||
@@ -591,3 +757,50 @@ func (t *P2PTunnel) closeOverlayConns(appID uint64) {
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
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)
|
||||
ch := t.pn.nodeData
|
||||
// if body[9] == 1 { // TODO: deal relay
|
||||
// ch = t.pn.nodeDataSmall
|
||||
// gLog.Printf(LvDEBUG, "read icmp %d", time.Now().Unix())
|
||||
// }
|
||||
if isRelay {
|
||||
fromPeerID := binary.LittleEndian.Uint64(body[:8])
|
||||
ch <- &NodeData{fromPeerID, body[8:]} // TODO: cache peerNodeID; encrypt/decrypt
|
||||
} else {
|
||||
ch <- &NodeData{NodeNameToID(t.config.PeerNode), body} // TODO: cache peerNodeID; encrypt/decrypt
|
||||
}
|
||||
}
|
||||
|
||||
func (t *P2PTunnel) asyncWriteNodeData(mainType, subType uint16, data []byte) {
|
||||
writeBytes := append(encodeHeader(mainType, subType, uint32(len(data))), data...)
|
||||
// if len(data) < 192 {
|
||||
if data[9] == 1 { // icmp
|
||||
select {
|
||||
case t.writeDataSmall <- writeBytes:
|
||||
// gLog.Printf(LvWARN, "%s:%d t.writeDataSmall write %d", t.config.PeerNode, t.id, len(t.writeDataSmall))
|
||||
default:
|
||||
gLog.Printf(LvWARN, "%s:%d t.writeDataSmall is full, drop it", t.config.PeerNode, t.id)
|
||||
}
|
||||
} else {
|
||||
select {
|
||||
case t.writeData <- writeBytes:
|
||||
default:
|
||||
gLog.Printf(LvWARN, "%s:%d t.writeData is full, drop it", t.config.PeerNode, t.id)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (t *P2PTunnel) WriteMessage(rtid uint64, mainType uint16, subType uint16, req interface{}) error {
|
||||
if rtid == 0 {
|
||||
return t.conn.WriteMessage(mainType, subType, &req)
|
||||
}
|
||||
relayHead := new(bytes.Buffer)
|
||||
binary.Write(relayHead, binary.LittleEndian, rtid)
|
||||
msg, _ := newMessage(mainType, subType, &req)
|
||||
msgWithHead := append(relayHead.Bytes(), msg...)
|
||||
return t.conn.WriteBytes(mainType, MsgRelayData, msgWithHead)
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user