diff --git a/device/receivesendproc.go b/device/receivesendproc.go index cc13a50..29c44d9 100644 --- a/device/receivesendproc.go +++ b/device/receivesendproc.go @@ -569,34 +569,23 @@ func (device *Device) process_UpdateSuperParamsMsg(peer *Peer, State_hash string return err } if SuperParams.PeerAliveTimeout <= 0 { - device.log.Errorf("SuperParams.PeerAliveTimeout <= 0: %v", SuperParams.PeerAliveTimeout) - return fmt.Errorf("SuperParams.PeerAliveTimeout <= 0: %v", SuperParams.PeerAliveTimeout) + device.log.Errorf("SuperParams.PeerAliveTimeout <= 0: %v, please check the config of the supernode", SuperParams.PeerAliveTimeout) + return fmt.Errorf("SuperParams.PeerAliveTimeout <= 0: %v, please check the config of the supernode", SuperParams.PeerAliveTimeout) } if SuperParams.SendPingInterval <= 0 { - device.log.Errorf("SuperParams.SendPingInterval <= 0: %v", SuperParams.SendPingInterval) - return fmt.Errorf("SuperParams.SendPingInterval <= 0: %v", SuperParams.SendPingInterval) + device.log.Errorf("SuperParams.SendPingInterval <= 0: %v, please check the config of the supernode", SuperParams.SendPingInterval) + return fmt.Errorf("SuperParams.SendPingInterval <= 0: %v, please check the config of the supernode", SuperParams.SendPingInterval) } - if SuperParams.HttpPostInterval <= 0 { - device.log.Errorf("SuperParams.HttpPostInterval <= 0: %v", SuperParams.HttpPostInterval) - return fmt.Errorf("SuperParams.HttpPostInterval <= 0: %v", SuperParams.HttpPostInterval) + if SuperParams.HttpPostInterval < 0 { + device.log.Errorf("SuperParams.HttpPostInterval < 0: %v, please check the config of the supernode", SuperParams.HttpPostInterval) + return fmt.Errorf("SuperParams.HttpPostInterval < 0: %v, please check the config of the supernode", SuperParams.HttpPostInterval) } device.EdgeConfig.DynamicRoute.PeerAliveTimeout = SuperParams.PeerAliveTimeout - - if device.EdgeConfig.DynamicRoute.SendPingInterval <= 0 { - device.EdgeConfig.DynamicRoute.SendPingInterval = SuperParams.SendPingInterval - device.Chan_SendPingStart <- struct{}{} - } else { - device.EdgeConfig.DynamicRoute.SendPingInterval = SuperParams.SendPingInterval - } - - if device.SuperConfig.HttpPostInterval <= 0 { - device.SuperConfig.HttpPostInterval = SuperParams.HttpPostInterval - device.Chan_HttpPostStart <- struct{}{} - } else { - device.SuperConfig.HttpPostInterval = SuperParams.HttpPostInterval - } - + device.EdgeConfig.DynamicRoute.SendPingInterval = SuperParams.SendPingInterval + device.SuperConfig.HttpPostInterval = SuperParams.HttpPostInterval + device.Chan_SendPingStart <- struct{}{} + device.Chan_HttpPostStart <- struct{}{} if SuperParams.AdditionalCost >= 0 { device.EdgeConfig.DynamicRoute.AdditionalCost = SuperParams.AdditionalCost } diff --git a/example_config/super_mode/s1.yaml b/example_config/super_mode/s1.yaml index afb5c06..cc9d9a4 100644 --- a/example_config/super_mode/s1.yaml +++ b/example_config/super_mode/s1.yaml @@ -1,5 +1,5 @@ nodename: NodeSuper -postscript: "" +postscript: example_config/echo.sh test privkeyv4: mL5IW0GuqbjgDeOJuPHBU2iJzBPNKhaNEXbIGwwYWWk= privkeyv6: +EdOKIoBp/EvIusHDsvXhV1RJYbyN3Qr8nxlz35wl3I= listenport: 3000 diff --git a/main_edge.go b/main_edge.go index b96478f..8814744 100644 --- a/main_edge.go +++ b/main_edge.go @@ -6,6 +6,7 @@ package main import ( + "encoding/binary" "errors" "fmt" "os" @@ -321,6 +322,22 @@ func Edge(configPath string, useUAPI bool, printExample bool, bindmode string) ( } if econfig.PostScript != "" { + envs := make(map[string]string) + nid := econfig.NodeID + nid_bytearr := []byte{0, 0} + binary.LittleEndian.PutUint16(nid_bytearr, uint16(nid)) + + envs["EG_MODE"] = "edge" + envs["EG_NODE_NAME"] = econfig.NodeName + envs["EG_NODE_ID_INT_DEC"] = fmt.Sprintf("%d", nid) + envs["EG_NODE_ID_BYTE0_DEC"] = fmt.Sprintf("%d", nid_bytearr[0]) + envs["EG_NODE_ID_BYTE1_DEC"] = fmt.Sprintf("%d", nid_bytearr[1]) + envs["EG_NODE_ID_INT_HEX"] = fmt.Sprintf("%x", nid) + envs["EG_NODE_ID_BYTE0_HEX"] = fmt.Sprintf("%X", nid_bytearr[0]) + envs["EG_NODE_ID_BYTE1_HEX"] = fmt.Sprintf("%X", nid_bytearr[1]) + envs["EG_INTERFACE_NAME"] = econfig.Interface.Name + envs["EG_INTERFACE_TYPE"] = econfig.Interface.Itype + cmdarg, err := shlex.Split(econfig.PostScript) if err != nil { return fmt.Errorf("Error parse PostScript %v\n", err) @@ -329,7 +346,10 @@ func Edge(configPath string, useUAPI bool, printExample bool, bindmode string) ( fmt.Printf("PostScript: exec.Command(%v)\n", cmdarg) } cmd := exec.Command(cmdarg[0], cmdarg[1:]...) - + cmd.Env = os.Environ() + for k, v := range envs { + cmd.Env = append(cmd.Env, k+"="+v) + } out, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("exec.Command(%v) failed with %v\n", cmdarg, err) @@ -338,6 +358,7 @@ func Edge(configPath string, useUAPI bool, printExample bool, bindmode string) ( fmt.Printf("PostScript output: %s\n", string(out)) } } + mtypes.SdNotify(false, mtypes.SdNotifyReady) // wait for program to terminate signal.Notify(term, syscall.SIGTERM) diff --git a/main_httpserver.go b/main_httpserver.go index 70164a7..4cabaf4 100644 --- a/main_httpserver.go +++ b/main_httpserver.go @@ -12,6 +12,7 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "time" "net/http" @@ -79,12 +80,12 @@ type HttpPeerInfo struct { } type PeerState struct { - NhTableState string - PeerInfoState string - SuperParamState string - JETSecret mtypes.JWTSecret - httpPostCount uint64 - LastSeen time.Time + NhTableState atomic.Value // string + PeerInfoState atomic.Value // string + SuperParamState atomic.Value // string + JETSecret atomic.Value // mtypes.JWTSecret + httpPostCount atomic.Value // uint64 + LastSeen atomic.Value // time.Time } type client struct { @@ -160,7 +161,7 @@ func get_api_peers(old_State_hash string) (api_peerinfo mtypes.API_Peers, StateH PSKey: peerinfo.PSKey, Connurl: &mtypes.API_connurl{}, } - if httpobj.http_PeerState[peerinfo.PubKey].LastSeen.Add(mtypes.S2TD(httpobj.http_sconfig.PeerAliveTimeout)).After(time.Now()) { + if httpobj.http_PeerState[peerinfo.PubKey].LastSeen.Load().(time.Time).Add(mtypes.S2TD(httpobj.http_sconfig.PeerAliveTimeout)).After(time.Now()) { connV4 := httpobj.http_device4.GetConnurl(peerinfo.NodeID) connV6 := httpobj.http_device6.GetConnurl(peerinfo.NodeID) if connV4 != "" { @@ -239,7 +240,7 @@ func get_superparams(w http.ResponseWriter, r *http.Request) { AdditionalCost: httpobj.http_PeerID2Info[NodeID].AdditionalCost, } SuperParamStr, _ := json.Marshal(SuperParams) - httpobj.http_PeerState[PubKey].SuperParamState = State + httpobj.http_PeerState[PubKey].SuperParamState.Store(State) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) w.Write([]byte(SuperParamStr)) @@ -291,7 +292,7 @@ func get_peerinfo(w http.ResponseWriter, r *http.Request) { } // Do something - httpobj.http_PeerState[PubKey].PeerInfoState = State + httpobj.http_PeerState[PubKey].PeerInfoState.Store(State) http_PeerInfo_2peer := make(mtypes.API_Peers) for PeerPubKey, peerinfo := range httpobj.http_PeerInfo { @@ -372,7 +373,7 @@ func get_nhtable(w http.ResponseWriter, r *http.Request) { return } - httpobj.http_PeerState[PubKey].NhTableState = State + httpobj.http_PeerState[PubKey].NhTableState.Store(State) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) w.Write([]byte(httpobj.http_NhTableStr)) @@ -404,7 +405,7 @@ func get_peerstate(w http.ResponseWriter, r *http.Request) { } for _, peerinfo := range httpobj.http_sconfig.Peers { - LastSeenStr := httpobj.http_PeerState[peerinfo.PubKey].LastSeen.String() + LastSeenStr := httpobj.http_PeerState[peerinfo.PubKey].LastSeen.Load().(time.Time).String() hs.PeerInfo[peerinfo.NodeID] = HttpPeerInfo{ Name: peerinfo.Name, LastSeen: LastSeenStr, @@ -470,7 +471,8 @@ func post_nodeinfo(w http.ResponseWriter, r *http.Request) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) } - return JWTSecret[:], nil + JWTSecretB := JWTSecret.Load().(mtypes.JWTSecret) + return JWTSecretB[:], nil }) if err != nil { w.WriteHeader(http.StatusBadRequest) @@ -486,7 +488,7 @@ func post_nodeinfo(w http.ResponseWriter, r *http.Request) { client_PostCount := token_claims.PostCount client_body_hash := token_claims.BodyHash - if client_PostCount < httpPostCount { + if client_PostCount < httpPostCount.Load().(uint64) { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(fmt.Sprintf("Request body: postcount too small: %v", httpPostCount))) return @@ -514,7 +516,7 @@ func post_nodeinfo(w http.ResponseWriter, r *http.Request) { httpobj.http_PeerIPs[PubKey].LocalIPv4 = client_report.LocalV4s httpobj.http_PeerIPs[PubKey].LocalIPv6 = client_report.LocalV6s - httpobj.http_PeerState[PubKey].httpPostCount = client_PostCount + 1 + httpobj.http_PeerState[PubKey].httpPostCount.Store(client_PostCount + 1) applied_pones := make([]mtypes.PongMsg, 0, len(client_report.Pongs)) for _, pong_msg := range client_report.Pongs { diff --git a/main_super.go b/main_super.go index a8c4736..8418e43 100644 --- a/main_super.go +++ b/main_super.go @@ -152,8 +152,8 @@ func Super(configPath string, useUAPI bool, printExample bool, bindmode string) if sconfig.PeerAliveTimeout <= 0 { return fmt.Errorf("PeerAliveTimeout must > 0 : %v", sconfig.PeerAliveTimeout) } - if sconfig.HttpPostInterval <= 0 { - return fmt.Errorf("HttpPostInterval must > 0 : %v", sconfig.HttpPostInterval) + if sconfig.HttpPostInterval < 0 { + return fmt.Errorf("HttpPostInterval must >= 0 : %v", sconfig.HttpPostInterval) } else if sconfig.HttpPostInterval > sconfig.PeerAliveTimeout { return fmt.Errorf("HttpPostInterval must <= PeerAliveTimeout : %v", sconfig.HttpPostInterval) } @@ -280,6 +280,7 @@ func Super(configPath string, useUAPI bool, printExample bool, bindmode string) fmt.Printf("PostScript output: %s\n", string(out)) } } + mtypes.SdNotify(false, mtypes.SdNotifyReady) signal.Notify(term, syscall.SIGTERM) signal.Notify(term, os.Interrupt) @@ -349,7 +350,16 @@ func super_peeradd(peerconf mtypes.SuperPeerInfo) error { } } httpobj.http_PeerID2Info[peerconf.NodeID] = peerconf - httpobj.http_PeerState[peerconf.PubKey] = &PeerState{} + + PS := PeerState{} + PS.NhTableState.Store("") // string + PS.PeerInfoState.Store("") // string + PS.SuperParamState.Store("") // string + PS.JETSecret.Store(mtypes.JWTSecret{}) // mtypes.JWTSecret + PS.httpPostCount.Store(uint64(0)) // uint64 + PS.LastSeen.Store(time.Time{}) // time.Time + httpobj.http_PeerState[peerconf.PubKey] = &PS + httpobj.http_PeerIPs[peerconf.PubKey] = &HttpPeerLocalIP{} return nil } @@ -405,15 +415,15 @@ func Event_server_event_hendler(graph *path.IG, events *mtypes.SUPER_Events) { httpobj.RLock() PubKey := httpobj.http_PeerID2Info[NodeID].PubKey if reg_msg.Node_id < mtypes.Special_NodeID { - httpobj.http_PeerState[PubKey].LastSeen = time.Now() - httpobj.http_PeerState[PubKey].JETSecret = reg_msg.JWTSecret - httpobj.http_PeerState[PubKey].httpPostCount = reg_msg.HttpPostCount - if httpobj.http_PeerState[PubKey].NhTableState == reg_msg.NhStateHash == false { - httpobj.http_PeerState[PubKey].NhTableState = reg_msg.NhStateHash + httpobj.http_PeerState[PubKey].LastSeen.Store(time.Now()) + httpobj.http_PeerState[PubKey].JETSecret.Store(reg_msg.JWTSecret) + httpobj.http_PeerState[PubKey].httpPostCount.Store(reg_msg.HttpPostCount) + if httpobj.http_PeerState[PubKey].NhTableState.Load().(string) == reg_msg.NhStateHash == false { + httpobj.http_PeerState[PubKey].NhTableState.Store(reg_msg.NhStateHash) should_push_nh = true } - if httpobj.http_PeerState[PubKey].PeerInfoState == reg_msg.PeerStateHash == false { - httpobj.http_PeerState[PubKey].PeerInfoState = reg_msg.PeerStateHash + if httpobj.http_PeerState[PubKey].PeerInfoState.Load().(string) == reg_msg.PeerStateHash == false { + httpobj.http_PeerState[PubKey].PeerInfoState.Store(reg_msg.PeerStateHash) should_push_peer = true } } @@ -507,11 +517,11 @@ func PushNhTable(force bool) { header.SetTTL(0) copy(buf[path.EgHeaderLen:], body) for pkstr, peerstate := range httpobj.http_PeerState { - isAlive := peerstate.LastSeen.Add(mtypes.S2TD(httpobj.http_sconfig.PeerAliveTimeout)).After(time.Now()) + isAlive := peerstate.LastSeen.Load().(time.Time).Add(mtypes.S2TD(httpobj.http_sconfig.PeerAliveTimeout)).After(time.Now()) if !isAlive { continue } - if force || peerstate.NhTableState != httpobj.http_NhTable_Hash { + if force || peerstate.NhTableState.Load().(string) != httpobj.http_NhTable_Hash { if peer := httpobj.http_device4.LookupPeerByStr(pkstr); peer != nil && peer.GetEndpointDstStr() != "" { httpobj.http_device4.SendPacket(peer, path.ServerUpdate, buf, device.MessageTransportOffsetContent) } @@ -542,11 +552,11 @@ func PushPeerinfo(force bool) { header.SetTTL(0) copy(buf[path.EgHeaderLen:], body) for pkstr, peerstate := range httpobj.http_PeerState { - isAlive := peerstate.LastSeen.Add(mtypes.S2TD(httpobj.http_sconfig.PeerAliveTimeout)).After(time.Now()) + isAlive := peerstate.LastSeen.Load().(time.Time).Add(mtypes.S2TD(httpobj.http_sconfig.PeerAliveTimeout)).After(time.Now()) if !isAlive { continue } - if force || peerstate.PeerInfoState != httpobj.http_PeerInfo_hash { + if force || peerstate.PeerInfoState.Load().(string) != httpobj.http_PeerInfo_hash { if peer := httpobj.http_device4.LookupPeerByStr(pkstr); peer != nil { httpobj.http_device4.SendPacket(peer, path.ServerUpdate, buf, device.MessageTransportOffsetContent) } @@ -577,11 +587,11 @@ func PushServerParams(force bool) { header.SetTTL(0) copy(buf[path.EgHeaderLen:], body) for pkstr, peerstate := range httpobj.http_PeerState { - isAlive := peerstate.LastSeen.Add(mtypes.S2TD(httpobj.http_sconfig.PeerAliveTimeout)).After(time.Now()) + isAlive := peerstate.LastSeen.Load().(time.Time).Add(mtypes.S2TD(httpobj.http_sconfig.PeerAliveTimeout)).After(time.Now()) if !isAlive { continue } - if force || peerstate.SuperParamState != httpobj.http_SuperParams_Hash { + if force || peerstate.SuperParamState.Load().(string) != httpobj.http_SuperParams_Hash { if peer := httpobj.http_device4.LookupPeerByStr(pkstr); peer != nil { httpobj.http_device4.SendPacket(peer, path.ServerUpdate, buf, device.MessageTransportOffsetContent) } diff --git a/mtypes/sdnotify.go b/mtypes/sdnotify.go new file mode 100644 index 0000000..ab478fc --- /dev/null +++ b/mtypes/sdnotify.go @@ -0,0 +1,84 @@ +// Copyright 2014 Docker, Inc. +// Copyright 2015-2018 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package daemon provides a Go implementation of the sd_notify protocol. +// It can be used to inform systemd of service start-up completion, watchdog +// events, and other status changes. +// +// https://www.freedesktop.org/software/systemd/man/sd_notify.html#Description +package mtypes + +import ( + "net" + "os" +) + +const ( + // SdNotifyReady tells the service manager that service startup is finished + // or the service finished loading its configuration. + SdNotifyReady = "READY=1" + + // SdNotifyStopping tells the service manager that the service is beginning + // its shutdown. + SdNotifyStopping = "STOPPING=1" + + // SdNotifyReloading tells the service manager that this service is + // reloading its configuration. Note that you must call SdNotifyReady when + // it completed reloading. + SdNotifyReloading = "RELOADING=1" + + // SdNotifyWatchdog tells the service manager to update the watchdog + // timestamp for the service. + SdNotifyWatchdog = "WATCHDOG=1" +) + +// SdNotify sends a message to the init daemon. It is common to ignore the error. +// If `unsetEnvironment` is true, the environment variable `NOTIFY_SOCKET` +// will be unconditionally unset. +// +// It returns one of the following: +// (false, nil) - notification not supported (i.e. NOTIFY_SOCKET is unset) +// (false, err) - notification supported, but failure happened (e.g. error connecting to NOTIFY_SOCKET or while sending data) +// (true, nil) - notification supported, data has been sent +func SdNotify(unsetEnvironment bool, state string) (bool, error) { + socketAddr := &net.UnixAddr{ + Name: os.Getenv("NOTIFY_SOCKET"), + Net: "unixgram", + } + + // NOTIFY_SOCKET not set + if socketAddr.Name == "" { + return false, nil + } + + if unsetEnvironment { + if err := os.Unsetenv("NOTIFY_SOCKET"); err != nil { + return false, err + } + } + + conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr) + // Error connecting to NOTIFY_SOCKET + if err != nil { + return false, err + } + defer conn.Close() + + if _, err = conn.Write([]byte(state)); err != nil { + return false, err + } + return true, nil +}