go.dedis.ch/onet/v3@v3.2.11-0.20210930124529-e36530bca7ef/server.go (about) 1 package onet 2 3 import ( 4 "fmt" 5 "os" 6 "runtime" 7 "sort" 8 "strconv" 9 "strings" 10 "sync" 11 "time" 12 13 "go.dedis.ch/kyber/v3" 14 "go.dedis.ch/onet/v3/cfgpath" 15 "go.dedis.ch/onet/v3/log" 16 "go.dedis.ch/onet/v3/network" 17 "golang.org/x/xerrors" 18 "rsc.io/goversion/version" 19 ) 20 21 // Server connects the Router, the Overlay, and the Services together. It sets 22 // up everything and returns once a working network has been set up. 23 type Server struct { 24 // Our private-key 25 private kyber.Scalar 26 *network.Router 27 // Overlay handles the mapping from tree and entityList to ServerIdentity. 28 // It uses tokens to represent an unique ProtocolInstance in the system 29 overlay *Overlay 30 // lock associated to access trees 31 treesLock sync.Mutex 32 serviceManager *serviceManager 33 statusReporterStruct *statusReporterStruct 34 // protocols holds a map of all available protocols and how to create an 35 // instance of it 36 protocols *protocolStorage 37 // webservice 38 WebSocket *WebSocket 39 // when this node has been started 40 started time.Time 41 // once everything's up and running 42 closeitChannel chan bool 43 IsStarted bool 44 45 suite network.Suite 46 } 47 48 func dbPathFromEnv() string { 49 p := os.Getenv("CONODE_SERVICE_PATH") 50 if p == "" { 51 p = cfgpath.GetDataPath("conode") 52 } 53 return p 54 } 55 56 // NewServer returns a fresh Server tied to a given Router. 57 // If dbPath is "", the server will write its database to the default 58 // location. If dbPath is != "", it is considered a temp dir, and the 59 // DB is deleted on close. 60 func newServer(s network.Suite, dbPath string, r *network.Router, pkey kyber.Scalar) *Server { 61 delDb := false 62 if dbPath == "" { 63 dbPath = dbPathFromEnv() 64 log.ErrFatal(os.MkdirAll(dbPath, 0750)) 65 } else { 66 delDb = true 67 } 68 69 c := &Server{ 70 private: pkey, 71 statusReporterStruct: newStatusReporterStruct(), 72 Router: r, 73 protocols: newProtocolStorage(), 74 suite: s, 75 closeitChannel: make(chan bool), 76 } 77 c.overlay = NewOverlay(c) 78 c.WebSocket = NewWebSocket(r.ServerIdentity) 79 c.serviceManager = newServiceManager(c, c.overlay, dbPath, delDb) 80 c.statusReporterStruct.RegisterStatusReporter("Generic", c) 81 return c 82 } 83 84 // NewServerTCP returns a new Server out of a private-key and its related 85 // public key within the ServerIdentity. The server will use a default 86 // TcpRouter as Router. 87 func NewServerTCP(e *network.ServerIdentity, suite network.Suite) *Server { 88 return NewServerTCPWithListenAddr(e, suite, "") 89 } 90 91 // NewServerTCPWithListenAddr returns a new Server out of a private-key and 92 // its related public key within the ServerIdentity. The server will use a 93 // TcpRouter listening on the given address as Router. 94 func NewServerTCPWithListenAddr(e *network.ServerIdentity, suite network.Suite, 95 listenAddr string) *Server { 96 r, err := network.NewTCPRouterWithListenAddr(e, suite, listenAddr) 97 log.ErrFatal(err) 98 return newServer(suite, "", r, e.GetPrivate()) 99 } 100 101 // Suite can (and should) be used to get the underlying Suite. 102 // Currently the suite is hardcoded into the network library. 103 // Don't use network.Suite but Host's Suite function instead if possible. 104 func (c *Server) Suite() network.Suite { 105 return c.suite 106 } 107 108 var gover version.Version 109 var goverOnce sync.Once 110 var goverOk = false 111 112 // GetStatus is a function that returns the status report of the server. 113 func (c *Server) GetStatus() *Status { 114 a := c.serviceManager.availableServices() 115 sort.Strings(a) 116 117 st := &Status{Field: map[string]string{ 118 "Available_Services": strings.Join(a, ","), 119 "TX_bytes": strconv.FormatUint(c.Router.Tx(), 10), 120 "RX_bytes": strconv.FormatUint(c.Router.Rx(), 10), 121 "Uptime": time.Now().Sub(c.started).String(), 122 "System": fmt.Sprintf("%s/%s/%s", runtime.GOOS, runtime.GOARCH, 123 runtime.Version()), 124 "Host": c.ServerIdentity.Address.Host(), 125 "Port": c.ServerIdentity.Address.Port(), 126 "Description": c.ServerIdentity.Description, 127 "ConnType": string(c.ServerIdentity.Address.ConnType()), 128 "GoRoutines": fmt.Sprintf("%v", runtime.NumGoroutine()), 129 }} 130 131 goverOnce.Do(func() { 132 v, err := version.ReadExe(os.Args[0]) 133 if err == nil { 134 gover = v 135 goverOk = true 136 } 137 }) 138 139 if goverOk { 140 st.Field["GoRelease"] = gover.Release 141 st.Field["GoModuleInfo"] = gover.ModuleInfo 142 } 143 144 return st 145 } 146 147 // Close closes the overlay and the Router 148 func (c *Server) Close() error { 149 c.Lock() 150 if c.IsStarted { 151 c.closeitChannel <- true 152 c.IsStarted = false 153 } 154 c.Unlock() 155 156 err := c.Router.Stop() 157 if err != nil { 158 err = xerrors.Errorf("stopping: %v", err) 159 log.Error("While stopping router:", err) 160 } 161 c.WebSocket.stop() 162 c.overlay.Close() 163 err = c.serviceManager.closeDatabase() 164 if err != nil { 165 err = xerrors.Errorf("closing db: %v", err) 166 log.Lvl3("Error closing database: " + err.Error()) 167 } 168 log.Lvl3("Host Close", c.ServerIdentity.Address, "listening?", c.Router.Listening()) 169 return err 170 } 171 172 // Address returns the address used by the Router. 173 func (c *Server) Address() network.Address { 174 return c.ServerIdentity.Address 175 } 176 177 // Service returns the service with the given name. 178 func (c *Server) Service(name string) Service { 179 return c.serviceManager.service(name) 180 } 181 182 // GetService is kept for backward-compatibility. 183 func (c *Server) GetService(name string) Service { 184 log.Warn("This method is deprecated - use `Server.Service` instead") 185 return c.Service(name) 186 } 187 188 // ProtocolRegister will sign up a new protocol to this Server. 189 // It returns the ID of the protocol. 190 func (c *Server) ProtocolRegister(name string, protocol NewProtocol) (ProtocolID, error) { 191 id, err := c.protocols.Register(name, protocol) 192 if err != nil { 193 return id, xerrors.Errorf("registering protocol: %v", err) 194 } 195 return id, nil 196 } 197 198 // protocolInstantiate instantiate a protocol from its ID 199 func (c *Server) protocolInstantiate(protoID ProtocolID, tni *TreeNodeInstance) (ProtocolInstance, error) { 200 fn, ok := c.protocols.instantiators[c.protocols.ProtocolIDToName(protoID)] 201 if !ok { 202 return nil, xerrors.New("No protocol constructor with this ID") 203 } 204 pi, err := fn(tni) 205 if err != nil { 206 return nil, xerrors.Errorf("creating protocol: %v", err) 207 } 208 return pi, nil 209 } 210 211 // Start makes the router and the WebSocket listen on their respective 212 // ports. It returns once all servers are started. 213 func (c *Server) Start() { 214 InformServerStarted() 215 c.started = time.Now() 216 if !c.Quiet { 217 log.Lvlf1("Starting server at %s on address %s", 218 c.started.Format("2006-01-02 15:04:05"), 219 c.ServerIdentity.Address) 220 } 221 go c.Router.Start() 222 go c.WebSocket.start() 223 for !c.Router.Listening() || !c.WebSocket.Listening() { 224 time.Sleep(50 * time.Millisecond) 225 } 226 c.Lock() 227 c.IsStarted = true 228 c.Unlock() 229 // Wait for closing of the channel 230 <-c.closeitChannel 231 } 232 233 // StartInBackground starts the services and returns once everything 234 // is up and running. 235 func (c *Server) StartInBackground() { 236 go c.Start() 237 c.WaitStartup() 238 } 239 240 // WaitStartup can be called to ensure that the server is up and 241 // running. It will loop and wait 50 milliseconds between each 242 // test. 243 func (c *Server) WaitStartup() { 244 for { 245 c.Lock() 246 s := c.IsStarted 247 c.Unlock() 248 if s { 249 return 250 } 251 time.Sleep(50 * time.Millisecond) 252 } 253 } 254 255 // For all services that have `TestClose` defined, call it to make 256 // sure they are able to clean up. This should only be used for tests! 257 func (c *Server) callTestClose() { 258 wg := sync.WaitGroup{} 259 c.serviceManager.servicesMutex.Lock() 260 for _, serv := range c.serviceManager.services { 261 wg.Add(1) 262 go func(s Service) { 263 defer wg.Done() 264 c, ok := s.(TestClose) 265 if ok { 266 c.TestClose() 267 } 268 }(serv) 269 } 270 c.serviceManager.servicesMutex.Unlock() 271 wg.Wait() 272 }