virtual.go 9.6 KB
Newer Older
Brian Tiger Chow's avatar
Brian Tiger Chow committed
1 2 3
package bitswap

import (
4
	"context"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
5
	"errors"
6
	"sort"
Steven Allen's avatar
Steven Allen committed
7
	"sync"
8
	"sync/atomic"
9
	"time"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
10

Jeromy's avatar
Jeromy committed
11 12
	bsmsg "github.com/ipfs/go-bitswap/message"
	bsnet "github.com/ipfs/go-bitswap/network"
13

Jeromy's avatar
Jeromy committed
14 15 16
	cid "github.com/ipfs/go-cid"
	delay "github.com/ipfs/go-ipfs-delay"
	mockrouting "github.com/ipfs/go-ipfs-routing/mock"
Raúl Kripalani's avatar
Raúl Kripalani committed
17 18 19

	"github.com/libp2p/go-libp2p-core/connmgr"
	"github.com/libp2p/go-libp2p-core/peer"
20
	protocol "github.com/libp2p/go-libp2p-core/protocol"
Raúl Kripalani's avatar
Raúl Kripalani committed
21
	"github.com/libp2p/go-libp2p-core/routing"
dirkmc's avatar
dirkmc committed
22
	tnet "github.com/libp2p/go-libp2p-testing/net"
23
	mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
24
	"github.com/libp2p/go-libp2p/p2p/protocol/ping"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
25 26
)

27 28
// VirtualNetwork generates a new testnet instance - a fake network that
// is used to simulate sending messages.
29
func VirtualNetwork(rs mockrouting.Server, d delay.D) Network {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
30
	return &network{
31 32 33 34 35 36 37 38 39 40
		latencies:          make(map[peer.ID]map[peer.ID]time.Duration),
		clients:            make(map[peer.ID]*receiverQueue),
		delay:              d,
		routingserver:      rs,
		isRateLimited:      false,
		rateLimitGenerator: nil,
		conns:              make(map[string]struct{}),
	}
}

41
// RateLimitGenerator is an interface for generating rate limits across peers
42 43 44 45
type RateLimitGenerator interface {
	NextRateLimit() float64
}

46 47
// RateLimitedVirtualNetwork generates a testnet instance where nodes are rate
// limited in the upload/download speed.
48 49 50
func RateLimitedVirtualNetwork(rs mockrouting.Server, d delay.D, rateLimitGenerator RateLimitGenerator) Network {
	return &network{
		latencies:          make(map[peer.ID]map[peer.ID]time.Duration),
51
		rateLimiters:       make(map[peer.ID]map[peer.ID]*mocknet.RateLimiter),
52 53 54 55 56 57
		clients:            make(map[peer.ID]*receiverQueue),
		delay:              d,
		routingserver:      rs,
		isRateLimited:      true,
		rateLimitGenerator: rateLimitGenerator,
		conns:              make(map[string]struct{}),
Brian Tiger Chow's avatar
Brian Tiger Chow committed
58 59 60 61
	}
}

type network struct {
62 63
	mu                 sync.Mutex
	latencies          map[peer.ID]map[peer.ID]time.Duration
64
	rateLimiters       map[peer.ID]map[peer.ID]*mocknet.RateLimiter
65 66 67 68 69 70
	clients            map[peer.ID]*receiverQueue
	routingserver      mockrouting.Server
	delay              delay.D
	isRateLimited      bool
	rateLimitGenerator RateLimitGenerator
	conns              map[string]struct{}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
71 72
}

73 74 75 76 77 78 79 80 81 82
type message struct {
	from       peer.ID
	msg        bsmsg.BitSwapMessage
	shouldSend time.Time
}

// receiverQueue queues up a set of messages to be sent, and sends them *in
// order* with their delays respected as much as sending them in order allows
// for
type receiverQueue struct {
83
	receiver *networkClient
84 85 86 87 88
	queue    []*message
	active   bool
	lk       sync.Mutex
}

