func main() { flag.Parse() IPs = parseIPs() MinPort, MaxPort = parsePorts() thisAddr = canonicalAddr(*flag_addr, IPs) var err error thisHost, _, err = net.SplitHostPort(thisAddr) util.FatalErr(err) DetectMumax() DetectGPUs() LoadJobs() http.HandleFunc("/do/", HandleRPC) http.HandleFunc("/", HandleStatus) httpfs.RegisterHandlers() // Listen and serve on all interfaces go func() { log.Println("serving at", thisAddr) // try to listen and serve on all interfaces other than thisAddr // this is for convenience, errors are not fatal. _, p, err := net.SplitHostPort(thisAddr) Fatal(err) ips := util.InterfaceAddrs() for _, ip := range ips { addr := net.JoinHostPort(ip, p) if addr != thisAddr { // skip thisAddr, will start later and is fatal on error go func() { err := http.ListenAndServe(addr, nil) if err != nil { log.Println("info:", err, "(but still serving other interfaces)") } }() } } // only on thisAddr, this server's unique address, // we HAVE to be listening. Fatal(http.ListenAndServe(thisAddr, nil)) }() ProbePeer(thisAddr) // make sure we have ourself as peer go FindPeers(IPs, MinPort, MaxPort) go RunComputeService() go LoopWatchdog() go RunShareDecay() // re-load jobs every hour so we don't stall on very exceptional circumstances go func() { for { time.Sleep(1 * time.Hour) LoadJobs() } }() <-make(chan struct{}) // wait forever }
// replace laddr by a canonical form, as it will serve as unique ID func canonicalAddr(laddr string, IPs []string) string { // safe initial guess: hostname:port h, p, err := net.SplitHostPort(laddr) Fatal(err) if h == "" { h, _ = os.Hostname() } name := net.JoinHostPort(h, p) ips := util.InterfaceAddrs() for _, ip := range ips { if contains(IPs, ip) { return net.JoinHostPort(ip, p) } } return name }