This commit is contained in:
TenderIronh
2026-04-01 15:33:30 +08:00
parent ef4bc1e1e3
commit 12393f00c5
23 changed files with 1047 additions and 383 deletions
+14 -2
View File
@@ -138,8 +138,8 @@ func netInfo() *NetInfo {
defer r.Body.Close()
buf := make([]byte, 1024*64)
n, err := r.Body.Read(buf)
if err != nil {
gLog.d("netInfo error:%s", err)
if err != nil && err != io.EOF {
gLog.d("error reading response body: %s", err)
continue
}
rsp := NetInfo{}
@@ -391,3 +391,15 @@ func lookupWithCustomDNS(ctx context.Context, domain string) ([]string, error) {
return resolver.LookupHost(ctx, domain)
}
func writeFull(w io.Writer, data []byte) error {
totalWritten := 0
for totalWritten < len(data) {
n, err := w.Write(data[totalWritten:])
if err != nil {
return fmt.Errorf("write failed after %d bytes: %w", totalWritten, err)
}
totalWritten += n
}
return nil
}
+10
View File
@@ -199,6 +199,11 @@ func (c *Config) retryAllMemApp() {
if app.config.SrcPort != 0 {
return true
}
if app.tunnelNum != int(gConf.sdwan.TunnelNum) {
gLog.d("memapp %s tunnelNum changed from %d to %d, delete it and not retry", app.config.LogPeerNode(), app.tunnelNum, gConf.sdwan.TunnelNum)
GNetwork.DeleteApp(app.config)
return true
}
app.Retry(true)
return true
})
@@ -333,6 +338,11 @@ func (c *Config) setNode(node string) {
c.Network.Node = node
c.Network.nodeID = NodeNameToID(c.Network.Node)
}
func (c *Config) setForcev6(force bool) {
c.mtx.Lock()
defer c.mtx.Unlock()
c.Forcev6 = force
}
func (c *Config) nodeID() uint64 {
c.mtx.Lock()
defer c.mtx.Unlock()
+20 -15
View File
@@ -51,7 +51,7 @@ func handlePush(subType uint16, msg []byte) error {
config.PunchPriority = req.PunchPriority
config.UnderlayProtocol = req.UnderlayProtocol
go func(r AddRelayTunnelReq) {
t, errDt := GNetwork.addDirectTunnel(config, 0)
t, errDt := GNetwork.addDirectTunnel(config, 0, nil)
if errDt == nil && t != nil {
// notify peer relay ready
msg := TunnelMsg{ID: t.id}
@@ -90,18 +90,24 @@ func handlePush(subType uint16, msg []byte) error {
appIdx = req.AppID
}
existApp, appok := GNetwork.apps.Load(appIdx)
var app *p2pApp
if appok {
app := existApp.(*p2pApp)
app = existApp.(*p2pApp)
if app.tunnelNum != int(req.TunnelNum) {
gLog.d("memapp tunnelNum changed from %d to %d", app.tunnelNum, req.TunnelNum)
GNetwork.DeleteApp(app.config)
app = nil
}
}
if app != nil {
app.config.AppName = fmt.Sprintf("%d", peerID)
app.id = req.AppID
app.key = req.AppKey
app.PreCalcKeyBytes()
app.relayMode[req.RelayIndex] = req.RelayMode
app.hbTime[req.RelayIndex] = time.Now()
if req.RelayTunnelID == 0 {
app.SetTunnel(existTunnel, 0)
} else {
app.SetTunnel(existTunnel, int(req.RelayIndex)) // TODO: merge two func
app.SetTunnel(existTunnel, int(req.RelayIndex))
if req.RelayTunnelID != 0 {
app.SetRelayTunnelID(req.RelayTunnelID, int(req.RelayIndex)) // direct tunnel rtid=0, no need set rtid
}
gLog.d("found existing memapp, update it")
@@ -111,7 +117,7 @@ func handlePush(subType uint16, msg []byte) error {
appConfig.Protocol = ""
appConfig.AppName = fmt.Sprintf("%d", peerID)
appConfig.PeerNode = req.From
app := p2pApp{
app = &p2pApp{
id: req.AppID,
config: appConfig,
running: true,
@@ -126,17 +132,13 @@ func handlePush(subType uint16, msg []byte) error {
app.Init(tunnelNum)
app.relayMode[req.RelayIndex] = req.RelayMode
app.hbTime[req.RelayIndex] = time.Now()
if req.RelayTunnelID == 0 {
app.SetTunnel(existTunnel, 0)
} else {
app.SetTunnel(existTunnel, int(req.RelayIndex))
app.SetRelayTunnelID(req.RelayTunnelID, int(req.RelayIndex))
}
app.SetTunnel(existTunnel, int(req.RelayIndex))
if req.RelayTunnelID != 0 {
app.SetRelayTunnelID(req.RelayTunnelID, int(req.RelayIndex))
app.relayNode[req.RelayIndex] = req.Node
}
app.Start(false)
GNetwork.apps.Store(appIdx, &app)
GNetwork.apps.Store(appIdx, app)
gLog.d("store memapp %d %d", appIdx, req.SrcPort)
}
@@ -175,6 +177,9 @@ func handlePush(subType uint16, msg []byte) error {
}
gConf.setNode(req.NewName)
gConf.setShareBandwidth(req.Bandwidth)
if req.PublicIPPort != 0 {
gConf.Network.PublicIPPort = req.PublicIPPort
}
gConf.Forcev6 = (req.Forcev6 != 0)
gLog.i("set forcev6 to %v", gConf.Forcev6)
gConf.save()
@@ -341,7 +346,7 @@ func handleConnectReq(msg []byte) (err error) {
}
// go GNetwork.AddTunnel(config, req.ID)
go func() {
GNetwork.addDirectTunnel(config, req.ID)
GNetwork.addDirectTunnel(config, req.ID, nil)
}()
return nil
}
+8 -6
View File
@@ -9,6 +9,8 @@ import (
"strings"
"time"
upnp "openp2p/pkg/upnp"
reuse "github.com/openp2p-cn/go-reuseport"
)
@@ -190,23 +192,23 @@ func publicIPTest(publicIP string, echoPort int) (hasPublicIP int, hasUPNPorNATP
}
func setUPNP(echoPort int) {
nat, err := Discover()
if err != nil || nat == nil {
gLog.d("could not perform UPNP discover:%s", err)
nat := upnp.Any() // Initialize the NAT interface
if nat == nil {
gLog.d("NAT interface is not available")
return
}
ext, err := nat.GetExternalAddress()
ext, err := nat.ExternalIP()
if err != nil {
gLog.d("could not perform UPNP external address:%s", err)
return
}
gLog.i("PublicIP:%v", ext)
externalPort, err := nat.AddPortMapping("udp", echoPort, echoPort, "openp2p", 604800)
externalPort, err := nat.AddMapping("udp", echoPort, echoPort, "openp2p", 604800)
if err != nil {
gLog.d("could not add udp UPNP port mapping %d", externalPort)
return
} else {
nat.AddPortMapping("tcp", echoPort, echoPort, "openp2p", 604800)
nat.AddMapping("tcp", echoPort, echoPort, "openp2p", 604800)
}
}
+13 -17
View File
@@ -8,8 +8,6 @@ import (
"fmt"
"net"
"os"
"os/exec"
"strings"
"github.com/openp2p-cn/wireguard-go/tun"
"github.com/vishvananda/netlink"
@@ -116,26 +114,24 @@ func delRoute(dst, gw string) error {
}
func delRoutesByGateway(gateway string) error {
cmd := exec.Command("route", "-n")
output, err := cmd.Output()
if err != nil {
return err
ipGW := net.ParseIP(gateway)
if ipGW == nil {
return fmt.Errorf("invalid gateway IP: %s", gateway)
}
lines := strings.Split(string(output), "\n")
for _, line := range lines {
if !strings.Contains(line, gateway) {
continue
}
fields := strings.Fields(line)
if len(fields) >= 8 && fields[1] == "0.0.0.0" && fields[7] == gateway {
delCmd := exec.Command("route", "del", "-net", fields[0], "gw", gateway)
err := delCmd.Run()
routes, err := netlink.RouteList(nil, netlink.FAMILY_V4)
if err != nil {
return fmt.Errorf("failed to list routes: %v", err)
}
for _, route := range routes {
if route.Gw != nil && route.Gw.Equal(ipGW) || (route.Dst != nil && route.Dst.IP.Equal(ipGW)) {
err := netlink.RouteDel(&route)
if err != nil {
gLog.e("Delete route %s error:%s", fields[0], err)
gLog.e("Failed to delete route: %v, error: %v", route, err)
continue
}
gLog.i("Delete route ok: %s %s %s\n", fields[0], fields[1], gateway)
gLog.i("Deleted route: %v", route)
}
}
return nil
+2 -1
View File
@@ -141,7 +141,8 @@ func (oConn *overlayConn) Write(buff []byte) (n int, err error) {
return
}
if oConn.connTCP != nil {
n, err = oConn.connTCP.Write(buff)
err = writeFull(oConn.connTCP, buff)
n = len(buff)
}
if err != nil {
+99 -68
View File
@@ -42,6 +42,7 @@ type p2pApp struct {
msgChan chan appMsgCtx
once sync.Once
tunnelNum int
relayIdxStart int
allTunnels []*P2PTunnel
retryNum []int
retryTime []time.Time
@@ -106,7 +107,7 @@ func (app *p2pApp) RetryTime() time.Time {
if app.allTunnels[0] != nil {
return app.config.retryTime
}
return app.retryTime[1]
return app.retryTime[app.relayIdxStart]
}
func (app *p2pApp) Init(tunnelNum int) {
@@ -133,6 +134,10 @@ func (app *p2pApp) Init(tunnelNum int) {
for i := 0; i < tunnelNum; i++ {
app.hbTime[i] = time.Now()
}
app.relayIdxStart = app.tunnelNum - 2
if app.relayIdxStart == 0 {
app.relayIdxStart = 1 // at least one direct tunnel
}
// app.unAckSeqStart.Store(0)
// app.mergeAckTs.Store(0)
// for i := 0; i < relayNum; i++ {
@@ -152,64 +157,72 @@ func (app *p2pApp) Start(isClient bool) {
func (app *p2pApp) daemonP2PTunnel() error {
for app.running {
app.daemonDirectTunnel()
if app.config.peerIP == gConf.Network.publicIP {
time.Sleep(time.Second * 10) // if peerIP is local IP, delay relay tunnel
}
for i := 1; i < app.tunnelNum; i++ {
app.daemonRelayTunnel(i)
}
for i := 0; i < app.relayIdxStart; i++ {
app.daemonDirectTunnel(i)
time.Sleep(time.Second)
}
for i := app.relayIdxStart; i < app.tunnelNum; i++ {
if i > app.relayIdxStart {
app.nextRetryTime[i] = time.Now().Add(time.Second * 180) // the second relay tunnel wait 3 mins
}
app.daemonRelayTunnel(i)
time.Sleep(time.Second)
}
time.Sleep(time.Second * 3)
}
return nil
}
func (app *p2pApp) daemonDirectTunnel() error {
func (app *p2pApp) daemonDirectTunnel(idx int) error {
if !GNetwork.online {
return nil
}
if app.config.ForceRelay == 1 && app.config.RelayNode != app.config.PeerNode {
return nil
}
if app.Tunnel(0) != nil && app.Tunnel(0).isActive() {
// TODO: multi direct tunnel support symmetric NAT traversal later
if idx > 0 && gConf.Network.hasIPv4 == 0 && gConf.Network.hasUPNPorNATPMP == 0 && app.config.hasIPv4 == 0 && app.config.hasUPNPorNATPMP == 0 && (gConf.Network.natType == NATSymmetric || app.config.peerNatType == NATSymmetric) {
return nil
}
if app.Tunnel(idx) != nil && app.Tunnel(idx).isActive() {
return nil
}
if app.config.nextRetryTime.After(time.Now()) || app.config.Enabled == 0 {
return nil
}
if time.Now().Add(-time.Minute * 15).After(app.config.retryTime) { // run normally 15min, reset retrynum
app.config.retryNum = 1
app.retryNum[idx] = 1
}
if app.config.retryNum > 0 { // first time not show reconnect log
gLog.i("appid:%d checkDirectTunnel detect peer %s disconnect, reconnecting the %d times...", app.id, app.config.LogPeerNode(), app.config.retryNum)
if app.retryNum[idx] > 0 { // first time not show reconnect log
gLog.i("appid:%d checkDirectTunnel detect peer %s disconnect, reconnecting the %d times...", app.id, app.config.LogPeerNode(), app.retryNum[idx])
}
app.config.retryNum++
app.retryNum[idx]++
app.config.retryTime = time.Now()
app.config.connectTime = time.Now()
err := app.buildDirectTunnel()
err := app.buildDirectTunnel(idx)
if err != nil {
app.config.errMsg = err.Error()
if err == ErrPeerOffline && app.config.retryNum > 2 { // stop retry, waiting for online
app.config.retryNum = retryLimit
if err == ErrPeerOffline && app.retryNum[idx] > 2 { // stop retry, waiting for online
app.retryNum[idx] = retryLimit
gLog.i("appid:%d checkDirectTunnel %s offline, it will auto reconnect when peer node online", app.id, app.config.LogPeerNode())
}
if err == ErrBuildTunnelBusy {
app.config.retryNum--
app.retryNum[idx]--
}
}
interval := calcRetryTimeRelay(float64(app.config.retryNum))
interval := calcRetryTimeRelay(float64(app.retryNum[idx]))
if app.preDirectSuccessIP == app.config.peerIP {
interval = math.Min(interval, 1800) // if peerIP has been direct link succeed, retry 30min max
}
app.config.nextRetryTime = time.Now().Add(time.Duration(interval) * time.Second)
if app.Tunnel(0) != nil {
if app.Tunnel(idx) != nil {
app.preDirectSuccessIP = app.config.peerIP
app.once.Do(func() {
go app.listen()
// memapp also need
for i := 1; i < app.tunnelNum; i++ {
for i := app.relayIdxStart; i < app.tunnelNum; i++ {
go app.relayHeartbeatLoop(i)
}
@@ -217,7 +230,7 @@ func (app *p2pApp) daemonDirectTunnel() error {
}
return nil
}
func (app *p2pApp) buildDirectTunnel() error {
func (app *p2pApp) buildDirectTunnel(idx int) error {
relayNode := ""
peerNatType := NATUnknown
peerIP := ""
@@ -225,12 +238,13 @@ func (app *p2pApp) buildDirectTunnel() error {
var t *P2PTunnel
var err error
pn := GNetwork
// TODO: optimize requestPeerInfo call frequency
initErr := pn.requestPeerInfo(&app.config)
if initErr != nil {
gLog.w("appid:%d buildDirectTunnel %s requestPeerInfo error:%s", app.id, app.config.LogPeerNode(), initErr)
return initErr
}
t, err = pn.addDirectTunnel(app.config, 0)
t, err = pn.addDirectTunnel(app.config, 0, app.Tunnel(idx^1))
if t != nil {
peerNatType = t.config.peerNatType
peerIP = t.config.peerIP
@@ -267,11 +281,11 @@ func (app *p2pApp) buildDirectTunnel() error {
}
gLog.d("appid:%d buildDirectTunnel sync appkey to %s", app.id, app.config.LogPeerNode())
pn.push(app.config.PeerNode, MsgPushAPPKey, &syncKeyReq)
app.SetTunnel(t, 0)
app.SetTunnel(t, idx)
// if memapp notify peer addmemapp
// if app.config.SrcPort == 0 {
req2 := ServerSideSaveMemApp{From: gConf.Network.Node, Node: gConf.Network.Node, TunnelID: t.id, RelayTunnelID: 0, TunnelNum: uint32(app.tunnelNum), AppID: app.id, AppKey: app.key, SrcPort: uint32(app.config.SrcPort)}
req2 := ServerSideSaveMemApp{From: gConf.Network.Node, Node: gConf.Network.Node, TunnelID: t.id, RelayTunnelID: 0, RelayIndex: uint32(idx), TunnelNum: uint32(app.tunnelNum), AppID: app.id, AppKey: app.key, SrcPort: uint32(app.config.SrcPort)}
pn.push(app.config.PeerNode, MsgPushServerSideSaveMemApp, &req2)
gLog.d("appid:%d buildDirectTunnel push %s ServerSideSaveMemApp: %s", app.id, app.config.LogPeerNode(), prettyJson(req2))
@@ -284,14 +298,15 @@ func (app *p2pApp) daemonRelayTunnel(idx int) error {
if !GNetwork.online {
return nil
}
if app.Tunnel(0) != nil && app.Tunnel(0).linkModeWeb == LinkModeIntranet { // in the same Lan, no relay
if app.Tunnel(0) != nil && app.relayIdxStart >= 2 { // multi direct tunnel no relay
return nil
}
// if app.config.ForceRelay == 1 && (gConf.sdwan.CentralNode == app.config.PeerNode && compareVersion(app.config.peerVersion, SupportDualTunnelVersion) < 0) {
if app.config.SrcPort == 0 && (gConf.sdwan.CentralNode == app.config.PeerNode || gConf.sdwan.CentralNode == gConf.Network.Node) { // memapp central node not build relay tunnel
return nil
}
if gConf.sdwan.CentralNode != "" && idx > 1 { // if central node exist only need one relayTunnel
if gConf.sdwan.CentralNode != "" && idx != app.relayIdxStart { // if central node exist only need one relayTunnel
return nil
}
app.hbMtx.Lock()
@@ -352,9 +367,12 @@ func (app *p2pApp) buildRelayTunnel(idx int) error {
return initErr
}
ExcludeNodes := ""
kk := 1 + ((idx - 1) ^ 1)
if app.tunnelNum > 2 && app.allTunnels[kk] != nil {
ExcludeNodes = app.allTunnels[1+((idx-1)^1)].config.PeerNode
theOtherTunnelIdx := app.relayIdxStart
if idx == app.relayIdxStart {
theOtherTunnelIdx = app.relayIdxStart + 1
}
if app.tunnelNum > 2 && app.allTunnels[theOtherTunnelIdx] != nil {
ExcludeNodes = app.allTunnels[theOtherTunnelIdx].config.PeerNode
}
t, rtid, relayMode, err = pn.addRelayTunnel(config, ExcludeNodes)
if t != nil {
@@ -364,24 +382,27 @@ func (app *p2pApp) buildRelayTunnel(idx int) error {
if err != nil {
errMsg = err.Error()
}
req := ReportConnect{
Error: errMsg,
Protocol: config.Protocol,
SrcPort: config.SrcPort,
NatType: gConf.Network.natType,
PeerNode: config.PeerNode,
DstPort: config.DstPort,
DstHost: config.DstHost,
PeerNatType: peerNatType,
PeerIP: peerIP,
ShareBandwidth: gConf.Network.ShareBandwidth,
RelayNode: relayNode,
Version: OpenP2PVersion,
if app.Tunnel(0) == nil {
req := ReportConnect{
Error: errMsg,
Protocol: config.Protocol,
SrcPort: config.SrcPort,
NatType: gConf.Network.natType,
PeerNode: config.PeerNode,
DstPort: config.DstPort,
DstHost: config.DstHost,
PeerNatType: peerNatType,
PeerIP: peerIP,
ShareBandwidth: gConf.Network.ShareBandwidth,
RelayNode: relayNode,
Version: OpenP2PVersion,
}
pn.write(MsgReport, MsgReportConnect, &req)
}
pn.write(MsgReport, MsgReportConnect, &req)
if err != nil {
if err != nil || t == nil {
return err
}
// if rtid != 0 || t.conn.Protocol() == "tcp" {
// sync appkey
syncKeyReq := APPKeySync{
@@ -446,31 +467,40 @@ func (app *p2pApp) IsActive() bool {
return res
}
// only for relay tunnel heartbeat update
func (app *p2pApp) UpdateHeartbeat(rtid uint64) {
app.hbMtx.Lock()
defer app.hbMtx.Unlock()
tidx := 1
if app.tunnelNum > 2 && rtid == app.rtid[2] || (app.Tunnel(2) != nil && app.Tunnel(2).id == rtid) { // ack return rtid!=
tidx = 2
for i := app.relayIdxStart; i < app.tunnelNum; i++ {
if rtid == app.rtid[i] || (app.Tunnel(i) != nil && app.Tunnel(i).id == rtid) {
app.hbTime[i] = time.Now()
rtt := int32(time.Since(app.whbTime[i]) / time.Millisecond)
preRtt := app.rtt[i].Load()
if preRtt != DefaultRtt {
rtt = int32(float64(preRtt)*(1-ma20) + float64(rtt)*ma20)
}
app.rtt[i].Store(rtt)
gLog.dev("appid:%d relay heartbeat %d store rtt %d", app.id, i, rtt)
return
}
}
app.hbTime[tidx] = time.Now()
rtt := int32(time.Since(app.whbTime[tidx]) / time.Millisecond)
preRtt := app.rtt[tidx].Load()
if preRtt != DefaultRtt {
rtt = int32(float64(preRtt)*(1-ma20) + float64(rtt)*ma20)
}
app.rtt[tidx].Store(rtt)
gLog.dev("appid:%d relay heartbeat %d store rtt %d", app.id, tidx, rtt)
}
func (app *p2pApp) UpdateRelayHeartbeatTs(rtid uint64) {
app.hbMtx.Lock()
defer app.hbMtx.Unlock()
relayIdx := 1
if app.tunnelNum > 2 && rtid == app.rtid[2] || (app.Tunnel(2) != nil && app.Tunnel(2).id == rtid) { // ack return rtid!=
relayIdx = 2
for i := app.relayIdxStart; i < app.tunnelNum; i++ {
if rtid == app.rtid[i] || (app.Tunnel(i) != nil && app.Tunnel(i).id == rtid) {
app.whbTime[i] = time.Now()
return
}
}
app.whbTime[relayIdx] = time.Now() // one side did not write relay hb, so write whbtime in this.
// relayIdx := 1
// if app.tunnelNum > 2 && rtid == app.rtid[2] || (app.Tunnel(2) != nil && app.Tunnel(2).id == rtid) { // ack return rtid!=
// relayIdx = 2
// }
// app.whbTime[relayIdx] = time.Now() // one side did not write relay hb, so write whbtime in this.
}
func (app *p2pApp) listenTCP() error {
@@ -714,7 +744,7 @@ func (app *p2pApp) WriteBytes(data []byte) error {
if t == nil {
return ErrAppWithoutTunnel
}
if tidx == 0 {
if tidx < app.relayIdxStart { // direct mode
return t.conn.WriteBytes(MsgP2P, MsgOverlayData, data)
}
all := append(app.relayHead[tidx].Bytes(), encodeHeader(MsgP2P, MsgOverlayData, uint32(len(data)))...)
@@ -745,7 +775,7 @@ func (app *p2pApp) WriteNodeDataMP(IPPacket []byte) (err error) {
dataWithSeq.Write(IPPacket)
// gLog.d("DEBUG writeTs=%d, unAckSeqStart=%d", wu.writeTs.UnixMilli(), app.unAckSeqStart[tidx].Load())
if tidx == 0 {
if tidx < app.relayIdxStart { // direct mode
t.asyncWriteNodeData(gConf.nodeID(), app.seqW, IPPacket, nil)
gLog.dev("appid:%d asyncWriteDirect IPPacket len=%d", app.id, len(IPPacket))
} else {
@@ -782,12 +812,13 @@ func (app *p2pApp) fastestTunnel() (t *P2PTunnel, idx int) {
return app.Tunnel(gConf.Network.specTunnel), gConf.Network.specTunnel
}
}
t = app.Tunnel(0)
idx = 0
if app.Tunnel(1) != nil {
t = app.Tunnel(1)
idx = 1
for i := 0; i < app.tunnelNum; i++ {
if app.Tunnel(i) != nil {
t = app.Tunnel(i)
idx = i
break
}
}
return
}
@@ -812,7 +843,7 @@ func (app *p2pApp) Retry(all bool) {
app.hbMtx.Lock()
app.hbTime[i] = time.Now().Add(-TunnelHeartbeatTime * 3)
app.hbMtx.Unlock()
app.config.retryNum = 0
// app.config.retryNum = 0
app.config.nextRetryTime = time.Now()
app.ResetWindow()
}
+67 -39
View File
@@ -126,6 +126,7 @@ func P2PNetworkInstance() {
HasUPNPorNATPMP: gConf.Network.hasUPNPorNATPMP,
Version: OpenP2PVersion,
IPv6: newIPv6,
PublicIPPort: gConf.Network.PublicIPPort,
}
GNetwork.write(MsgReport, MsgReportBasic, &req)
}
@@ -142,19 +143,9 @@ func P2PNetworkInstance() {
func (pn *P2PNetwork) keepAlive() {
gLog.i("P2PNetwork keepAlive start")
// !hbTime && !initTime = hang, exit worker
var lastCheckTime time.Time
for {
time.Sleep(time.Second * 10)
// Skip check if we're waking from sleep/hibernation
now := time.Now()
if !lastCheckTime.IsZero() && now.Sub(lastCheckTime) > NetworkHeartbeatTime*3 {
gLog.i("Detected possible sleep/wake cycle, skipping this check")
lastCheckTime = now
continue
}
lastCheckTime = now
if pn.hbTime.Before(time.Now().Add(-NetworkHeartbeatTime * 3)) {
if pn.initTime.After(time.Now().Add(-NetworkHeartbeatTime * 3)) {
gLog.d("Init less than 3 mins, skipping this check")
@@ -285,8 +276,8 @@ func (pn *P2PNetwork) autorunApp() {
}
func (pn *P2PNetwork) addRelayTunnel(config AppConfig, excludeNodes string) (*P2PTunnel, uint64, string, error) {
gLog.i("addRelayTunnel to %s start", config.LogPeerNode())
defer gLog.i("addRelayTunnel to %s end", config.LogPeerNode())
gLog.d("addRelayTunnel to %s start", config.LogPeerNode())
defer gLog.d("addRelayTunnel to %s end", config.LogPeerNode())
var relayTunnel *P2PTunnel
relayConfig := AppConfig{
peerToken: config.peerToken,
@@ -342,7 +333,7 @@ func (pn *P2PNetwork) addRelayTunnel(config AppConfig, excludeNodes string) (*P2
///
if relayTunnel == nil {
var err error
relayTunnel, err = pn.addDirectTunnel(relayConfig, 0)
relayTunnel, err = pn.addDirectTunnel(relayConfig, 0, nil)
if err != nil || relayTunnel == nil {
gLog.w("direct connect error:%s", err)
if err != nil && config.RelayNode != "" {
@@ -392,8 +383,15 @@ func (pn *P2PNetwork) AddApp(config AppConfig) error {
pn.msgMap.Store(NodeNameToID(config.PeerNode), make(chan msgCtx, MsgQueueSize))
}
// check if app already exist?
if pn.findApp(&config) != nil {
return errors.New("P2PApp already exist")
existApp := pn.findApp(&config)
if existApp != nil {
if existApp.tunnelNum == int(gConf.sdwan.TunnelNum) {
return errors.New("P2PApp already exist")
} else {
gLog.d("app %s exist but tunnelNum changed from %d to %d, delete it and recreate", existApp.config.AppName, existApp.tunnelNum, gConf.sdwan.TunnelNum)
pn.DeleteApp(config)
}
}
app := p2pApp{
@@ -459,13 +457,13 @@ func (pn *P2PNetwork) DeleteApp(config AppConfig) {
}
func (pn *P2PNetwork) findTunnel(peerNode string) (t *P2PTunnel) {
func (pn *P2PNetwork) findTunnel(peerNode string, ignoredTunnel *P2PTunnel) (t *P2PTunnel) {
t = nil
// find existing tunnel to peer
pn.allTunnels.Range(func(id, i interface{}) bool {
tmpt := i.(*P2PTunnel)
if tmpt.config.PeerNode == peerNode {
gLog.i("tunnel already exist %s", tmpt.config.LogPeerNode())
if tmpt.config.PeerNode == peerNode && tmpt != ignoredTunnel {
gLog.d("tunnel already exist %s", tmpt.config.LogPeerNode())
isActive := tmpt.checkActive()
// inactive, close it
if !isActive {
@@ -481,7 +479,7 @@ func (pn *P2PNetwork) findTunnel(peerNode string) (t *P2PTunnel) {
return t
}
func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunnel, err error) {
func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64, ignoredTunnel *P2PTunnel) (t *P2PTunnel, err error) {
gLog.d("addDirectTunnel %s%d to %s:%s:%d tid:%d start", config.Protocol, config.SrcPort, config.LogPeerNode(), config.DstHost, config.DstPort, tid)
defer gLog.d("addDirectTunnel %s%d to %s:%s:%d tid:%d end", config.Protocol, config.SrcPort, config.LogPeerNode(), config.DstHost, config.DstPort, tid)
@@ -502,14 +500,14 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunne
}
if isClient { // only client side find existing tunnel, server side should force build tunnel
if existTunnel := pn.findTunnel(config.PeerNode); existTunnel != nil {
if existTunnel := pn.findTunnel(config.PeerNode, ignoredTunnel); existTunnel != nil {
return existTunnel, nil
}
}
// server side
if !isClient {
t, err = pn.newTunnel(config, tid, isClient)
t, err = pn.newTunnel(config, tid, isClient, ignoredTunnel)
return t, err // always return
}
@@ -521,15 +519,15 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunne
return nil, initErr
}
gLog.d("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.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)
gLog.d("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.PunchPriority=%d,IPv6=%s",
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, config.PunchPriority, gConf.IPv6())
// try Intranet
if config.peerIP == gConf.Network.publicIP && compareVersion(config.peerVersion, SupportIntranetVersion) >= 0 { // old version client has no peerLanIP
gLog.i("try Intranet")
config.linkMode = LinkModeIntranet
config.isUnderlayServer = 0
if t, err = pn.newTunnel(config, tid, isClient); err == nil {
if t, err = pn.newTunnel(config, tid, isClient, ignoredTunnel); err == nil {
return t, nil
}
}
@@ -542,7 +540,7 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunne
if gConf.Forcev6 {
thisTunnelForcev6 = true
}
if t, err = pn.newTunnel(config, tid, isClient); err == nil {
if t, err = pn.newTunnel(config, tid, isClient, ignoredTunnel); err == nil {
return t, nil
}
}
@@ -564,7 +562,7 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunne
} else {
config.isUnderlayServer = 0
}
if t, err = pn.newTunnel(config, tid, isClient); err == nil {
if t, err = pn.newTunnel(config, tid, isClient, ignoredTunnel); err == nil {
return t, nil
}
}
@@ -581,7 +579,7 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunne
gLog.i("try UDP4 Punch")
config.linkMode = LinkModeUDPPunch
config.isUnderlayServer = 0
if t, err = pn.newTunnel(config, tid, isClient); err == nil {
if t, err = pn.newTunnel(config, tid, isClient, ignoredTunnel); err == nil {
return t, nil
}
}
@@ -601,7 +599,7 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunne
gLog.i("try TCP4 Punch")
config.linkMode = LinkModeTCPPunch
config.isUnderlayServer = 0
if t, err = pn.newTunnel(config, tid, isClient); err == nil {
if t, err = pn.newTunnel(config, tid, isClient, ignoredTunnel); err == nil {
gLog.i("TCP4 Punch ok")
return t, nil
}
@@ -613,8 +611,8 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunne
primaryPunchFunc = funcTCP
secondaryPunchFunc = funcUDP
} else {
primaryPunchFunc = funcTCP
secondaryPunchFunc = funcUDP
primaryPunchFunc = funcUDP
secondaryPunchFunc = funcTCP
}
if t, err = primaryPunchFunc(); t != nil && err == nil {
return t, err
@@ -627,9 +625,9 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunne
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, ignoredTunnel *P2PTunnel) (t *P2PTunnel, err error) {
if isClient { // only client side find existing tunnel, server side should force build tunnel
if existTunnel := pn.findTunnel(config.PeerNode); existTunnel != nil {
if existTunnel := pn.findTunnel(config.PeerNode, ignoredTunnel); existTunnel != nil {
return existTunnel, nil
}
}
@@ -665,8 +663,9 @@ func (pn *P2PNetwork) init() error {
pn.wgReconnect.Add(1)
defer pn.wgReconnect.Done()
var err error
initOK := false
defer func() {
if err != nil {
if !initOK {
// init failed, retry
pn.close(true)
gLog.e("P2PNetwork init error:%s", err)
@@ -760,6 +759,14 @@ func (pn *P2PNetwork) init() error {
ws, _, err := d.Dial(u.String(), nil)
if err != nil {
gLog.e("Dial error:%s", err)
switch gConf.Network.ServerPort {
case WsPort:
gConf.Network.ServerPort = WsPort2
gLog.i("try alternative port %d", WsPort2)
case WsPort2:
gConf.Network.ServerPort = WsPort
gLog.i("try alternative port %d", WsPort)
}
break
}
pn.running = true
@@ -769,7 +776,7 @@ func (pn *P2PNetwork) init() error {
if len(localAddr) == 2 {
gConf.Network.localIP = localAddr[0]
} else {
err = errors.New("get local ip failed")
gLog.e("get local ip failed:%s", ws.LocalAddr().String())
break
}
go pn.readLoop()
@@ -781,6 +788,7 @@ func (pn *P2PNetwork) init() error {
LanIP: gConf.Network.localIP,
OS: gConf.Network.os,
HasIPv4: gConf.Network.hasIPv4,
PublicIPPort: gConf.Network.PublicIPPort,
HasUPNPorNATPMP: gConf.Network.hasUPNPorNATPMP,
Version: OpenP2PVersion,
}
@@ -795,10 +803,22 @@ func (pn *P2PNetwork) init() error {
pn.refreshIPv6()
}
req.IPv6 = gConf.IPv6()
pn.write(MsgReport, MsgReportBasic, &req)
pn.write(MsgReport, MsgReportBasic, &req) // TODO: if report failed, many logic problems, loss lanip os version...
head, _ := pn.read("", MsgReport, MsgReportBasicRsp, ClientAPITimeout)
if head == nil {
gLog.e("read MsgReportBasic rsp error, retry")
pn.write(MsgReport, MsgReportBasic, &req) // TODO: if report failed, many logic problems, loss lanip os version...
head, _ := pn.read("", MsgReport, MsgReportBasicRsp, ClientAPITimeout)
if head == nil {
gLog.e("read MsgReportBasic rsp error again, exit")
os.Exit(9)
}
return
}
}()
go pn.autorunApp()
pn.write(MsgSDWAN, MsgSDWANInfoReq, nil)
initOK = true
gLog.d("P2PNetwork init ok")
break
}
@@ -828,6 +848,10 @@ func (pn *P2PNetwork) handleMessage(msg []byte) {
} else {
gConf.setToken(rsp.Token)
gConf.setUser(rsp.User)
gConf.setForcev6(rsp.Forcev6 != 0)
if rsp.PublicIPPort != 0 {
gConf.Network.PublicIPPort = rsp.PublicIPPort
}
if len(rsp.Node) >= MinNodeNameLen {
gConf.setNode(rsp.Node)
}
@@ -1039,7 +1063,7 @@ func (pn *P2PNetwork) read(node string, mainType uint16, subType uint16, timeout
if head.MainType != mainType || head.SubType != subType {
// gLog.d("read msg error type %d:%d expect %d:%d, requeue it", head.MainType, head.SubType, mainType, subType)
ch <- msg
time.Sleep(time.Second)
time.Sleep(time.Millisecond * 50)
continue
}
if mainType == MsgPush {
@@ -1069,9 +1093,14 @@ func (pn *P2PNetwork) updateAppHeartbeat(appID uint64, rtid uint64, updateRelayT
// ipv6 will expired need to refresh.
func (pn *P2PNetwork) refreshIPv6() {
for i := 0; i < 2; i++ {
url := "http://ipv6.ddnspod.com/"
if i == 1 {
url = "ipv6.icanhazip.com"
}
client := &http.Client{Timeout: time.Second * 10}
r, err := client.Get("http://ipv6.ddnspod.com/")
r, err := client.Get(url)
if err != nil {
gLog.d("refreshIPv6 error:%s", err)
continue
@@ -1221,4 +1250,3 @@ func (pn *P2PNetwork) ReadNode(tm time.Duration) []byte {
}
return nil
}
+10 -5
View File
@@ -293,7 +293,7 @@ func (t *P2PTunnel) connectUnderlayUDP() (c underlay, err error) {
gLog.d("UDP4 connection ok")
} else {
if t.config.UnderlayProtocol == "kcp" {
ul, err = listenKCP(t.localHoleAddr.String(), TunnelIdleTimeout)
// ul, err = listenKCP(t.localHoleAddr.String(), TunnelIdleTimeout)
} else {
ul, err = listenQuic(t.localHoleAddr.String(), TunnelIdleTimeout)
}
@@ -337,7 +337,7 @@ func (t *P2PTunnel) connectUnderlayUDP() (c underlay, err error) {
GNetwork.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, ReadMsgTimeout)
gLog.d("%s dial to %s", underlayProtocol, t.remoteHoleAddr.String())
if t.config.UnderlayProtocol == "kcp" {
ul, errL = dialKCP(conn, t.remoteHoleAddr, UnderlayConnectTimeout)
// ul, errL = dialKCP(conn, t.remoteHoleAddr, UnderlayConnectTimeout)
} else {
ul, errL = dialQuic(conn, t.remoteHoleAddr, UnderlayConnectTimeout)
}
@@ -602,7 +602,7 @@ func (t *P2PTunnel) readLoop() {
head, body, err := t.conn.ReadBuffer()
if err != nil || head == nil {
if t.isRuning() {
gLog.w("%d tunnel read error:%s", t.id, err)
gLog.d("%d tunnel read error:%s", t.id, err)
}
break
}
@@ -630,7 +630,12 @@ func (t *P2PTunnel) readLoop() {
existApp, appok := GNetwork.apps.Load(memAppPeerID)
if appok {
app := existApp.(*p2pApp)
app.rtt[0].Store(int32(time.Since(t.whbTime) / time.Millisecond))
for i := 0; i < app.relayIdxStart; i++ {
if app.Tunnel(i) == t {
app.rtt[i].Store(int32(time.Since(t.whbTime) / time.Millisecond))
break
}
}
}
}
@@ -806,7 +811,7 @@ func (t *P2PTunnel) writeLoop() {
t.whbTime = time.Now()
err := t.conn.WriteBytes(MsgP2P, MsgTunnelHeartbeat, nil)
if err != nil {
gLog.w("%d write tunnel heartbeat error %s", t.id, err)
gLog.d("%d write tunnel heartbeat error %s", t.id, err)
t.close()
return
}
+44 -37
View File
@@ -10,7 +10,7 @@ import (
"time"
)
const OpenP2PVersion = "3.24.33"
const OpenP2PVersion = "3.25.8"
const ProductName string = "openp2p"
const LeastSupportVersion = "3.0.0"
const SyncServerTimeVersion = "3.9.0"
@@ -20,10 +20,12 @@ const SupportIntranetVersion = "3.14.5"
const SupportDualTunnelVersion = "3.15.5"
const IPv6PunchVersion = "3.24.9"
const SupportUDP4DirectVersion = "3.24.16"
const SupportMultiDirectVersion = "3.25.1"
const (
NATDetectPort1 = 27180
NATDetectPort2 = 27181
WsPort = 27183
WsPort2 = 465
UDPPort1 = 27182
UDPPort2 = 27183
)
@@ -124,41 +126,42 @@ const (
// MsgP2P sub type message
const (
MsgPunchHandshake = iota
MsgPunchHandshakeAck
MsgTunnelHandshake
MsgTunnelHandshakeAck
MsgTunnelHeartbeat
MsgTunnelHeartbeatAck
MsgOverlayConnectReq
MsgOverlayConnectRsp
MsgOverlayDisconnectReq
MsgOverlayData
MsgRelayData
MsgRelayHeartbeat
MsgRelayHeartbeatAck
MsgNodeData
MsgRelayNodeData
MsgNodeDataMP
MsgNodeDataMPAck
MsgRelayHeartbeatAck2
MsgPunchHandshake = 0
MsgPunchHandshakeAck = 1
MsgTunnelHandshake = 2
MsgTunnelHandshakeAck = 3
MsgTunnelHeartbeat = 4
MsgTunnelHeartbeatAck = 5
MsgOverlayConnectReq = 6
MsgOverlayConnectRsp = 7
MsgOverlayDisconnectReq = 8
MsgOverlayData = 9
MsgRelayData = 10
MsgRelayHeartbeat = 11
MsgRelayHeartbeatAck = 12
MsgNodeData = 13
MsgRelayNodeData = 14
MsgNodeDataMP = 15
MsgNodeDataMPAck = 16
MsgRelayHeartbeatAck2 = 17
)
// MsgRelay sub type message
const (
MsgRelayNodeReq = iota
MsgRelayNodeRsp
MsgRelayNodeReq = 0
MsgRelayNodeRsp = 1
)
// MsgReport sub type message
const (
MsgReportBasic = iota
MsgReportQuery
MsgReportConnect
MsgReportApps
MsgReportLog
MsgReportMemApps
MsgReportResponse
MsgReportBasic = 0
MsgReportQuery = 1
MsgReportConnect = 2
MsgReportApps = 3
MsgReportLog = 4
MsgReportMemApps = 5
MsgReportResponse = 6
MsgReportBasicRsp = 7
)
const (
@@ -218,19 +221,19 @@ const (
)
const (
MsgQueryPeerInfoReq = iota
MsgQueryPeerInfoRsp
MsgQueryPeerInfoReq = 0
MsgQueryPeerInfoRsp = 1
)
const (
MsgSDWANInfoReq = iota
MsgSDWANInfoRsp
MsgSDWANInfoReq = 0
MsgSDWANInfoRsp = 1
)
// MsgNATDetect
const (
MsgNAT = iota
MsgPublicIP
MsgNAT = 0
MsgPublicIP = 1
)
func newMessage(mainType uint16, subType uint16, packet interface{}) ([]byte, error) {
@@ -320,6 +323,8 @@ type LoginRsp struct {
Token uint64 `json:"token,omitempty"`
Ts int64 `json:"ts,omitempty"`
LoginMaxDelay int `json:"loginMaxDelay,omitempty"` // seconds
Forcev6 int `json:"forcev6,omitempty"`
PublicIPPort int `json:"publicIPPort,omitempty"`
}
type NatDetectReq struct {
@@ -394,6 +399,7 @@ type ReportBasic struct {
LanIP string `json:"lanIP,omitempty"`
HasIPv4 int `json:"hasIPv4,omitempty"`
IPv6 string `json:"IPv6,omitempty"`
PublicIPPort int `json:"publicIPPort,omitempty"`
HasUPNPorNATPMP int `json:"hasUPNPorNATPMP,omitempty"`
Version string `json:"version,omitempty"`
NetInfo NetInfo `json:"netInfo,omitempty"`
@@ -498,9 +504,10 @@ type ProfileInfo struct {
}
type EditNode struct {
NewName string `json:"newName,omitempty"`
Bandwidth int `json:"bandwidth,omitempty"`
Forcev6 int `json:"forcev6,omitempty"`
NewName string `json:"newName,omitempty"`
Bandwidth int `json:"bandwidth,omitempty"`
Forcev6 int `json:"forcev6,omitempty"`
PublicIPPort int `json:"publicIPPort,omitempty"`
}
type QueryPeerInfoReq struct {
+15 -1
View File
@@ -57,6 +57,10 @@ func (s *p2pSDWAN) reset() {
gLog.i("reset sdwan when network disconnected")
// clear sysroute
delRoutesByGateway(s.gateway.String())
s.sysRoute.Range(func(key, value interface{}) bool {
s.sysRoute.Delete(key)
return true
})
// clear internel route
s.internalRoute = NewIPTree("")
// clear p2papp
@@ -67,6 +71,7 @@ func (s *p2pSDWAN) reset() {
gConf.resetSDWAN()
}
func (s *p2pSDWAN) init() error {
gConf.Network.previousIP = gConf.Network.publicIP
if gConf.getSDWAN().Gateway == "" {
@@ -88,6 +93,15 @@ func (s *p2pSDWAN) init() error {
s.internalRoute.Del(node.IP, node.IP)
ipNum, _ := inetAtoN(node.IP)
s.sysRoute.Delete(ipNum)
// if node.Name == gConf.Network.Node {
// // this is local node, need rm all client-side apps
// GNetwork.apps.Range(func(id, i interface{}) bool {
// app := i.(*p2pApp)
// if app.config.is
// return true
// })
// continue
// }
gConf.delete(AppConfig{SrcPort: 0, PeerNode: node.Name})
GNetwork.DeleteApp(AppConfig{SrcPort: 0, PeerNode: node.Name})
arr := strings.Split(node.Resource, ",")
@@ -309,7 +323,7 @@ func handleSDWAN(subType uint16, msg []byte) error {
}
gLog.i("sdwan init:%s", prettyJson(rsp))
// GNetwork.sdwan.detail = &rsp
if gConf.Network.previousIP != gConf.Network.publicIP || gConf.getSDWAN().CentralNode != rsp.CentralNode {
if gConf.Network.previousIP != gConf.Network.publicIP || gConf.getSDWAN().CentralNode != rsp.CentralNode || gConf.getSDWAN().Gateway != rsp.Gateway {
GNetwork.sdwan.reset()
preAndroidSDWANConfig = "" // let androind app reset vpnservice
}
+3 -3
View File
@@ -42,7 +42,7 @@ func DefaultWriteBytes(ul underlay, mainType, subType uint16, data []byte) error
writeBytes := append(encodeHeader(mainType, subType, uint32(len(data))), data...)
ul.SetWriteDeadline(time.Now().Add(TunnelHeartbeatTime / 2))
ul.WLock()
_, err := ul.Write(writeBytes)
err := writeFull(ul, writeBytes)
ul.WUnlock()
return err
}
@@ -50,7 +50,7 @@ func DefaultWriteBytes(ul underlay, mainType, subType uint16, data []byte) error
func DefaultWriteBuffer(ul underlay, data []byte) error {
ul.SetWriteDeadline(time.Now().Add(TunnelHeartbeatTime / 2))
ul.WLock()
_, err := ul.Write(data)
err := writeFull(ul, data)
ul.WUnlock()
return err
}
@@ -62,7 +62,7 @@ func DefaultWriteMessage(ul underlay, mainType uint16, subType uint16, packet in
}
ul.SetWriteDeadline(time.Now().Add(TunnelHeartbeatTime / 2))
ul.WLock()
_, err = ul.Write(writeBytes)
err = writeFull(ul, writeBytes)
ul.WUnlock()
return err
}
+14 -25
View File
@@ -16,14 +16,14 @@ import (
"github.com/quic-go/quic-go"
)
// quic.Dial do not support version 44, disable it
var quicVersion []quic.Version
// quic.DialContext do not support version 44,disable it
var quicVersion []quic.VersionNumber
type underlayQUIC struct {
listener *quic.Listener
listener quic.Listener
writeMtx *sync.Mutex
*quic.Stream
*quic.Conn
quic.Stream
quic.Connection
}
func (conn *underlayQUIC) Protocol() string {
@@ -47,17 +47,8 @@ func (conn *underlayQUIC) WriteMessage(mainType uint16, subType uint16, packet i
}
func (conn *underlayQUIC) Close() error {
// CancelRead expects a StreamErrorCode; using 1 as before (application-defined)
if conn.Stream != nil {
conn.Stream.CancelRead(1)
// close send-side of stream
_ = conn.Stream.Close()
}
if conn.Conn != nil {
// CloseWithError expects an ApplicationErrorCode and a description.
// 0 is zero-value; keep behavior similar to old CloseWithError(0,"")
_ = conn.Conn.CloseWithError(0, "")
}
conn.Stream.CancelRead(1)
conn.Connection.CloseWithError(0, "")
conn.CloseListener()
return nil
}
@@ -69,7 +60,7 @@ func (conn *underlayQUIC) WUnlock() {
}
func (conn *underlayQUIC) CloseListener() {
if conn.listener != nil {
_ = conn.listener.Close()
conn.listener.Close()
}
}
@@ -85,7 +76,7 @@ func (conn *underlayQUIC) Accept() error {
return err
}
conn.Stream = stream
conn.Conn = sess
conn.Connection = sess
return nil
}
@@ -105,25 +96,23 @@ func listenQuic(addr string, idleTimeout time.Duration) (*underlayQUIC, error) {
return ul, nil
}
func dialQuic(pconn *net.UDPConn, remoteAddr *net.UDPAddr, timeout time.Duration) (*underlayQUIC, error) {
func dialQuic(conn *net.UDPConn, remoteAddr *net.UDPAddr, timeout time.Duration) (*underlayQUIC, error) {
tlsConf := &tls.Config{
InsecureSkipVerify: true,
NextProtos: []string{"openp2pv1"},
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
// New API: quic.Dial(ctx, packetConn, remoteAddr, tlsConf, quicConfig)
connection, err := quic.Dial(ctx, pconn, remoteAddr, tlsConf,
Connection, err := quic.DialContext(ctx, conn, remoteAddr, conn.LocalAddr().String(), tlsConf,
&quic.Config{Versions: quicVersion, MaxIdleTimeout: TunnelIdleTimeout, DisablePathMTUDiscovery: true})
if err != nil {
return nil, fmt.Errorf("quic.Dial error:%s", err)
return nil, fmt.Errorf("quic.DialContext error:%s", err)
}
stream, err := connection.OpenStreamSync(context.Background())
stream, err := Connection.OpenStreamSync(context.Background())
if err != nil {
return nil, fmt.Errorf("OpenStreamSync error:%s", err)
}
qConn := &underlayQUIC{nil, &sync.Mutex{}, stream, connection}
qConn := &underlayQUIC{nil, &sync.Mutex{}, stream, Connection}
return qConn, nil
}
+3 -3
View File
@@ -9,7 +9,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
@@ -49,7 +48,7 @@ func update(host string, port int) error {
gLog.e("get update info error:%s", rsp.Status)
return err
}
rspBuf, err := ioutil.ReadAll(rsp.Body)
rspBuf, err := io.ReadAll(rsp.Body)
if err != nil {
gLog.e("update:read update list failed:%s", err)
return err
@@ -94,7 +93,8 @@ func downloadFile(url string, checksum string, dstFile string) error {
RootCAs: caCertPool,
InsecureSkipVerify: gConf.TLSInsecureSkipVerify},
}
client := &http.Client{Transport: tr}
client := &http.Client{Transport: tr,
Timeout: 60 * time.Second}
response, err := client.Get(url)
if err != nil {
gLog.e("download url %s error:%s", url, err)
+11 -29
View File
@@ -17,13 +17,13 @@ type v4Listener struct {
acceptCh chan bool
running bool
tcpListener *net.TCPListener
udpListener *quic.Listener
udpListener quic.Listener
wg sync.WaitGroup
}
func (vl *v4Listener) start() {
vl.running = true
vl.acceptCh = make(chan bool, 500)
v4l.acceptCh = make(chan bool, 500)
vl.wg.Add(1)
go func() {
defer vl.wg.Done()
@@ -56,11 +56,11 @@ func (vl *v4Listener) stop() {
func (vl *v4Listener) listenTCP() error {
gLog.d("v4Listener listenTCP %d start", vl.port)
defer gLog.d("v4Listener listenTCP %d end", vl.port)
addr, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("0.0.0.0:%d", vl.port))
addr, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("0.0.0.0:%d", vl.port)) // system will auto listen both v4 and v6
var err error
vl.tcpListener, err = net.ListenTCP("tcp", addr)
if err != nil {
gLog.e("v4Listener listen %d error:%s", vl.port, err)
gLog.e("v4Listener listen %d error:", vl.port, err)
return err
}
defer vl.tcpListener.Close()
@@ -69,11 +69,7 @@ func (vl *v4Listener) listenTCP() error {
if err != nil {
break
}
utcp := &underlayTCP{
writeMtx: &sync.Mutex{},
Conn: c,
connectTime: time.Now(),
}
utcp := &underlayTCP{writeMtx: &sync.Mutex{}, Conn: c, connectTime: time.Now()}
go vl.handleConnection(utcp)
}
vl.tcpListener = nil
@@ -84,15 +80,8 @@ func (vl *v4Listener) listenUDP() error {
gLog.d("v4Listener listenUDP %d start", vl.port)
defer gLog.d("v4Listener listenUDP %d end", vl.port)
var err error
vl.udpListener, err = quic.ListenAddr(
fmt.Sprintf("0.0.0.0:%d", vl.port),
generateTLSConfig(),
&quic.Config{
Versions: quicVersion,
MaxIdleTimeout: TunnelIdleTimeout,
DisablePathMTUDiscovery: true,
},
)
vl.udpListener, err = quic.ListenAddr(fmt.Sprintf("0.0.0.0:%d", vl.port), generateTLSConfig(),
&quic.Config{Versions: quicVersion, MaxIdleTimeout: TunnelIdleTimeout, DisablePathMTUDiscovery: true})
if err != nil {
return err
}
@@ -108,14 +97,7 @@ func (vl *v4Listener) listenUDP() error {
if err != nil {
break
}
ul := &underlayQUIC{
listener: nil,
writeMtx: &sync.Mutex{},
Stream: stream,
Conn: sess,
}
ul := &underlayQUIC{writeMtx: &sync.Mutex{}, Stream: stream, Connection: sess}
go vl.handleConnection(ul)
}
vl.udpListener = nil
@@ -128,14 +110,14 @@ func (vl *v4Listener) handleConnection(ul underlay) {
_, buff, err := ul.ReadBuffer()
if err != nil || buff == nil {
gLog.e("v4Listener read MsgTunnelHandshake error:%s", err)
return
}
ul.WriteBytes(MsgP2P, MsgTunnelHandshakeAck, buff)
var tid uint64
if string(buff) == "OpenP2P,hello" { // old client
// save remoteIP as key
remoteAddr := ul.RemoteAddr().(*net.TCPAddr).IP
ipBytes := remoteAddr.To4()
tid = uint64(binary.BigEndian.Uint32(ipBytes))
tid = uint64(binary.BigEndian.Uint32(ipBytes)) // bytes not enough for uint64
gLog.d("hello %s", string(buff))
} else {
if len(buff) < 8 {
@@ -164,7 +146,7 @@ func (vl *v4Listener) handleConnection(ul underlay) {
func (vl *v4Listener) getUnderlay(tid uint64) underlay {
for i := 0; i < 100; i++ {
select {
case <-time.After(50 * time.Millisecond):
case <-time.After(time.Millisecond * 50):
case <-vl.acceptCh:
}
if u, ok := vl.conns.LoadAndDelete(tid); ok {