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  }