dirkmc's avatar
dirkmc committed
89
func (n *network) Adapter(p tnet.Identity, opts ...bsnet.NetOpt) bsnet.BitSwapNetwork {
Steven Allen's avatar
Steven Allen committed
90 91 92
	n.mu.Lock()
	defer n.mu.Unlock()

93 94 95 96 97 98 99 100 101 102 103 104
	s := bsnet.Settings{
		SupportedProtocols: []protocol.ID{
			bsnet.ProtocolBitswap,
			bsnet.ProtocolBitswapOneOne,
			bsnet.ProtocolBitswapOneZero,
			bsnet.ProtocolBitswapNoVers,
		},
	}
	for _, opt := range opts {
		opt(&s)
	}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
105
	client := &networkClient{
106 107 108 109
		local:              p.ID(),
		network:            n,
		routing:            n.routingserver.Client(p),
		supportedProtocols: s.SupportedProtocols,
Brian Tiger Chow's avatar
Brian Tiger Chow committed
110
	}
111
	n.clients[p.ID()] = &receiverQueue{receiver: client}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
112 113 114
	return client
}

115
func (n *network) HasPeer(p peer.ID) bool {
Steven Allen's avatar
Steven Allen committed
116 117 118
	n.mu.Lock()
	defer n.mu.Unlock()

119
	_, found := n.clients[p]
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
120 121 122
	return found
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
123 124 125 126
// TODO should this be completely asynchronous?
// TODO what does the network layer do with errors received from services?
func (n *network) SendMessage(
	ctx context.Context,
127 128
	from peer.ID,
	to peer.ID,
129
	mes bsmsg.BitSwapMessage) error {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
130

Dirk McCormick's avatar
Dirk McCormick committed
131 132
	mes = mes.Clone()

Steven Allen's avatar
Steven Allen committed
133 134 135
	n.mu.Lock()
	defer n.mu.Unlock()

136 137 138 139 140 141 142 143 144 145 146 147
	latencies, ok := n.latencies[from]
	if !ok {
		latencies = make(map[peer.ID]time.Duration)
		n.latencies[from] = latencies
	}

	latency, ok := latencies[to]
	if !ok {
		latency = n.delay.NextWaitTime()
		latencies[to] = latency
	}

148 149 150 151
	var bandwidthDelay time.Duration
	if n.isRateLimited {
		rateLimiters, ok := n.rateLimiters[from]
		if !ok {
152
			rateLimiters = make(map[peer.ID]*mocknet.RateLimiter)
153 154 155
			n.rateLimiters[from] = rateLimiters
		}

156
		rateLimiter, ok := rateLimiters[to]
157
		if !ok {
158 159
			rateLimiter = mocknet.NewRateLimiter(n.rateLimitGenerator.NextRateLimit())
			rateLimiters[to] = rateLimiter
160 161 162
		}

		size := mes.ToProtoV1().Size()
163
		bandwidthDelay = rateLimiter.Limit(size)
164 165 166 167
	} else {
		bandwidthDelay = 0
	}

168
	receiver, ok := n.clients[to]
Brian Tiger Chow's avatar
Brian Tiger Chow committed
169
	if !ok {
Łukasz Magiera's avatar
Łukasz Magiera committed
170
		return errors.New("cannot locate peer on network")
Brian Tiger Chow's avatar
Brian Tiger Chow committed
171 172 173 174 175
	}

	// nb: terminate the context since the context wouldn't actually be passed
	// over the network in a real scenario

176 177 178
	msg := &message{
		from:       from,
		msg:        mes,
179
		shouldSend: time.Now().Add(latency).Add(bandwidthDelay),
180 181
	}
	receiver.enqueue(msg)
Brian Tiger Chow's avatar
Brian Tiger Chow committed
182 183 184 185 186

	return nil
}

type networkClient struct {
187
	local peer.ID
Brian Tiger Chow's avatar
Brian Tiger Chow committed
188
	bsnet.Receiver
189 190 191 192
	network            *network
	routing            routing.Routing
	stats              bsnet.Stats
	supportedProtocols []protocol.ID
Brian Tiger Chow's avatar
Brian Tiger Chow committed
193 194
}

dirkmc's avatar
dirkmc committed
195 196 197 198
func (nc *networkClient) Self() peer.ID {
	return nc.local
}

199 200 201 202 203 204 205 206 207 208
func (nc *networkClient) Ping(ctx context.Context, p peer.ID) ping.Result {
	return ping.Result{RTT: nc.Latency(p)}
}

func (nc *networkClient) Latency(p peer.ID) time.Duration {
	nc.network.mu.Lock()
	defer nc.network.mu.Unlock()
	return nc.network.latencies[nc.local][p]
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
209 210
func (nc *networkClient) SendMessage(
	ctx context.Context,
211
	to peer.ID,
Brian Tiger Chow's avatar
Brian Tiger Chow committed
212
	message bsmsg.BitSwapMessage) error {
213 214 215 216 217 218 219
	if err := nc.network.SendMessage(ctx, nc.local, to, message); err != nil {
		return err
	}
	atomic.AddUint64(&nc.stats.MessagesSent, 1)
	return nil
}

220 221
func (nc *networkClient) Stats() bsnet.Stats {
	return bsnet.Stats{
222 223 224
		MessagesRecvd: atomic.LoadUint64(&nc.stats.MessagesRecvd),
		MessagesSent:  atomic.LoadUint64(&nc.stats.MessagesSent),
	}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
225 226
}

227
// FindProvidersAsync returns a channel of providers for the given key.
228
func (nc *networkClient) FindProvidersAsync(ctx context.Context, k cid.Cid, max int) <-chan peer.ID {
Raúl Kripalani's avatar
Raúl Kripalani committed
229
	// NB: this function duplicates the AddrInfo -> ID transformation in the
230 231 232 233 234 235 236
	// bitswap network adapter. Not to worry. This network client will be
	// deprecated once the ipfsnet.Mock is added. The code below is only
	// temporary.

	out := make(chan peer.ID)
	go func() {
		defer close(out)
237
		providers := nc.routing.FindProvidersAsync(ctx, k, max)
238 239 240 241 242 243 244 245
		for info := range providers {
			select {
			case <-ctx.Done():
			case out <- info.ID:
			}
		}
	}()
	return out
246 247
}

Raúl Kripalani's avatar
Raúl Kripalani committed
248 249
func (nc *networkClient) ConnectionManager() connmgr.ConnManager {
	return &connmgr.NullConnMgr{}
250 251
}

Jeromy's avatar
Jeromy committed
252
type messagePasser struct {
253
	net    *networkClient
Jeromy's avatar
Jeromy committed
254 255 256 257 258
	target peer.ID
	local  peer.ID
	ctx    context.Context
}

259
func (mp *messagePasser) SendMsg(ctx context.Context, m bsmsg.BitSwapMessage) error {
260
	return mp.net.SendMessage(ctx, mp.target, m)
Jeromy's avatar
Jeromy committed
261 262 263 264 265 266
}

func (mp *messagePasser) Close() error {
	return nil
}

267 268 269 270
func (mp *messagePasser) Reset() error {
	return nil
}

271 272 273 274 275 276
var oldProtos = map[protocol.ID]struct{}{
	bsnet.ProtocolBitswapNoVers:  struct{}{},
	bsnet.ProtocolBitswapOneZero: struct{}{},
	bsnet.ProtocolBitswapOneOne:  struct{}{},
}

dirkmc's avatar
dirkmc committed
277
func (mp *messagePasser) SupportsHave() bool {
278 279 280 281 282 283 284
	protos := mp.net.network.clients[mp.target].receiver.supportedProtocols
	for _, proto := range protos {
		if _, ok := oldProtos[proto]; !ok {
			return true
		}
	}
	return false
dirkmc's avatar
dirkmc committed
285 286
}

287
func (nc *networkClient) NewMessageSender(ctx context.Context, p peer.ID) (bsnet.MessageSender, error) {
Jeromy's avatar
Jeromy committed
288
	return &messagePasser{
289
		net:    nc,
Jeromy's avatar
Jeromy committed
290
		target: p,
291
		local:  nc.local,
Jeromy's avatar
Jeromy committed
292 293 294 295
		ctx:    ctx,
	}, nil
}

296
// Provide provides the key to the network.
297
func (nc *networkClient) Provide(ctx context.Context, k cid.Cid) error {
298
	return nc.routing.Provide(ctx, k, true)
299 300
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
301 302 303
func (nc *networkClient) SetDelegate(r bsnet.Receiver) {
	nc.Receiver = r
}
304 305

func (nc *networkClient) ConnectTo(_ context.Context, p peer.ID) error {
Steven Allen's avatar
Steven Allen committed
306 307 308 309
	nc.network.mu.Lock()
	otherClient, ok := nc.network.clients[p]
	if !ok {
		nc.network.mu.Unlock()
310 311
		return errors.New("no such peer in network")
	}
Steven Allen's avatar
Steven Allen committed
312

313 314
	tag := tagForPeers(nc.local, p)
	if _, ok := nc.network.conns[tag]; ok {
Steven Allen's avatar
Steven Allen committed
315
		nc.network.mu.Unlock()
dirkmc's avatar
dirkmc committed
316
		// log.Warning("ALREADY CONNECTED TO PEER (is this a reconnect? test lib needs fixing)")
317 318 319
		return nil
	}
	nc.network.conns[tag] = struct{}{}
Steven Allen's avatar
Steven Allen committed
320 321
	nc.network.mu.Unlock()

322
	otherClient.receiver.PeerConnected(nc.local)
323 324 325
	nc.Receiver.PeerConnected(p)
	return nil
}
326

dirkmc's avatar
dirkmc committed
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
func (nc *networkClient) DisconnectFrom(_ context.Context, p peer.ID) error {
	nc.network.mu.Lock()
	defer nc.network.mu.Unlock()

	otherClient, ok := nc.network.clients[p]
	if !ok {
		return errors.New("no such peer in network")
	}

	tag := tagForPeers(nc.local, p)
	if _, ok := nc.network.conns[tag]; !ok {
		// Already disconnected
		return nil
	}
	delete(nc.network.conns, tag)

	otherClient.receiver.PeerDisconnected(nc.local)
	nc.Receiver.PeerDisconnected(p)
	return nil
}

348 349 350 351 352 353 354 355 356 357
func (rq *receiverQueue) enqueue(m *message) {
	rq.lk.Lock()
	defer rq.lk.Unlock()
	rq.queue = append(rq.queue, m)
	if !rq.active {
		rq.active = true
		go rq.process()
	}
}

358 359 360 361 362 363 364 365 366 367 368 369
func (rq *receiverQueue) Swap(i, j int) {
	rq.queue[i], rq.queue[j] = rq.queue[j], rq.queue[i]
}

func (rq *receiverQueue) Len() int {
	return len(rq.queue)
}

func (rq *receiverQueue) Less(i, j int) bool {
	return rq.queue[i].shouldSend.UnixNano() < rq.queue[j].shouldSend.UnixNano()
}

370 371 372
func (rq *receiverQueue) process() {
	for {
		rq.lk.Lock()
373
		sort.Sort(rq)
374 375 376 377 378 379
		if len(rq.queue) == 0 {
			rq.active = false
			rq.lk.Unlock()
			return
		}
		m := rq.queue[0]
380 381 382 383 384 385 386 387 388 389
		if time.Until(m.shouldSend).Seconds() < 0.1 {
			rq.queue = rq.queue[1:]
			rq.lk.Unlock()
			time.Sleep(time.Until(m.shouldSend))
			atomic.AddUint64(&rq.receiver.stats.MessagesRecvd, 1)
			rq.receiver.ReceiveMessage(context.TODO(), m.from, m.msg)
		} else {
			rq.lk.Unlock()
			time.Sleep(100 * time.Millisecond)
		}
390 391 392
	}
}

393 394 395 396 397 398
func tagForPeers(a, b peer.ID) string {
	if a < b {
		return string(a + b)
	}
	return string(b + a)
}