// Listen for new connections on the given multiaddr func (s *Swarm) setupListener(maddr ma.Multiaddr) error { // TODO rethink how this has to work. (jbenet) // // resolved, err := resolveUnspecifiedAddresses([]ma.Multiaddr{maddr}) // if err != nil { // return err // } // for _, a := range resolved { // s.peers.AddAddr(s.local, a) // } sk := s.peers.PrivKey(s.local) if sk == nil { // may be fine for sk to be nil, just log a warning. log.Warning("Listener not given PrivateKey, so WILL NOT SECURE conns.") } log.Debugf("Swarm Listening at %s", maddr) list, err := conn.Listen(s.Context(), maddr, s.local, sk) if err != nil { return err } list.SetAddrFilters(s.Filters) if cw, ok := list.(conn.ListenerConnWrapper); ok { cw.SetConnWrapper(func(c manet.Conn) manet.Conn { return mconn.WrapConn(s.bwc, c) }) } // AddListener to the peerstream Listener. this will begin accepting connections // and streams! sl, err := s.swarm.AddListener(list) if err != nil { return err } log.Debugf("Swarm Listeners at %s", s.ListenAddresses()) // signal to our notifiees on successful conn. s.notifyAll(func(n inet.Notifiee) { n.Listen((*Network)(s), maddr) }) // go consume peerstream's listen accept errors. note, these ARE errors. // they may be killing the listener, and if we get _any_ we should be // fixing this in our conn.Listener (to ignore them or handle them // differently.) go func(ctx context.Context, sl *ps.Listener) { // signal to our notifiees closing defer s.notifyAll(func(n inet.Notifiee) { n.ListenClose((*Network)(s), maddr) }) for { select { case err, more := <-sl.AcceptErrors(): if !more { return } log.Warningf("swarm listener accept error: %s", err) case <-ctx.Done(): return } } }(s.Context(), sl) return nil }
// dial is the actual swarm's dial logic, gated by Dial. func (s *Swarm) dial(ctx context.Context, p peer.ID) (*Conn, error) { var logdial = lgbl.Dial("swarm", s.LocalPeer(), p, nil, nil) if p == s.local { log.Event(ctx, "swarmDialDoDialSelf", logdial) return nil, ErrDialToSelf } defer log.EventBegin(ctx, "swarmDialDo", logdial).Done() logdial["dial"] = "failure" // start off with failure. set to "success" at the end. sk := s.peers.PrivKey(s.local) logdial["encrypted"] = (sk != nil) // log wether this will be an encrypted dial or not. if sk == nil { // fine for sk to be nil, just log. log.Debug("Dial not given PrivateKey, so WILL NOT SECURE conn.") } // get our own addrs. try dialing out from our listener addresses (reusing ports) // Note that using our peerstore's addresses here is incorrect, as that would // include observed addresses. TODO: make peerstore's address book smarter. localAddrs := s.ListenAddresses() if len(localAddrs) == 0 { log.Debug("Dialing out with no local addresses.") } // get remote peer addrs remoteAddrs := s.peers.Addrs(p) // make sure we can use the addresses. remoteAddrs = addrutil.FilterUsableAddrs(remoteAddrs) // drop out any addrs that would just dial ourselves. use ListenAddresses // as that is a more authoritative view than localAddrs. ila, _ := s.InterfaceListenAddresses() remoteAddrs = addrutil.Subtract(remoteAddrs, ila) remoteAddrs = addrutil.Subtract(remoteAddrs, s.peers.Addrs(s.local)) log.Debugf("%s swarm dialing %s -- local:%s remote:%s", s.local, p, s.ListenAddresses(), remoteAddrs) if len(remoteAddrs) == 0 { err := errors.New("peer has no addresses") logdial["error"] = err return nil, err } remoteAddrs = s.filterAddrs(remoteAddrs) if len(remoteAddrs) == 0 { err := errors.New("all adresses for peer have been filtered out") logdial["error"] = err return nil, err } // open connection to peer d := &conn.Dialer{ Dialer: manet.Dialer{ Dialer: net.Dialer{ Timeout: s.dialT, }, }, LocalPeer: s.local, LocalAddrs: localAddrs, PrivateKey: sk, Wrapper: func(c manet.Conn) manet.Conn { return mconn.WrapConn(s.bwc, c) }, } // try to get a connection to any addr connC, err := s.dialAddrs(ctx, d, p, remoteAddrs) if err != nil { logdial["error"] = err return nil, err } logdial["netconn"] = lgbl.NetConn(connC) // ok try to setup the new connection. defer log.EventBegin(ctx, "swarmDialDoSetup", logdial, lgbl.NetConn(connC)).Done() swarmC, err := dialConnSetup(ctx, s, connC) if err != nil { logdial["error"] = err connC.Close() // close the connection. didn't work out :( return nil, err } logdial["dial"] = "success" return swarmC, nil }