mock_net.go 7.83 KB
Newer Older
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
1 2 3 4
package mocknet

import (
	"fmt"
5
	"sort"
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
6 7
	"sync"

8 9 10 11 12 13 14 15 16
	ic "github.com/ipfs/go-ipfs/p2p/crypto"
	host "github.com/ipfs/go-ipfs/p2p/host"
	bhost "github.com/ipfs/go-ipfs/p2p/host/basic"
	inet "github.com/ipfs/go-ipfs/p2p/net"
	peer "github.com/ipfs/go-ipfs/p2p/peer"
	p2putil "github.com/ipfs/go-ipfs/p2p/test/util"
	testutil "github.com/ipfs/go-ipfs/util/testutil"

	ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
17 18
	"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
	goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
19
	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
20 21 22 23
)

// mocknet implements mocknet.Mocknet
type mocknet struct {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
24 25
	nets  map[peer.ID]*peernet
	hosts map[peer.ID]*bhost.BasicHost
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
26 27 28 29 30

	// links make it possible to connect two peers.
	// think of links as the physical medium.
	// usually only one, but there could be multiple
	// **links are shared between peers**
31
	links map[peer.ID]map[peer.ID]map[*link]struct{}
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
32 33 34

	linkDefaults LinkOptions

35
	proc goprocess.Process // for Context closing
36
	ctx  context.Context
Jeromy's avatar
Jeromy committed
37
	sync.Mutex
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
38 39 40 41
}

