// Creates a new bootstrapper, configuring to listen on the given interface for // for incoming requests and scan the same interface for other peers. The magic // is used to filter multiple Iris networks in the same physical network, while // the overlay is the TCP listener port of the DHT. func New(ipnet *net.IPNet, magic []byte, node *big.Int, overlay int) (*Bootstrapper, chan *Event, error) { // Issue a warning if we have a single machine subnet if ones, bits := ipnet.Mask.Size(); bits-ones < 2 { log.Printf("bootstrap: WARNING! cannot search on interface %v, network mask covers the whole space", ipnet) } bs := &Bootstrapper{ magic: magic, beats: make(chan *Event, config.BootBeatsBuffer), fast: true, } // Open the server socket var err error for _, port := range config.BootPorts { bs.addr, err = net.ResolveUDPAddr("udp", net.JoinHostPort(ipnet.IP.String(), strconv.Itoa(port))) if err != nil { return nil, nil, err } bs.sock, err = net.ListenUDP("udp", bs.addr) if err != nil { continue } else { bs.addr.Port = bs.sock.LocalAddr().(*net.UDPAddr).Port bs.mask = &ipnet.Mask break } } if err != nil { return nil, nil, fmt.Errorf("no available ports") } // Generate the local heartbeat messages (request and response) bs.magic = magic bs.gob = gobber.New() bs.gob.Init(new(Message)) msg := Message{ Version: config.ProtocolVersion, Magic: magic, NodeId: node, Overlay: overlay, Request: true, } if buf, err := bs.gob.Encode(msg); err != nil { return nil, nil, fmt.Errorf("request encode failed: %v.", err) } else { bs.request = make([]byte, len(buf)) copy(bs.request, buf) } msg.Request = false if buf, err := bs.gob.Encode(msg); err != nil { return nil, nil, fmt.Errorf("response encode failed: %v.", err) } else { bs.response = make([]byte, len(buf)) copy(bs.response, buf) } // Return the ready-to-boot bootstrapper return bs, bs.beats, nil }
// Creates a new bootstrapper, configuring to listen on the given interface for // for incoming requests and scan the same interface for other peers. The magic // is used to filter multiple Iris networks in the same physical network, while // the overlay is the TCP listener port of the DHT. func New(ipnet *net.IPNet, magic []byte, owner *big.Int, endpoint int) (*Bootstrapper, chan *Event, error) { logger := log15.New("subsys", "bootstrap", "ipnet", ipnet) gobber := gobber.New() gobber.Init(new(Message)) // Do some environment dependent IP black magic if detectGoogleComputeEngine() { // Google Compute Engine issues /32 addresses, find real subnet logger.Info("detected GCE, retrieving real netmask") old := ipnet.String() if err := updateIPNet(ipnet); err != nil { logger.Error("failed to retrieve netmask, defaulting", "error", err) ipnet.Mask = ipnet.IP.DefaultMask() } logger.Info("network subnet mask replaced", "old", old, "new", ipnet) logger = log15.New("subsys", "bootstrap", "ipnet", ipnet) } b := &Bootstrapper{ ipnet: ipnet, magic: magic, beats: make(chan *Event, config.BootBeatsBuffer), phase: uint32(0), gob: gobber, request: newBootstrapRequest(magic, owner, endpoint, gobber), response: newBootstrapResponse(magic, owner, endpoint, gobber), // Seeding algorithms and address sinks scanSeed: newScanSeeder(ipnet, logger), probeSeed: newProbeSeeder(ipnet, logger), coreOSSeed: newCoreOSSeeder(ipnet, logger), scanSink: make(chan *net.IPAddr, config.BootSeedSinkBuffer), probeSink: make(chan *net.IPAddr, config.BootSeedSinkBuffer), coreOSSink: make(chan *net.IPAddr, config.BootSeedSinkBuffer), // Maintenance fields quit: make(chan chan error), log: logger, } // Open the server socket var err error for _, port := range config.BootPorts { b.addr, err = net.ResolveUDPAddr("udp", net.JoinHostPort(ipnet.IP.String(), strconv.Itoa(port))) if err != nil { return nil, nil, err } b.sock, err = net.ListenUDP("udp", b.addr) if err != nil { continue } else { b.addr.Port = b.sock.LocalAddr().(*net.UDPAddr).Port b.mask = &ipnet.Mask break } } if err != nil { return nil, nil, fmt.Errorf("no available ports") } // Return the ready-to-boot bootstrapper return b, b.beats, nil }