refactor update and fix token loss bug

This commit is contained in:
TenderIronh
2025-11-17 10:00:50 +08:00
parent 6639f40d70
commit 57fe6986b0
4 changed files with 301 additions and 106 deletions
+114 -3
View File
@@ -2,18 +2,22 @@ package openp2p
import ( import (
"bytes" "bytes"
"context"
"crypto/aes" "crypto/aes"
"crypto/cipher" "crypto/cipher"
"crypto/tls" "crypto/tls"
"encoding/binary" "encoding/binary"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"math"
"math/big" "math/big"
"math/rand" "math/rand"
"net" "net"
"net/http" "net/http"
"os" "os"
"os/exec" "os/exec"
"runtime"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@@ -128,19 +132,19 @@ func netInfo() *NetInfo {
client := &http.Client{Transport: tr, Timeout: time.Second * 10} client := &http.Client{Transport: tr, Timeout: time.Second * 10}
r, err := client.Get("https://ifconfig.co/json") r, err := client.Get("https://ifconfig.co/json")
if err != nil { if err != nil {
gLog.Println(LvDEBUG, "netInfo error:", err) gLog.d("netInfo error:%s", err)
continue continue
} }
defer r.Body.Close() defer r.Body.Close()
buf := make([]byte, 1024*64) buf := make([]byte, 1024*64)
n, err := r.Body.Read(buf) n, err := r.Body.Read(buf)
if err != nil { if err != nil {
gLog.Println(LvDEBUG, "netInfo error:", err) gLog.d("netInfo error:%s", err)
continue continue
} }
rsp := NetInfo{} rsp := NetInfo{}
if err = json.Unmarshal(buf[:n], &rsp); err != nil { if err = json.Unmarshal(buf[:n], &rsp); err != nil {
gLog.Printf(LvERROR, "wrong NetInfo:%s", err) gLog.e("wrong NetInfo:%s", err)
continue continue
} }
return &rsp return &rsp
@@ -280,3 +284,110 @@ func calculateChecksum(data []byte) uint16 {
return uint16(^sum) return uint16(^sum)
} }
func min(nums ...int32) int32 {
if len(nums) == 0 {
return 0 // 如果没有输入,返回最大值
}
minVal := nums[0]
for _, num := range nums[1:] {
if num < minVal {
minVal = num
}
}
return minVal
}
func calcRetryTimeRelay(x float64) float64 {
return 10 + math.Exp(0.8*(x-3.6))
}
func calcRetryTimeDirect(x float64) float64 {
return 10 + math.Exp(2.8*(x-4))
}
func isAndroid() bool {
if runtime.GOOS == "android" {
return true
}
data, err := os.ReadFile("/proc/version")
if err != nil {
return false
}
return strings.Contains(string(data), "Android")
}
func moveFile(src, dst string) error {
err := os.Rename(src, dst)
if err == nil {
return nil
}
// windows could not rename running executable, so copy then delete
if runtime.GOOS == "windows" {
err = copyFile(src, dst)
if err != nil {
return err
}
os.Remove(src)
}
return nil
}
func copyFile(src, dst string) error {
sourceFile, err := os.Open(src)
if err != nil {
return err
}
defer sourceFile.Close()
destFile, err := os.Create(dst)
if err != nil {
return err
}
defer destFile.Close()
_, err = io.Copy(destFile, sourceFile)
if err != nil {
return err
}
return destFile.Sync()
}
func resolveServerIP(host string) ([]string, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// 先系统 DNS
ips, err := net.DefaultResolver.LookupHost(ctx, host)
if err == nil && len(ips) > 0 {
gLog.i("system dns resolved %s -> %v", host, ips)
return ips, nil
}
gLog.e("system dns resolve failed for %s: %v", host, err)
gLog.i("retry with fallback dns...")
// 再 fallback dns
return lookupWithCustomDNS(ctx, host)
}
func lookupWithCustomDNS(ctx context.Context, domain string) ([]string, error) {
resolver := &net.Resolver{
PreferGo: true,
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
dialer := &net.Dialer{Timeout: 5 * time.Second}
// 先 119.29.29.29
conn, err := dialer.DialContext(ctx, network, "119.29.29.29:53")
if err == nil {
return conn, nil
}
// 再 8.8.8.8
return dialer.DialContext(ctx, network, "8.8.8.8:53")
},
}
return resolver.LookupHost(ctx, domain)
}
+42 -42
View File
@@ -79,8 +79,11 @@ type Config struct {
LogLevel int LogLevel int
MaxLogSize int MaxLogSize int
TLSInsecureSkipVerify bool
Forcev6 bool
daemonMode bool daemonMode bool
mtx sync.Mutex mtx sync.RWMutex
fileMtx sync.Mutex
sdwanMtx sync.Mutex sdwanMtx sync.Mutex
sdwan SDWANInfo sdwan SDWANInfo
delNodes []*SDWANNode delNodes []*SDWANNode
@@ -251,31 +254,42 @@ func (c *Config) delete(app AppConfig) {
} }
func (c *Config) save() { func (c *Config) save() {
// c.mtx.Lock() c.fileMtx.Lock()
// defer c.mtx.Unlock() // internal call defer c.fileMtx.Unlock()
if c.Network.Token == 0 { if c.Network.Token == 0 {
gLog.e("c.Network.Token == 0 skip save")
return return
} }
data, _ := json.MarshalIndent(c, "", " ") data, err := json.MarshalIndent(c, "", " ")
err := os.WriteFile("config.json", data, 0644) if err != nil || len(data) < 16 {
if err != nil { gLog.e("MarshalIndent config.json error:%v, len=%d", err, len(data))
gLog.Println(LvERROR, "save config.json error:", err)
}
}
func (c *Config) saveCache() {
// c.mtx.Lock()
// defer c.mtx.Unlock() // internal call
if c.Network.Token == 0 {
return return
} }
data, _ := json.MarshalIndent(c, "", " ") err = os.WriteFile("config.json0", data, 0644)
err := os.WriteFile("config.json0", data, 0644)
if err != nil { if err != nil {
gLog.Println(LvERROR, "save config.json0 error:", err) gLog.e("save config.json error:%v", err)
}
} }
// verify if the file is written correctly
data, err = os.ReadFile("config.json0")
if err != nil {
return
}
var tmpConfig Config
err = json.Unmarshal(data, &tmpConfig)
if err != nil {
gLog.e("parse config.json error:", err)
return
}
err = os.Rename("config.json0", "config.json")
if err != nil {
gLog.e("rename config file error:%v", err)
}
}
// -d run, then worker serverport always WsPort.
// func init() {
func init() { func init() {
gConf.LogLevel = int(LvINFO) gConf.LogLevel = int(LvINFO)
gConf.MaxLogSize = 1024 * 1024 gConf.MaxLogSize = 1024 * 1024
@@ -286,19 +300,19 @@ func init() {
} }
func (c *Config) load() error { func (c *Config) load() error {
c.mtx.Lock() c.fileMtx.Lock()
defer c.mtx.Unlock() defer c.fileMtx.Unlock()
data, err := os.ReadFile("config.json") data, err := os.ReadFile("config.json")
if err != nil { if err != nil {
return c.loadCache() return err
} }
c.mtx.Lock()
defer c.mtx.Unlock()
err = json.Unmarshal(data, &c) err = json.Unmarshal(data, &c)
if err != nil { if err != nil {
gLog.Println(LvERROR, "parse config.json error:", err) gLog.e("parse config.json error:", err)
// try cache return err
return c.loadCache()
} }
// load ok. cache it
var filteredApps []*AppConfig // filter memapp var filteredApps []*AppConfig // filter memapp
for _, app := range c.Apps { for _, app := range c.Apps {
if app.SrcPort != 0 { if app.SrcPort != 0 {
@@ -306,19 +320,7 @@ func (c *Config) load() error {
} }
} }
c.Apps = filteredApps c.Apps = filteredApps
c.saveCache() c.Network.natType = NATUnknown
return err
}
func (c *Config) loadCache() error {
data, err := os.ReadFile("config.json0")
if err != nil {
return err
}
err = json.Unmarshal(data, &c)
if err != nil {
gLog.Println(LvERROR, "parse config.json0 error:", err)
}
return err return err
} }
@@ -326,7 +328,6 @@ func (c *Config) loadCache() error {
func (c *Config) setToken(token uint64) { func (c *Config) setToken(token uint64) {
c.mtx.Lock() c.mtx.Lock()
defer c.mtx.Unlock() defer c.mtx.Unlock()
defer c.save()
if token != 0 { if token != 0 {
c.Network.Token = token c.Network.Token = token
} }
@@ -334,13 +335,11 @@ func (c *Config) setToken(token uint64) {
func (c *Config) setUser(user string) { func (c *Config) setUser(user string) {
c.mtx.Lock() c.mtx.Lock()
defer c.mtx.Unlock() defer c.mtx.Unlock()
defer c.save()
c.Network.User = user c.Network.User = user
} }
func (c *Config) setNode(node string) { func (c *Config) setNode(node string) {
c.mtx.Lock() c.mtx.Lock()
defer c.mtx.Unlock() defer c.mtx.Unlock()
defer c.save()
c.Network.Node = node c.Network.Node = node
c.Network.nodeID = NodeNameToID(c.Network.Node) c.Network.nodeID = NodeNameToID(c.Network.Node)
} }
@@ -379,6 +378,7 @@ type NetworkConfig struct {
mac string mac string
os string os string
publicIP string publicIP string
previousIP string // for publicIP change detect
natType int natType int
hasIPv4 int hasIPv4 int
publicIPv6 string // must lowwer-case not save json publicIPv6 string // must lowwer-case not save json
@@ -505,9 +505,9 @@ func parseParams(subCommand string, cmd string) {
gConf.Network.UDPPort1 = UDPPort1 gConf.Network.UDPPort1 = UDPPort1
gConf.Network.UDPPort2 = UDPPort2 gConf.Network.UDPPort2 = UDPPort2
gLog.setLevel(LogLevel(gConf.LogLevel)) gLog.setLevel(LogLevel(gConf.LogLevel))
gLog.setMaxSize(int64(gConf.MaxLogSize))
if *notVerbose { if *notVerbose {
gLog.setMode(LogFile) gLog.setMode(LogFile)
} }
// gConf.mtx.Unlock()
gConf.save() gConf.save()
} }
+64 -1
View File
@@ -74,7 +74,7 @@ func encodeHeader(mainType uint16, subType uint16, len uint32) []byte {
return headBuf.Bytes() return headBuf.Bytes()
} }
// Message type // Message main type
const ( const (
MsgLogin = 0 MsgLogin = 0
MsgHeartbeat = 1 MsgHeartbeat = 1
@@ -109,6 +109,8 @@ const (
MsgPushReportMemApps = 17 MsgPushReportMemApps = 17
MsgPushServerSideSaveMemApp = 18 MsgPushServerSideSaveMemApp = 18
MsgPushCheckRemoteService = 19 MsgPushCheckRemoteService = 19
MsgPushSpecTunnel = 20
MsgPushReportHeap = 21
) )
// MsgP2P sub type message // MsgP2P sub type message
@@ -128,6 +130,9 @@ const (
MsgRelayHeartbeatAck MsgRelayHeartbeatAck
MsgNodeData MsgNodeData
MsgRelayNodeData MsgRelayNodeData
MsgNodeDataMP
MsgNodeDataMPAck
MsgRelayHeartbeatAck2
) )
// MsgRelay sub type message // MsgRelay sub type message
@@ -243,6 +248,21 @@ func newMessage(mainType uint16, subType uint16, packet interface{}) ([]byte, er
return writeBytes, nil return writeBytes, nil
} }
func newMessageWithBuff(mainType uint16, subType uint16, data []byte) ([]byte, error) {
head := openP2PHeader{
uint32(len(data)),
mainType,
subType,
}
headBuf := new(bytes.Buffer)
err := binary.Write(headBuf, binary.LittleEndian, head)
if err != nil {
return nil, err
}
writeBytes := append(headBuf.Bytes(), data...)
return writeBytes, nil
}
func NodeNameToID(name string) uint64 { func NodeNameToID(name string) uint64 {
return crc64.Checksum([]byte(name), crc64.MakeTable(crc64.ISO)) return crc64.Checksum([]byte(name), crc64.MakeTable(crc64.ISO))
} }
@@ -346,6 +366,8 @@ type AddRelayTunnelReq struct {
RelayMode string `json:"relayMode,omitempty"` RelayMode string `json:"relayMode,omitempty"`
AppID uint64 `json:"appID,omitempty"` // deprecated AppID uint64 `json:"appID,omitempty"` // deprecated
AppKey uint64 `json:"appKey,omitempty"` // deprecated AppKey uint64 `json:"appKey,omitempty"` // deprecated
UnderlayProtocol string `json:"underlayProtocol,omitempty"` // quic or kcp, default quic
PunchPriority int `json:"punchPriority,omitempty"`
} }
type APPKeySync struct { type APPKeySync struct {
@@ -356,6 +378,7 @@ type APPKeySync struct {
type RelayHeartbeat struct { type RelayHeartbeat struct {
From string `json:"from,omitempty"` From string `json:"from,omitempty"`
RelayTunnelID uint64 `json:"relayTunnelID,omitempty"` RelayTunnelID uint64 `json:"relayTunnelID,omitempty"`
RelayTunnelID2 uint64 `json:"relayTunnelID2,omitempty"`
AppID uint64 `json:"appID,omitempty"` AppID uint64 `json:"appID,omitempty"`
} }
@@ -416,12 +439,15 @@ type AppInfo struct {
type ReportApps struct { type ReportApps struct {
Apps []AppInfo Apps []AppInfo
TunError string `json:"tunError,omitempty"`
} }
type ReportLogReq struct { type ReportLogReq struct {
FileName string `json:"fileName,omitempty"` FileName string `json:"fileName,omitempty"`
Offset int64 `json:"offset,omitempty"` Offset int64 `json:"offset,omitempty"`
Len int64 `json:"len,omitempty"` Len int64 `json:"len,omitempty"`
IsSetLogLevel int64 `json:"isSetLogLevel,omitempty"`
LogLevel int64 `json:"loglevel,omitempty"`
} }
type ReportLogRsp struct { type ReportLogRsp struct {
FileName string `json:"fileName,omitempty"` FileName string `json:"fileName,omitempty"`
@@ -434,6 +460,7 @@ type UpdateInfo struct {
Error int `json:"error,omitempty"` Error int `json:"error,omitempty"`
ErrorDetail string `json:"errorDetail,omitempty"` ErrorDetail string `json:"errorDetail,omitempty"`
Url string `json:"url,omitempty"` Url string `json:"url,omitempty"`
Url2 string `json:"url2,omitempty"`
} }
type NetInfo struct { type NetInfo struct {
@@ -467,6 +494,7 @@ type ProfileInfo struct {
type EditNode struct { type EditNode struct {
NewName string `json:"newName,omitempty"` NewName string `json:"newName,omitempty"`
Bandwidth int `json:"bandwidth,omitempty"` Bandwidth int `json:"bandwidth,omitempty"`
Forcev6 int `json:"forcev6,omitempty"`
} }
type QueryPeerInfoReq struct { type QueryPeerInfoReq struct {
@@ -501,6 +529,8 @@ type SDWANInfo struct {
ForceRelay int32 `json:"forceRelay,omitempty"` ForceRelay int32 `json:"forceRelay,omitempty"`
PunchPriority int32 `json:"punchPriority,omitempty"` PunchPriority int32 `json:"punchPriority,omitempty"`
Enable int32 `json:"enable,omitempty"` Enable int32 `json:"enable,omitempty"`
TunnelNum int32 `json:"tunnelNum,omitempty"`
Mtu int32 `json:"mtu,omitempty"`
Nodes []*SDWANNode Nodes []*SDWANNode
} }
@@ -516,6 +546,10 @@ type ServerSideSaveMemApp struct {
RelayTunnelID uint64 `json:"relayTunnelID,omitempty"` // rtid, if not 0 relay RelayTunnelID uint64 `json:"relayTunnelID,omitempty"` // rtid, if not 0 relay
RelayMode string `json:"relayMode,omitempty"` RelayMode string `json:"relayMode,omitempty"`
AppID uint64 `json:"appID,omitempty"` AppID uint64 `json:"appID,omitempty"`
AppKey uint64 `json:"appKey,omitempty"`
RelayIndex uint32 `json:"relayIndex,omitempty"`
TunnelNum uint32 `json:"tunnelNum,omitempty"`
SrcPort uint32 `json:"srcPort,omitempty"`
} }
type CheckRemoteService struct { type CheckRemoteService struct {
@@ -523,6 +557,10 @@ type CheckRemoteService struct {
Port uint32 `json:"port,omitempty"` Port uint32 `json:"port,omitempty"`
} }
type SpecTunnel struct {
TunnelIndex uint32 `json:"tunnelIndex,omitempty"`
}
const rootCA = `-----BEGIN CERTIFICATE----- const rootCA = `-----BEGIN CERTIFICATE-----
MIIDhTCCAm0CFHm0cd8dnGCbUW/OcS56jf0gvRk7MA0GCSqGSIb3DQEBCwUAMH4x MIIDhTCCAm0CFHm0cd8dnGCbUW/OcS56jf0gvRk7MA0GCSqGSIb3DQEBCwUAMH4x
CzAJBgNVBAYTAkNOMQswCQYDVQQIDAJHRDETMBEGA1UECgwKb3BlbnAycC5jbjET CzAJBgNVBAYTAkNOMQswCQYDVQQIDAJHRDETMBEGA1UECgwKb3BlbnAycC5jbjET
@@ -545,6 +583,31 @@ RVtXS+DplMClQ5QSlv3StwcWOsjyiAimNfLEU5xoEfq17yOJUTU1OTL4YOt16QUc
C1tnzFr3k/ioqFR7cnyzNrbjlfPOmO9l2WReEbMP3bvaSHm6EcpJKS8= C1tnzFr3k/ioqFR7cnyzNrbjlfPOmO9l2WReEbMP3bvaSHm6EcpJKS8=
-----END CERTIFICATE-----` -----END CERTIFICATE-----`
const rootEdgeCA = `-----BEGIN CERTIFICATE-----
MIID/zCCAuegAwIBAgIUI53UqyuJSa74NFIKherg5WTjtl4wDQYJKoZIhvcNAQEL
BQAwgYYxCzAJBgNVBAYTAkNOMQswCQYDVQQIDAJHRDETMBEGA1UECgwKb3BlbnAy
cC5jbjETMBEGA1UECwwKb3BlbnAycC5jbjEbMBkGA1UEAwwSb3BlbnAycC5jbiBS
b290IENBMSMwIQYJKoZIhvcNAQkBFhRvcGVucDJwLmNuQGdtYWlsLmNvbTAeFw0y
NTA5MDMwNTExMTBaFw0zNTA5MDEwNTExMTBaMIGGMQswCQYDVQQGEwJDTjELMAkG
A1UECAwCR0QxEzARBgNVBAoMCm9wZW5wMnAuY24xEzARBgNVBAsMCm9wZW5wMnAu
Y24xGzAZBgNVBAMMEm9wZW5wMnAuY24gUm9vdCBDQTEjMCEGCSqGSIb3DQEJARYU
b3BlbnAycC5jbkBnbWFpbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQC/aHC0opWx1MFkXYI+Mm0CkMi7nB5XaD3K/DGGtA/kadhayFSWb6Y2+UWW
s6OYBy7NmQRJgTedS4siQA6JEG4H3FBbz8URLt4TH/EP9+6QB0Z+P0arvUXNkl4k
7cALmblaiqjq2M199+FWKhDWH2vMr1htY9Y3ldivLRMeH76diKgf8NvsX+wGR8bZ
4MlJMFln0UeUYKIbekK7DmA5/9f2A/2Nrmi84PKGHU+0ZjB7gik/slW5zH0k7e+S
wNtTuf8+6+t/LcJK9dWsS6f5+DOWmLcIWs6s/VMP9ODEzlY/hKMFk53+H+AjAZY/
J/qhOxLXMNlNjdjwSEFPBY/vwVEnAgMBAAGjYzBhMB0GA1UdDgQWBBTXSSeIvz/R
6A1pz0H4xBlV1Vu9kTAfBgNVHSMEGDAWgBTXSSeIvz/R6A1pz0H4xBlV1Vu9kTAP
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC
AQEABqvvKwM+k2NfIFf9tzo1EsD4rQunyn6K5Zhf/kspb9++2Onw/lDlOErxSLLz
C5aXn+B48honQeYEL/cYhH4duVQb0Zk71iF/PKDxYvF79Xbx9k7Kzg6RryaH8ZfQ
pyEao+Uc6O895F+SLBog5aHIbz8gFNCRVaSAv3xpUIyQ/haxyHHapaLqt/ueNFVP
qEG+9R41q55rEYb2ltINhumS3gb4qOcKI5pHuAw42pF8SShqaBIfFXSZ4u9ib7/k
CvHN0kDYavV6NRiCSRF6wMxmaF70WpfqQhGdw0WyIzJfMOtSdvctjfNCoaWy2V2s
nLaJXgiPehxIVGNC9dk/ZZzI2g==
-----END CERTIFICATE-----`
const ISRGRootX1 = `-----BEGIN CERTIFICATE----- const ISRGRootX1 = `-----BEGIN CERTIFICATE-----
MIIEJjCCAw6gAwIBAgISAztStWq026ej0RCsk3ErbUdPMA0GCSqGSIb3DQEBCwUA MIIEJjCCAw6gAwIBAgISAztStWq026ej0RCsk3ErbUdPMA0GCSqGSIb3DQEBCwUA
MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
+55 -34
View File
@@ -19,21 +19,21 @@ import (
) )
func update(host string, port int) error { func update(host string, port int) error {
gLog.Println(LvINFO, "update start") gLog.i("update start")
defer gLog.Println(LvINFO, "update end") defer gLog.i("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.e("Failed to load system root CAs:%s", err)
} else {
caCertPool = x509.NewCertPool() caCertPool = x509.NewCertPool()
} }
caCertPool.AppendCertsFromPEM([]byte(rootCA)) caCertPool.AppendCertsFromPEM([]byte(rootCA))
caCertPool.AppendCertsFromPEM([]byte(rootEdgeCA))
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: gConf.TLSInsecureSkipVerify},
}, },
Timeout: time.Second * 30, Timeout: time.Second * 30,
} }
@@ -41,99 +41,116 @@ func update(host string, port int) error {
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.e("update:query update list failed:%s", 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.e("get update info error:%s", 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.e("update:read update list failed:%s", 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.e("%s update info decode error:%s", string(rspBuf), err)
return err return err
} }
if updateInfo.Error != 0 { if updateInfo.Error != 0 {
gLog.Println(LvERROR, "update error:", updateInfo.Error, updateInfo.ErrorDetail) gLog.e("update error:%d,%s", 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.e("update: download failed:%s, retry...", err)
err = updateFile(updateInfo.Url2, "", "openp2p")
if err != nil {
gLog.e("update: download failed:%s", 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.e("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.e("Failed to load system root CAs:%s", err)
} else {
caCertPool = x509.NewCertPool() caCertPool = x509.NewCertPool()
} }
caCertPool.AppendCertsFromPEM([]byte(rootCA)) caCertPool.AppendCertsFromPEM([]byte(rootCA))
caCertPool.AppendCertsFromPEM([]byte(rootEdgeCA))
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: gConf.TLSInsecureSkipVerify},
} }
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.e("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.e("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.i("download %s ok", url)
gLog.Printf(LvINFO, "size: %d bytes", n) gLog.i("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.i("download %s", url)
tmpFile := filepath.Dir(os.Args[0]) + "/openp2p.tmp" tempDir := os.TempDir()
tmpFile := filepath.Join(tempDir, "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" backupBase := filepath.Base(os.Args[0])
err = os.Rename(os.Args[0], backupFile) // the old daemon process was using the 0 file, so it will prevent override it var backupFile string
if runtime.GOOS == "windows" {
backupFile = filepath.Join(tempDir, backupBase+"0")
} else {
backupFile = os.Args[0] + "0" // linux can not mv running executable to /tmp, because they are different volumns
}
gLog.i("backup file %s --> %s", os.Args[0], backupFile)
err = moveFile(os.Args[0], backupFile)
if err != nil { if err != nil {
gLog.Printf(LvINFO, " rename %s error:%s, retry 1", os.Args[0], err) if runtime.GOOS == "windows" {
backupFile = os.Args[0] + "1" backupFile = filepath.Join(tempDir, backupBase+"1")
err = os.Rename(os.Args[0], backupFile) } else {
backupFile = os.Args[0] + "1" // 1st update will mv deamon process to 0, 2nd update mv to 0 will failed, mv to 1
}
gLog.i("backup file %s --> %s", os.Args[0], backupFile)
err = moveFile(os.Args[0], backupFile)
if err != nil { if err != nil {
gLog.Printf(LvINFO, " rename %s error:%s", os.Args[0], err) gLog.e(" rename %s error:%s", os.Args[0], err)
return err
} }
} }
// extract // extract
gLog.Println(LvINFO, "extract files") gLog.i("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.e("extract error:%s. revert rename", err)
os.Rename(backupFile, os.Args[0]) moveFile(backupFile, os.Args[0])
return err return err
} }
os.Remove(tmpFile) os.Remove(tmpFile)
@@ -224,16 +241,20 @@ func extractTgz(dst, src string) error {
} }
func cleanTempFiles() { func cleanTempFiles() {
tmpFile := os.Args[0] + "0" tempDir := os.TempDir()
backupBase := filepath.Base(os.Args[0])
for i := 0; i < 2; i++ {
tmpFile := fmt.Sprintf("%s%d", os.Args[0], i)
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.d(" remove %s error:%s", tmpFile, err)
} }
} }
tmpFile = os.Args[0] + "1" tmpFile = fmt.Sprintf("%s%s%d", tempDir, backupBase, i)
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.d(" remove %s error:%s", tmpFile, err)
}
} }
} }
} }