gopkg.in/dedis/onet.v2@v2.0.0-20181115163211-c8f3724038a7/simulation.go (about) 1 package onet 2 3 import ( 4 "errors" 5 "io/ioutil" 6 "net" 7 "os" 8 "strconv" 9 "strings" 10 "time" 11 12 "github.com/BurntSushi/toml" 13 "gopkg.in/dedis/kyber.v2" 14 "gopkg.in/dedis/kyber.v2/suites" 15 "gopkg.in/dedis/kyber.v2/util/key" 16 "gopkg.in/dedis/onet.v2/log" 17 "gopkg.in/dedis/onet.v2/network" 18 ) 19 20 type simulationCreate func(string) (Simulation, error) 21 22 var simulationRegistered map[string]simulationCreate 23 24 // SimulationFileName is the name of the (binary encoded) file containing the 25 // simulation config. 26 const SimulationFileName = "simulation.bin" 27 28 // Simulation is an interface needed by every protocol that wants to be available 29 // to be used in a simulation. 30 type Simulation interface { 31 // This has to initialise all necessary files and copy them to the 32 // 'dir'-directory. This directory will be accessible to all simulated 33 // hosts. 34 // Setup also gets a slice of all available hosts. In turn it has 35 // to return a tree using one or more of these hosts. It can create 36 // the Roster as desired, putting more than one ServerIdentity/Host on the same host. 37 // The 'config'-argument holds all arguments read from the runfile in 38 // toml-format. 39 Setup(dir string, hosts []string) (*SimulationConfig, error) 40 41 // Node will be run for every node and might be used to setup load- 42 // creation. It is started once the Host is set up and running, but before 43 // 'Run' 44 Node(config *SimulationConfig) error 45 46 // Run will begin with the simulation or return an error. It is sure 47 // to be run on the host where 'tree.Root' is. It should only return 48 // when all rounds are done. 49 Run(config *SimulationConfig) error 50 } 51 52 // SimulationConfig has to be returned from 'Setup' and will be passed to 53 // 'Run'. 54 type SimulationConfig struct { 55 // Represents the tree that has to be used 56 Tree *Tree 57 // The Roster used by the tree 58 Roster *Roster 59 // All private keys generated by 'Setup', indexed by the complete addresses 60 PrivateKeys map[network.Address]kyber.Scalar 61 // If non-nil, points to our overlay 62 Overlay *Overlay 63 // If non-nil, points to our host 64 Server *Server 65 // Tells if the simulation should use TLS addresses; if not, use PlainTCP 66 TLS bool 67 // Additional configuration used to run 68 Config string 69 } 70 71 // SimulationConfigFile stores the state of the simulation's config. 72 // Only used internally. 73 type SimulationConfigFile struct { 74 TreeMarshal *TreeMarshal 75 Roster *Roster 76 PrivateKeys map[network.Address]kyber.Scalar 77 TLS bool 78 Config string 79 } 80 81 // LoadSimulationConfig gets all configuration from dir + SimulationFileName and instantiates the 82 // corresponding host 'ca'. 83 func LoadSimulationConfig(s, dir, ca string) ([]*SimulationConfig, error) { 84 // Have all servers created by NewServerTCP below put their 85 // db's into this simulation directory. 86 os.Setenv("CONODE_SERVICE_PATH", dir) 87 88 // TODO: Figure this out from the incoming simulation file somehow 89 suite := suites.MustFind(s) 90 91 network.RegisterMessage(SimulationConfigFile{}) 92 bin, err := ioutil.ReadFile(dir + "/" + SimulationFileName) 93 if err != nil { 94 return nil, err 95 } 96 _, msg, err := network.Unmarshal(bin, suite) 97 if err != nil { 98 return nil, err 99 } 100 101 scf := msg.(*SimulationConfigFile) 102 sc := &SimulationConfig{ 103 Roster: scf.Roster, 104 PrivateKeys: scf.PrivateKeys, 105 TLS: scf.TLS, 106 Config: scf.Config, 107 } 108 sc.Tree, err = scf.TreeMarshal.MakeTree(sc.Roster) 109 if err != nil { 110 return nil, err 111 } 112 113 var ret []*SimulationConfig 114 if ca != "" { 115 if !strings.Contains(ca, ":") { 116 // to correctly match hosts a column is needed, else 117 // 10.255.0.1 would also match 10.255.0.10 and others 118 ca += ":" 119 } 120 for _, e := range sc.Roster.List { 121 if strings.Contains(e.Address.String(), ca) { 122 e.SetPrivate(scf.PrivateKeys[e.Address]) 123 server := NewServerTCP(e, suite) 124 server.UnauthOk = true 125 server.Quiet = true 126 scNew := *sc 127 scNew.Server = server 128 scNew.Overlay = server.overlay 129 ret = append(ret, &scNew) 130 } 131 } 132 if len(ret) == 0 { 133 return nil, errors.New("Address not used in simulation: " + ca) 134 } 135 } else { 136 ret = append(ret, sc) 137 } 138 addr := string(sc.Roster.List[0].Address) 139 if strings.Contains(addr, "127.0.0.") { 140 // Now strip all superfluous numbers of localhost 141 for i := range sc.Roster.List { 142 _, port, _ := net.SplitHostPort(sc.Roster.List[i].Address.NetworkAddress()) 143 // put 127.0.0.1 because 127.0.0.X is not reachable on Mac OS X 144 if sc.TLS { 145 sc.Roster.List[i].Address = network.NewTLSAddress("127.0.0.1:" + port) 146 } else { 147 sc.Roster.List[i].Address = network.NewTCPAddress("127.0.0.1:" + port) 148 } 149 } 150 } 151 return ret, nil 152 } 153 154 // Save takes everything in the SimulationConfig structure and saves it to 155 // dir + SimulationFileName 156 func (sc *SimulationConfig) Save(dir string) error { 157 network.RegisterMessage(&SimulationConfigFile{}) 158 scf := &SimulationConfigFile{ 159 TreeMarshal: sc.Tree.MakeTreeMarshal(), 160 Roster: sc.Roster, 161 PrivateKeys: sc.PrivateKeys, 162 TLS: sc.TLS, 163 Config: sc.Config, 164 } 165 buf, err := network.Marshal(scf) 166 if err != nil { 167 log.Fatal(err) 168 } 169 err = ioutil.WriteFile(dir+"/"+SimulationFileName, buf, 0660) 170 if err != nil { 171 log.Fatal(err) 172 } 173 174 return nil 175 } 176 177 // GetService returns the service with the given name. 178 func (sc *SimulationConfig) GetService(name string) Service { 179 return sc.Server.serviceManager.service(name) 180 } 181 182 // SimulationRegister is must to be called to register a simulation. 183 // Protocol or simulation developers must not forget to call this function 184 // with the protocol's name. 185 func SimulationRegister(name string, sim simulationCreate) { 186 if simulationRegistered == nil { 187 simulationRegistered = make(map[string]simulationCreate) 188 } 189 simulationRegistered[name] = sim 190 } 191 192 // NewSimulation returns a simulation and decodes the 'conf' into the 193 // simulation-structure 194 func NewSimulation(name string, conf string) (Simulation, error) { 195 sim, ok := simulationRegistered[name] 196 if !ok { 197 return nil, errors.New("Didn't find simulation " + name) 198 } 199 simInst, err := sim(conf) 200 if err != nil { 201 return nil, err 202 } 203 _, err = toml.Decode(conf, simInst) 204 if err != nil { 205 return nil, err 206 } 207 return simInst, nil 208 } 209 210 // SimulationBFTree is the main struct storing the data for all the simulations 211 // which use a tree with a certain branching factor or depth. 212 type SimulationBFTree struct { 213 Rounds int 214 BF int 215 Hosts int 216 SingleHost bool 217 Depth int 218 Suite string 219 PreScript string // executable script to run before the simulation on each machine 220 TLS bool // tells if using TLS or PlainTCP addresses 221 } 222 223 // CreateRoster creates an Roster with the host-names in 'addresses'. 224 // It creates 's.Hosts' entries, starting from 'port' for each round through 225 // 'addresses'. The network.Address(es) created are of type TLS or PlainTCP, 226 // depending on the value 'TLS' in 'sc'. 227 func (s *SimulationBFTree) CreateRoster(sc *SimulationConfig, addresses []string, port int) { 228 start := time.Now() 229 sc.TLS = s.TLS 230 suite, err := suites.Find(s.Suite) 231 if err != nil { 232 log.Fatalf("Could not look up suite \"%v\": %v", s.Suite, err.Error()) 233 } 234 nbrAddr := len(addresses) 235 if sc.PrivateKeys == nil { 236 sc.PrivateKeys = make(map[network.Address]kyber.Scalar) 237 } 238 hosts := s.Hosts 239 if s.SingleHost { 240 // If we want to work with a single host, we only make one 241 // host per server 242 log.Fatal("Not supported yet") 243 hosts = nbrAddr 244 if hosts > s.Hosts { 245 hosts = s.Hosts 246 } 247 } 248 localhosts := false 249 listeners := make([]net.Listener, hosts) 250 services := make([]net.Listener, hosts) 251 if strings.Contains(addresses[0], "127.0.0.") { 252 localhosts = true 253 } 254 entities := make([]*network.ServerIdentity, hosts) 255 log.Lvl3("Doing", hosts, "hosts") 256 key := key.NewKeyPair(suite) 257 for c := 0; c < hosts; c++ { 258 key.Private.Add(key.Private, suite.Scalar().One()) 259 key.Public.Add(key.Public, suite.Point().Base()) 260 address := addresses[c%nbrAddr] + ":" 261 var add network.Address 262 if localhosts { 263 // If we have localhosts, we have to search for an empty port 264 port := 0 265 for port == 0 { 266 267 var err error 268 listeners[c], err = net.Listen("tcp", ":0") 269 if err != nil { 270 log.Fatal("Couldn't search for empty port:", err) 271 } 272 _, p, _ := net.SplitHostPort(listeners[c].Addr().String()) 273 port, _ = strconv.Atoi(p) 274 services[c], err = net.Listen("tcp", ":"+strconv.Itoa(port+1)) 275 if err != nil { 276 port = 0 277 } 278 } 279 address += strconv.Itoa(port) 280 if sc.TLS { 281 add = network.NewTLSAddress(address) 282 } else { 283 add = network.NewTCPAddress(address) 284 } 285 log.Lvl4("Found free port", address) 286 } else { 287 address += strconv.Itoa(port + (c/nbrAddr)*2) 288 if sc.TLS { 289 add = network.NewTLSAddress(address) 290 } else { 291 add = network.NewTCPAddress(address) 292 } 293 } 294 entities[c] = network.NewServerIdentity(key.Public.Clone(), add) 295 entities[c].SetPrivate(key.Private) 296 sc.PrivateKeys[entities[c].Address] = key.Private.Clone() 297 } 298 299 // And close all our listeners 300 if localhosts { 301 for _, l := range listeners { 302 err := l.Close() 303 if err != nil { 304 log.Fatal("Couldn't close port:", l, err) 305 } 306 } 307 for _, l := range services { 308 err := l.Close() 309 if err != nil { 310 log.Fatal("Couldn't close port:", l, err) 311 } 312 } 313 } 314 315 sc.Roster = NewRoster(entities) 316 log.Lvl3("Creating entity List took: " + time.Now().Sub(start).String()) 317 } 318 319 // CreateTree the tree as defined in SimulationBFTree and stores the result 320 // in 'sc' 321 func (s *SimulationBFTree) CreateTree(sc *SimulationConfig) error { 322 log.Lvl3("CreateTree strarted") 323 start := time.Now() 324 if sc.Roster == nil { 325 return errors.New("Empty Roster") 326 } 327 sc.Tree = sc.Roster.GenerateBigNaryTree(s.BF, s.Hosts) 328 log.Lvl3("Creating tree took: " + time.Now().Sub(start).String()) 329 return nil 330 } 331 332 // Node - standard registers the entityList and the Tree with that Overlay, 333 // so we don't have to pass that around for the experiments. 334 func (s *SimulationBFTree) Node(sc *SimulationConfig) error { 335 sc.Overlay.RegisterRoster(sc.Roster) 336 sc.Overlay.RegisterTree(sc.Tree) 337 return nil 338 } 339 340 // GetSingleHost returns the 'SingleHost'-flag 341 func (sc SimulationConfig) GetSingleHost() bool { 342 var sh struct{ SingleHost bool } 343 _, err := toml.Decode(sc.Config, &sh) 344 if err != nil { 345 log.Error("Couldn't decode string", sc.Config, "into toml.") 346 return false 347 } 348 return sh.SingleHost 349 }