notif.go 2.52 KB
Newer Older
1 2 3
package dht

import (
4
	"context"
5 6
	"io"

7 8
	inet "github.com/libp2p/go-libp2p-net"
	ma "github.com/multiformats/go-multiaddr"
Jeromy's avatar
Jeromy committed
9
	mstream "github.com/multiformats/go-multistream"
10 11 12 13 14 15 16 17 18
)

// netNotifiee defines methods to be used with the IpfsDHT
type netNotifiee IpfsDHT

func (nn *netNotifiee) DHT() *IpfsDHT {
	return (*IpfsDHT)(nn)
}

19 20 21 22 23
type peerTracker struct {
	refcount int
	cancel   func()
}

24 25 26
func (nn *netNotifiee) Connected(n inet.Network, v inet.Conn) {
	dht := nn.DHT()
	select {
27
	case <-dht.Process().Closing():
28
		return
29
	default:
30
	}
31

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
	dht.plk.Lock()
	defer dht.plk.Unlock()

	conn, ok := nn.peers[v.RemotePeer()]
	if ok {
		conn.refcount += 1
		return
	}

	ctx, cancel := context.WithCancel(dht.Context())

	nn.peers[v.RemotePeer()] = &peerTracker{
		refcount: 1,
		cancel:   cancel,
	}

48 49 50 51 52 53 54
	go func() {

		// Note: We *could* just check the peerstore to see if the remote side supports the dht
		// protocol, but its not clear that that information will make it into the peerstore
		// by the time this notification is sent. So just to be very careful, we brute force this
		// and open a new stream

55 56 57 58 59 60 61 62 63
		for {
			s, err := dht.host.NewStream(ctx, v.RemotePeer(), ProtocolDHT, ProtocolDHTOld)

			switch err {
			case nil:
				s.Close()
				dht.plk.Lock()
				defer dht.plk.Unlock()

64
				// Check if canceled under the lock.
65 66 67 68
				if ctx.Err() == nil {
					dht.Update(dht.Context(), v.RemotePeer())
				}
			case io.EOF:
69 70 71 72
				if ctx.Err() == nil {
					// Connection died but we may still have *an* open connection (context not canceled) so try again.
					continue
				}
73 74 75 76 77 78 79
			case mstream.ErrNotSupported:
				// Client mode only, don't bother adding them to our routing table
			default:
				// real error? thats odd
				log.Errorf("checking dht client type: %s", err)
			}
			return
80 81
		}
	}()
82 83 84 85 86
}

func (nn *netNotifiee) Disconnected(n inet.Network, v inet.Conn) {
	dht := nn.DHT()
	select {
87
	case <-dht.Process().Closing():
88
		return
89
	default:
90
	}
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106

	dht.plk.Lock()
	defer dht.plk.Unlock()

	conn, ok := nn.peers[v.RemotePeer()]
	if !ok {
		// Unmatched disconnects are fine. It just means that we were
		// already connected when we registered the listener.
		return
	}
	conn.refcount -= 1
	if conn.refcount == 0 {
		delete(nn.peers, v.RemotePeer())
		conn.cancel()
		dht.routingTable.Remove(v.RemotePeer())
	}
107 108 109 110
}

func (nn *netNotifiee) OpenedStream(n inet.Network, v inet.Stream) {}
func (nn *netNotifiee) ClosedStream(n inet.Network, v inet.Stream) {}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
111 112
func (nn *netNotifiee) Listen(n inet.Network, a ma.Multiaddr)      {}
func (nn *netNotifiee) ListenClose(n inet.Network, a ma.Multiaddr) {}