func New(ctx context.Context) Mocknet {
	return &mocknet{
42
		nets:  map[peer.ID]*peernet{},
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
43
		hosts: map[peer.ID]*bhost.BasicHost{},
44
		links: map[peer.ID]map[peer.ID]map[*link]struct{}{},
45
		proc:  goprocessctx.WithContext(ctx),
46
		ctx:   ctx,
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
47 48 49
	}
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
50
func (mn *mocknet) GenPeer() (host.Host, error) {
51
	sk, err := p2putil.RandTestBogusPrivateKey()
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
52 53 54 55
	if err != nil {
		return nil, err
	}

56
	a := testutil.RandLocalTCPAddress()
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
57

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
58
	h, err := mn.AddPeer(sk, a)
59
	if err != nil {
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
60 61 62
		return nil, err
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
63
	return h, nil
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
64 65
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
66
func (mn *mocknet) AddPeer(k ic.PrivKey, a ma.Multiaddr) (host.Host, error) {
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
	p, err := peer.IDFromPublicKey(k.GetPublic())
	if err != nil {
		return nil, err
	}

	ps := peer.NewPeerstore()
	ps.AddAddr(p, a, peer.PermanentAddrTTL)
	ps.AddPrivKey(p, k)
	ps.AddPubKey(p, k.GetPublic())

	return mn.AddPeerWithPeerstore(p, ps)
}

func (mn *mocknet) AddPeerWithPeerstore(p peer.ID, ps peer.Peerstore) (host.Host, error) {
	n, err := newPeernet(mn.ctx, mn, p, ps)
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
82 83 84 85
	if err != nil {
		return nil, err
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
86
	h := bhost.New(n)
87

88
	mn.proc.AddChild(n.proc)
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
89 90

	mn.Lock()
91
	mn.nets[n.peer] = n
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
92
	mn.hosts[n.peer] = h
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
93
	mn.Unlock()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
94
	return h, nil
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
95 96
}

97
func (mn *mocknet) Peers() []peer.ID {
Jeromy's avatar
Jeromy committed
98 99
	mn.Lock()
	defer mn.Unlock()
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
100

101
	cp := make([]peer.ID, 0, len(mn.nets))
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
102 103 104
	for _, n := range mn.nets {
		cp = append(cp, n.peer)
	}
105
	sort.Sort(peer.IDSlice(cp))
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
106 107 108
	return cp
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
109
func (mn *mocknet) Host(pid peer.ID) host.Host {
Jeromy's avatar
Jeromy committed
110
	mn.Lock()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
111
	host := mn.hosts[pid]
Jeromy's avatar
Jeromy committed
112
	mn.Unlock()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
113 114 115
	return host
}

Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
116
func (mn *mocknet) Net(pid peer.ID) inet.Network {
Jeromy's avatar
Jeromy committed
117
	mn.Lock()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
118
	n := mn.nets[pid]
Jeromy's avatar
Jeromy committed
119
	mn.Unlock()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
120 121 122 123
	return n
}

func (mn *mocknet) Hosts() []host.Host {
Jeromy's avatar
Jeromy committed
124 125
	mn.Lock()
	defer mn.Unlock()
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
126

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
127 128 129
	cp := make([]host.Host, 0, len(mn.hosts))
	for _, h := range mn.hosts {
		cp = append(cp, h)
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
130
	}
131 132

	sort.Sort(hostSlice(cp))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
133
	return cp
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
134 135 136
}

func (mn *mocknet) Nets() []inet.Network {
Jeromy's avatar
Jeromy committed
137 138
	mn.Lock()
	defer mn.Unlock()
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
139 140 141 142 143

	cp := make([]inet.Network, 0, len(mn.nets))
	for _, n := range mn.nets {
		cp = append(cp, n)
	}
144
	sort.Sort(netSlice(cp))
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
145 146 147
	return cp
}

148 149 150
// Links returns a copy of the internal link state map.
// (wow, much map. so data structure. how compose. ahhh pointer)
func (mn *mocknet) Links() LinkMap {
Jeromy's avatar
Jeromy committed
151 152
	mn.Lock()
	defer mn.Unlock()
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168

	links := map[string]map[string]map[Link]struct{}{}
	for p1, lm := range mn.links {
		sp1 := string(p1)
		links[sp1] = map[string]map[Link]struct{}{}
		for p2, ls := range lm {
			sp2 := string(p2)
			links[sp1][sp2] = map[Link]struct{}{}
			for l := range ls {
				links[sp1][sp2][l] = struct{}{}
			}
		}
	}
	return links
}

Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
169 170 171 172 173 174 175 176 177 178 179 180
func (mn *mocknet) LinkAll() error {
	nets := mn.Nets()
	for _, n1 := range nets {
		for _, n2 := range nets {
			if _, err := mn.LinkNets(n1, n2); err != nil {
				return err
			}
		}
	}
	return nil
}

181
func (mn *mocknet) LinkPeers(p1, p2 peer.ID) (Link, error) {
Jeromy's avatar
Jeromy committed
182
	mn.Lock()
183 184
	n1 := mn.nets[p1]
	n2 := mn.nets[p2]
Jeromy's avatar
Jeromy committed
185
	mn.Unlock()
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205

	if n1 == nil {
		return nil, fmt.Errorf("network for p1 not in mocknet")
	}

	if n2 == nil {
		return nil, fmt.Errorf("network for p2 not in mocknet")
	}

	return mn.LinkNets(n1, n2)
}

func (mn *mocknet) validate(n inet.Network) (*peernet, error) {
	// WARNING: assumes locks acquired

	nr, ok := n.(*peernet)
	if !ok {
		return nil, fmt.Errorf("Network not supported (use mock package nets only)")
	}

206
	if _, found := mn.nets[nr.peer]; !found {
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
207 208 209 210 211 212 213
		return nil, fmt.Errorf("Network not on mocknet. is it from another mocknet?")
	}

	return nr, nil
}

func (mn *mocknet) LinkNets(n1, n2 inet.Network) (Link, error) {
Jeromy's avatar
Jeromy committed
214
	mn.Lock()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
215
	n1r, err1 := mn.validate(n1)
216
	n2r, err2 := mn.validate(n2)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
217
	ld := mn.linkDefaults
Jeromy's avatar
Jeromy committed
218
	mn.Unlock()
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
219

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
220 221
	if err1 != nil {
		return nil, err1
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
222
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
223 224
	if err2 != nil {
		return nil, err2
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
225 226
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
227 228
	l := newLink(mn, ld)
	l.nets = append(l.nets, n1r, n2r)
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
	mn.addLink(l)
	return l, nil
}

func (mn *mocknet) Unlink(l2 Link) error {

	l, ok := l2.(*link)
	if !ok {
		return fmt.Errorf("only links from mocknet are supported")
	}

	mn.removeLink(l)
	return nil
}

244
func (mn *mocknet) UnlinkPeers(p1, p2 peer.ID) error {
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
245 246 247 248 249 250 251 252 253 254 255 256 257 258
	ls := mn.LinksBetweenPeers(p1, p2)
	if ls == nil {
		return fmt.Errorf("no link between p1 and p2")
	}

	for _, l := range ls {
		if err := mn.Unlink(l); err != nil {
			return err
		}
	}
	return nil
}

func (mn *mocknet) UnlinkNets(n1, n2 inet.Network) error {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
259
	return mn.UnlinkPeers(n1.LocalPeer(), n2.LocalPeer())
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
260 261
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
262
// get from the links map. and lazily contruct.
Jeromy's avatar
Jeromy committed
263
func (mn *mocknet) linksMapGet(p1, p2 peer.ID) map[*link]struct{} {
264

265
	l1, found := mn.links[p1]
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
266
	if !found {
267 268
		mn.links[p1] = map[peer.ID]map[*link]struct{}{}
		l1 = mn.links[p1] // so we make sure it's there.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
269 270
	}

271
	l2, found := l1[p2]
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
272 273
	if !found {
		m := map[*link]struct{}{}
274 275
		l1[p2] = m
		l2 = l1[p2]
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
276 277
	}

Jeromy's avatar
Jeromy committed
278
	return l2
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
279 280
}

Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
281 282 283 284 285
func (mn *mocknet) addLink(l *link) {
	mn.Lock()
	defer mn.Unlock()

	n1, n2 := l.nets[0], l.nets[1]
Jeromy's avatar
Jeromy committed
286 287
	mn.linksMapGet(n1.peer, n2.peer)[l] = struct{}{}
	mn.linksMapGet(n2.peer, n1.peer)[l] = struct{}{}
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
288 289 290 291 292 293 294
}

func (mn *mocknet) removeLink(l *link) {
	mn.Lock()
	defer mn.Unlock()

	n1, n2 := l.nets[0], l.nets[1]
Jeromy's avatar
Jeromy committed
295 296
	delete(mn.linksMapGet(n1.peer, n2.peer), l)
	delete(mn.linksMapGet(n2.peer, n1.peer), l)
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
297 298
}

rht's avatar
rht committed
299
func (mn *mocknet) ConnectAllButSelf() error {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
300 301 302 303 304 305 306
	nets := mn.Nets()
	for _, n1 := range nets {
		for _, n2 := range nets {
			if n1 == n2 {
				continue
			}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
307
			if _, err := mn.ConnectNets(n1, n2); err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
308 309 310 311 312
				return err
			}
		}
	}
	return nil
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
313 314
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
315
func (mn *mocknet) ConnectPeers(a, b peer.ID) (inet.Conn, error) {
316
	return mn.Net(a).DialPeer(mn.ctx, b)
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
317 318
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
319
func (mn *mocknet) ConnectNets(a, b inet.Network) (inet.Conn, error) {
320
	return a.DialPeer(mn.ctx, b.LocalPeer())
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
321 322
}

323 324
func (mn *mocknet) DisconnectPeers(p1, p2 peer.ID) error {
	return mn.Net(p1).ClosePeer(p2)
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
325 326 327
}

func (mn *mocknet) DisconnectNets(n1, n2 inet.Network) error {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
328
	return n1.ClosePeer(n2.LocalPeer())
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
329 330
}

331
func (mn *mocknet) LinksBetweenPeers(p1, p2 peer.ID) []Link {
Jeromy's avatar
Jeromy committed
332 333
	mn.Lock()
	defer mn.Unlock()
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
334

Jeromy's avatar
Jeromy committed
335
	ls2 := mn.linksMapGet(p1, p2)
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
	cp := make([]Link, 0, len(ls2))
	for l := range ls2 {
		cp = append(cp, l)
	}
	return cp
}

func (mn *mocknet) LinksBetweenNets(n1, n2 inet.Network) []Link {
	return mn.LinksBetweenPeers(n1.LocalPeer(), n2.LocalPeer())
}

func (mn *mocknet) SetLinkDefaults(o LinkOptions) {
	mn.Lock()
	mn.linkDefaults = o
	mn.Unlock()
}

func (mn *mocknet) LinkDefaults() LinkOptions {
Jeromy's avatar
Jeromy committed
354 355
	mn.Lock()
	defer mn.Unlock()
Juan Batiz-Benet's avatar
mock2  
Juan Batiz-Benet committed
356 357
	return mn.linkDefaults
}
358 359 360 361 362 363 364 365 366 367 368 369 370 371

// netSlice for sorting by peer
type netSlice []inet.Network

func (es netSlice) Len() int           { return len(es) }
func (es netSlice) Swap(i, j int)      { es[i], es[j] = es[j], es[i] }
func (es netSlice) Less(i, j int) bool { return string(es[i].LocalPeer()) < string(es[j].LocalPeer()) }

// hostSlice for sorting by peer
type hostSlice []host.Host

func (es hostSlice) Len() int           { return len(es) }
func (es hostSlice) Swap(i, j int)      { es[i], es[j] = es[j], es[i] }
func (es hostSlice) Less(i, j int) bool { return string(es[i].ID()) < string(es[j].ID()) }