dht.go 16.3 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2
package dht

3
import (
4
	"bytes"
5 6 7
	"errors"
	"sync"
	"time"
8

9
	peer "github.com/jbenet/go-ipfs/peer"
Jeromy's avatar
Jeromy committed
10
	kb "github.com/jbenet/go-ipfs/routing/kbucket"
11 12
	swarm "github.com/jbenet/go-ipfs/swarm"
	u "github.com/jbenet/go-ipfs/util"
13 14

	ma "github.com/jbenet/go-multiaddr"
Jeromy's avatar
Jeromy committed
15 16 17

	ds "github.com/jbenet/datastore.go"

18
	"code.google.com/p/goprotobuf/proto"
19 20
)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
21 22 23 24 25
// TODO. SEE https://github.com/jbenet/node-ipfs/blob/master/submodules/ipfs-dht/index.js

// IpfsDHT is an implementation of Kademlia with Coral and S/Kademlia modifications.
// It is used to implement the base IpfsRouting module.
type IpfsDHT struct {
26 27
	// Array of routing tables for differently distanced nodes
	// NOTE: (currently, only a single table is used)
28
	routingTables []*kb.RoutingTable
29

30
	network swarm.Network
31

Jeromy's avatar
Jeromy committed
32 33 34 35 36
	// Local peer (yourself)
	self *peer.Peer

	// Local data
	datastore ds.Datastore
37
	dslock    sync.Mutex
38

39
	providers *ProviderManager
40

41 42
	// Signal to shutdown dht
	shutdown chan struct{}
43 44 45

	// When this peer started up
	birth time.Time
46 47 48

	//lock to make diagnostics work better
	diaglock sync.Mutex
49

50
	// listener is a server to register to listen for responses to messages
51
	listener *mesListener
52 53
}

Jeromy's avatar
Jeromy committed
54
// NewDHT creates a new DHT object with the given peer as the 'local' host
Jeromy's avatar
Jeromy committed
55
func NewDHT(p *peer.Peer, net swarm.Network) *IpfsDHT {
56
	dht := new(IpfsDHT)
Jeromy's avatar
Jeromy committed
57
	dht.network = net
58 59
	dht.datastore = ds.NewMapDatastore()
	dht.self = p
60
	dht.providers = NewProviderManager()
Jeromy's avatar
Jeromy committed
61
	dht.shutdown = make(chan struct{})
62

63 64 65 66 67
	dht.routingTables = make([]*kb.RoutingTable, 3)
	dht.routingTables[0] = kb.NewRoutingTable(20, kb.ConvertPeerID(p.ID), time.Millisecond*30)
	dht.routingTables[1] = kb.NewRoutingTable(20, kb.ConvertPeerID(p.ID), time.Millisecond*100)
	dht.routingTables[2] = kb.NewRoutingTable(20, kb.ConvertPeerID(p.ID), time.Hour)
	dht.listener = newMesListener()
68
	dht.birth = time.Now()
Jeromy's avatar
Jeromy committed
69
	return dht
70 71
}

72
// Start up background goroutines needed by the DHT
73 74 75 76
func (dht *IpfsDHT) Start() {
	go dht.handleMessages()
}

77
// Connect to a new peer at the given address, ping and add to the routing table
78
func (dht *IpfsDHT) Connect(addr *ma.Multiaddr) (*peer.Peer, error) {
79
	maddrstr, _ := addr.String()
80
	u.DOut("Connect to new peer: %s\n", maddrstr)
81
	npeer, err := dht.network.ConnectNew(addr)
82
	if err != nil {
83
		return nil, err
84 85
	}

Jeromy's avatar
Jeromy committed
86 87
	// Ping new peer to register in their routing table
	// NOTE: this should be done better...
88
	err = dht.Ping(npeer, time.Second*2)
Jeromy's avatar
Jeromy committed
89
	if err != nil {
Jeromy's avatar
Jeromy committed
90
		return nil, errors.New("failed to ping newly connected peer\n")
Jeromy's avatar
Jeromy committed
91 92
	}

93 94
	dht.Update(npeer)

95
	return npeer, nil
Jeromy's avatar
Jeromy committed
96 97
}

98 99
// Read in all messages from swarm and handle them appropriately
// NOTE: this function is just a quick sketch
100
func (dht *IpfsDHT) handleMessages() {
Jeromy's avatar
Jeromy committed
101
	u.DOut("Begin message handling routine\n")
102

103 104
	errs := dht.network.GetErrChan()
	dhtmes := dht.network.GetChannel(swarm.PBWrapper_DHT_MESSAGE)
105 106
	for {
		select {
107
		case mes, ok := <-dhtmes:
108
			if !ok {
Jeromy's avatar
Jeromy committed
109
				u.DOut("handleMessages closing, bad recv on incoming\n")
110 111
				return
			}
112
			pmes := new(PBDHTMessage)
113 114
			err := proto.Unmarshal(mes.Data, pmes)
			if err != nil {
115
				u.PErr("Failed to decode protobuf message: %s\n", err)
116 117 118
				continue
			}

119
			dht.Update(mes.Peer)
120

121
			// Note: not sure if this is the correct place for this
122
			if pmes.GetResponse() {
123
				dht.listener.Respond(pmes.GetId(), mes)
124
				continue
125
			}
126 127
			//

128
			u.DOut("[peer: %s]\nGot message type: '%s' [id = %x, from = %s]\n",
Jeromy's avatar
Jeromy committed
129
				dht.self.ID.Pretty(),
130
				PBDHTMessage_MessageType_name[int32(pmes.GetType())],
131
				pmes.GetId(), mes.Peer.ID.Pretty())
132
			switch pmes.GetType() {
133
			case PBDHTMessage_GET_VALUE:
134
				dht.handleGetValue(mes.Peer, pmes)
135
			case PBDHTMessage_PUT_VALUE:
Jeromy's avatar
Jeromy committed
136
				dht.handlePutValue(mes.Peer, pmes)
137
			case PBDHTMessage_FIND_NODE:
Jeromy's avatar
Jeromy committed
138
				dht.handleFindPeer(mes.Peer, pmes)
139
			case PBDHTMessage_ADD_PROVIDER:
140
				dht.handleAddProvider(mes.Peer, pmes)
141
			case PBDHTMessage_GET_PROVIDERS:
142
				dht.handleGetProviders(mes.Peer, pmes)
143
			case PBDHTMessage_PING:
144
				dht.handlePing(mes.Peer, pmes)
145
			case PBDHTMessage_DIAGNOSTIC:
146
				dht.handleDiagnostic(mes.Peer, pmes)
147 148
			default:
				u.PErr("Recieved invalid message type")
149 150
			}

151
		case err := <-errs:
152
			u.PErr("dht err: %s\n", err)
153 154
		case <-dht.shutdown:
			return
155 156 157 158
		}
	}
}

Jeromy's avatar
Jeromy committed
159
func (dht *IpfsDHT) putValueToNetwork(p *peer.Peer, key string, value []byte) error {
160
	pmes := Message{
161 162
		Type:  PBDHTMessage_PUT_VALUE,
		Key:   key,
163
		Value: value,
164
		ID:    GenerateMessageID(),
165 166 167
	}

	mes := swarm.NewMessage(p, pmes.ToProtobuf())
168
	dht.network.Send(mes)
169 170 171
	return nil
}

172
func (dht *IpfsDHT) handleGetValue(p *peer.Peer, pmes *PBDHTMessage) {
173
	u.DOut("handleGetValue for key: %s\n", pmes.GetKey())
Jeromy's avatar
Jeromy committed
174
	dskey := ds.NewKey(pmes.GetKey())
175
	resp := &Message{
Jeromy's avatar
Jeromy committed
176
		Response: true,
177
		ID:       pmes.GetId(),
Jeromy's avatar
Jeromy committed
178 179 180
		Key:      pmes.GetKey(),
	}
	iVal, err := dht.datastore.Get(dskey)
Jeromy's avatar
Jeromy committed
181
	if err == nil {
Jeromy's avatar
Jeromy committed
182
		u.DOut("handleGetValue success!\n")
Jeromy's avatar
Jeromy committed
183 184
		resp.Success = true
		resp.Value = iVal.([]byte)
Jeromy's avatar
Jeromy committed
185
	} else if err == ds.ErrNotFound {
Jeromy's avatar
Jeromy committed
186
		// Check if we know any providers for the requested value
187 188
		provs := dht.providers.GetProviders(u.Key(pmes.GetKey()))
		if len(provs) > 0 {
189
			u.DOut("handleGetValue returning %d provider[s]\n", len(provs))
190
			resp.Peers = provs
Jeromy's avatar
Jeromy committed
191 192 193
			resp.Success = true
		} else {
			// No providers?
194 195
			// Find closest peer on given cluster to desired key and reply with that info

196 197 198
			level := 0
			if len(pmes.GetValue()) < 1 {
				// TODO: maybe return an error? Defaulting isnt a good idea IMO
Jeromy's avatar
Jeromy committed
199
				u.PErr("handleGetValue: no routing level specified, assuming 0\n")
200 201 202
			} else {
				level = int(pmes.GetValue()[0]) // Using value field to specify cluster level
			}
203
			u.DOut("handleGetValue searching level %d clusters\n", level)
204

205
			closer := dht.routingTables[level].NearestPeer(kb.ConvertKey(u.Key(pmes.GetKey())))
206

Jeromy's avatar
Jeromy committed
207
			if closer.ID.Equal(dht.self.ID) {
Jeromy's avatar
Jeromy committed
208
				u.DOut("Attempted to return self! this shouldnt happen...\n")
Jeromy's avatar
Jeromy committed
209 210 211
				resp.Peers = nil
				goto out
			}
212 213 214
			// If this peer is closer than the one from the table, return nil
			if kb.Closer(dht.self.ID, closer.ID, u.Key(pmes.GetKey())) {
				resp.Peers = nil
Jeromy's avatar
Jeromy committed
215
				u.DOut("handleGetValue could not find a closer node than myself.\n")
216
			} else {
217
				u.DOut("handleGetValue returning a closer peer: '%s'\n", closer.ID.Pretty())
218 219
				resp.Peers = []*peer.Peer{closer}
			}
220
		}
Jeromy's avatar
Jeromy committed
221
	} else {
222
		//temp: what other errors can a datastore return?
Jeromy's avatar
Jeromy committed
223
		panic(err)
224
	}
225

Jeromy's avatar
Jeromy committed
226
out:
227
	mes := swarm.NewMessage(p, resp.ToProtobuf())
228
	dht.network.Send(mes)
229 230
}

Jeromy's avatar
Jeromy committed
231
// Store a value in this peer local storage
232
func (dht *IpfsDHT) handlePutValue(p *peer.Peer, pmes *PBDHTMessage) {
233 234
	dht.dslock.Lock()
	defer dht.dslock.Unlock()
Jeromy's avatar
Jeromy committed
235 236 237 238 239 240
	dskey := ds.NewKey(pmes.GetKey())
	err := dht.datastore.Put(dskey, pmes.GetValue())
	if err != nil {
		// For now, just panic, handle this better later maybe
		panic(err)
	}
241 242
}

243
func (dht *IpfsDHT) handlePing(p *peer.Peer, pmes *PBDHTMessage) {
244
	resp := Message{
245
		Type:     pmes.GetType(),
246
		Response: true,
247
		ID:       pmes.GetId(),
248
	}
249

250
	dht.network.Send(swarm.NewMessage(p, resp.ToProtobuf()))
251 252
}

253
func (dht *IpfsDHT) handleFindPeer(p *peer.Peer, pmes *PBDHTMessage) {
254
	resp := Message{
255
		Type:     pmes.GetType(),
256
		ID:       pmes.GetId(),
257 258 259 260 261 262 263
		Response: true,
	}
	defer func() {
		mes := swarm.NewMessage(p, resp.ToProtobuf())
		dht.network.Send(mes)
	}()
	level := pmes.GetValue()[0]
264
	u.DOut("handleFindPeer: searching for '%s'\n", peer.ID(pmes.GetKey()).Pretty())
265
	closest := dht.routingTables[level].NearestPeer(kb.ConvertKey(u.Key(pmes.GetKey())))
Jeromy's avatar
Jeromy committed
266
	if closest == nil {
Jeromy's avatar
Jeromy committed
267
		u.PErr("handleFindPeer: could not find anything.\n")
268
		return
Jeromy's avatar
Jeromy committed
269 270 271
	}

	if len(closest.Addresses) == 0 {
Jeromy's avatar
Jeromy committed
272
		u.PErr("handleFindPeer: no addresses for connected peer...\n")
273
		return
Jeromy's avatar
Jeromy committed
274 275
	}

276 277 278
	// If the found peer further away than this peer...
	if kb.Closer(dht.self.ID, closest.ID, u.Key(pmes.GetKey())) {
		return
Jeromy's avatar
Jeromy committed
279 280
	}

281
	u.DOut("handleFindPeer: sending back '%s'\n", closest.ID.Pretty())
282 283 284 285 286
	resp.Peers = []*peer.Peer{closest}
	resp.Success = true
}

func (dht *IpfsDHT) handleGetProviders(p *peer.Peer, pmes *PBDHTMessage) {
287
	resp := Message{
288 289
		Type:     PBDHTMessage_GET_PROVIDERS,
		Key:      pmes.GetKey(),
290
		ID:       pmes.GetId(),
291
		Response: true,
Jeromy's avatar
Jeromy committed
292 293
	}

294
	providers := dht.providers.GetProviders(u.Key(pmes.GetKey()))
295
	if providers == nil || len(providers) == 0 {
Jeromy's avatar
Jeromy committed
296 297 298 299 300
		level := 0
		if len(pmes.GetValue()) > 0 {
			level = int(pmes.GetValue()[0])
		}

301
		closer := dht.routingTables[level].NearestPeer(kb.ConvertKey(u.Key(pmes.GetKey())))
Jeromy's avatar
Jeromy committed
302 303 304 305 306
		if kb.Closer(dht.self.ID, closer.ID, u.Key(pmes.GetKey())) {
			resp.Peers = nil
		} else {
			resp.Peers = []*peer.Peer{closer}
		}
307
	} else {
308
		resp.Peers = providers
309
		resp.Success = true
310 311 312
	}

	mes := swarm.NewMessage(p, resp.ToProtobuf())
313
	dht.network.Send(mes)
314 315
}

316 317
type providerInfo struct {
	Creation time.Time
318
	Value    *peer.Peer
319 320
}

321
func (dht *IpfsDHT) handleAddProvider(p *peer.Peer, pmes *PBDHTMessage) {
322
	key := u.Key(pmes.GetKey())
323
	dht.providers.AddProvider(key, p)
324 325
}

326
// Halt stops all communications from this peer and shut down
327 328 329 330
func (dht *IpfsDHT) Halt() {
	dht.shutdown <- struct{}{}
	dht.network.Close()
}
331

Jeromy's avatar
Jeromy committed
332
// NOTE: not yet finished, low priority
333
func (dht *IpfsDHT) handleDiagnostic(p *peer.Peer, pmes *PBDHTMessage) {
334
	seq := dht.routingTables[0].NearestPeers(kb.ConvertPeerID(dht.self.ID), 10)
335
	listenChan := dht.listener.Listen(pmes.GetId(), len(seq), time.Second*30)
336

337
	for _, ps := range seq {
338
		mes := swarm.NewMessage(ps, pmes)
339
		dht.network.Send(mes)
340 341 342
	}

	buf := new(bytes.Buffer)
343 344 345
	di := dht.getDiagInfo()
	buf.Write(di.Marshal())

346 347 348 349 350 351 352 353
	// NOTE: this shouldnt be a hardcoded value
	after := time.After(time.Second * 20)
	count := len(seq)
	for count > 0 {
		select {
		case <-after:
			//Timeout, return what we have
			goto out
354 355 356
		case reqResp := <-listenChan:
			pmesOut := new(PBDHTMessage)
			err := proto.Unmarshal(reqResp.Data, pmesOut)
357 358 359 360
			if err != nil {
				// It broke? eh, whatever, keep going
				continue
			}
361
			buf.Write(reqResp.Data)
362 363 364 365 366
			count--
		}
	}

out:
367
	resp := Message{
368
		Type:     PBDHTMessage_DIAGNOSTIC,
369
		ID:       pmes.GetId(),
370
		Value:    buf.Bytes(),
371 372 373 374
		Response: true,
	}

	mes := swarm.NewMessage(p, resp.ToProtobuf())
375
	dht.network.Send(mes)
376
}
377

378 379 380
func (dht *IpfsDHT) getValueOrPeers(p *peer.Peer, key u.Key, timeout time.Duration, level int) ([]byte, []*peer.Peer, error) {
	pmes, err := dht.getValueSingle(p, key, timeout, level)
	if err != nil {
381
		return nil, nil, err
382 383 384 385 386 387 388 389 390 391 392 393 394
	}

	if pmes.GetSuccess() {
		if pmes.Value == nil { // We were given provider[s]
			val, err := dht.getFromPeerList(key, timeout, pmes.GetPeers(), level)
			if err != nil {
				return nil, nil, err
			}
			return val, nil, nil
		}

		// Success! We were given the value
		return pmes.GetValue(), nil, nil
395
	}
396

397 398 399 400 401 402 403 404
	// We were given a closer node
	var peers []*peer.Peer
	for _, pb := range pmes.GetPeers() {
		if peer.ID(pb.GetId()).Equal(dht.self.ID) {
			continue
		}
		addr, err := ma.NewMultiaddr(pb.GetAddr())
		if err != nil {
405
			u.PErr("%v\n", err.Error())
406 407
			continue
		}
408

409 410
		np, err := dht.network.GetConnection(peer.ID(pb.GetId()), addr)
		if err != nil {
411
			u.PErr("%v\n", err.Error())
412
			continue
413
		}
414 415

		peers = append(peers, np)
416
	}
417
	return nil, peers, nil
418 419
}

420 421
// getValueSingle simply performs the get value RPC with the given parameters
func (dht *IpfsDHT) getValueSingle(p *peer.Peer, key u.Key, timeout time.Duration, level int) (*PBDHTMessage, error) {
422
	pmes := Message{
423 424 425
		Type:  PBDHTMessage_GET_VALUE,
		Key:   string(key),
		Value: []byte{byte(level)},
426
		ID:    GenerateMessageID(),
Jeromy's avatar
Jeromy committed
427
	}
428
	responseChan := dht.listener.Listen(pmes.ID, 1, time.Minute)
Jeromy's avatar
Jeromy committed
429 430

	mes := swarm.NewMessage(p, pmes.ToProtobuf())
431
	t := time.Now()
432
	dht.network.Send(mes)
Jeromy's avatar
Jeromy committed
433 434 435 436 437

	// Wait for either the response or a timeout
	timeup := time.After(timeout)
	select {
	case <-timeup:
438
		dht.listener.Unlisten(pmes.ID)
Jeromy's avatar
Jeromy committed
439
		return nil, u.ErrTimeout
440
	case resp, ok := <-responseChan:
Jeromy's avatar
Jeromy committed
441
		if !ok {
Jeromy's avatar
Jeromy committed
442
			u.PErr("response channel closed before timeout, please investigate.\n")
Jeromy's avatar
Jeromy committed
443 444
			return nil, u.ErrTimeout
		}
445 446
		roundtrip := time.Since(t)
		resp.Peer.SetLatency(roundtrip)
447 448
		pmesOut := new(PBDHTMessage)
		err := proto.Unmarshal(resp.Data, pmesOut)
Jeromy's avatar
Jeromy committed
449 450 451
		if err != nil {
			return nil, err
		}
452
		return pmesOut, nil
Jeromy's avatar
Jeromy committed
453 454 455
	}
}

456 457 458 459 460 461 462 463 464 465
// TODO: Im not certain on this implementation, we get a list of peers/providers
// from someone what do we do with it? Connect to each of them? randomly pick
// one to get the value from? Or just connect to one at a time until we get a
// successful connection and request the value from it?
func (dht *IpfsDHT) getFromPeerList(key u.Key, timeout time.Duration,
	peerlist []*PBDHTMessage_PBPeer, level int) ([]byte, error) {
	for _, pinfo := range peerlist {
		p, _ := dht.Find(peer.ID(pinfo.GetId()))
		if p == nil {
			maddr, err := ma.NewMultiaddr(pinfo.GetAddr())
Jeromy's avatar
Jeromy committed
466
			if err != nil {
467
				u.PErr("getValue error: %s\n", err)
Jeromy's avatar
Jeromy committed
468 469
				continue
			}
470

471
			p, err = dht.network.GetConnection(peer.ID(pinfo.GetId()), maddr)
Jeromy's avatar
Jeromy committed
472
			if err != nil {
473
				u.PErr("getValue error: %s\n", err)
Jeromy's avatar
Jeromy committed
474 475 476
				continue
			}
		}
477
		pmes, err := dht.getValueSingle(p, key, timeout, level)
Jeromy's avatar
Jeromy committed
478
		if err != nil {
479
			u.DErr("getFromPeers error: %s\n", err)
Jeromy's avatar
Jeromy committed
480 481
			continue
		}
482
		dht.providers.AddProvider(key, p)
Jeromy's avatar
Jeromy committed
483

484 485 486 487
		// Make sure it was a successful get
		if pmes.GetSuccess() && pmes.Value != nil {
			return pmes.GetValue(), nil
		}
Jeromy's avatar
Jeromy committed
488 489 490 491
	}
	return nil, u.ErrNotFound
}

492
func (dht *IpfsDHT) getLocal(key u.Key) ([]byte, error) {
493 494
	dht.dslock.Lock()
	defer dht.dslock.Unlock()
495
	v, err := dht.datastore.Get(ds.NewKey(string(key)))
496 497 498 499 500 501
	if err != nil {
		return nil, err
	}
	return v.([]byte), nil
}

502
func (dht *IpfsDHT) putLocal(key u.Key, value []byte) error {
503 504
	return dht.datastore.Put(ds.NewKey(string(key)), value)
}
505

506
// Update TODO(chas) Document this function
507
func (dht *IpfsDHT) Update(p *peer.Peer) {
508
	for _, route := range dht.routingTables {
509 510 511 512
		removed := route.Update(p)
		// Only drop the connection if no tables refer to this peer
		if removed != nil {
			found := false
513
			for _, r := range dht.routingTables {
514 515 516 517 518 519 520 521 522
				if r.Find(removed.ID) != nil {
					found = true
					break
				}
			}
			if !found {
				dht.network.Drop(removed)
			}
		}
523 524
	}
}
Jeromy's avatar
Jeromy committed
525

526
// Find looks for a peer with a given ID connected to this dht and returns the peer and the table it was found in.
Jeromy's avatar
Jeromy committed
527
func (dht *IpfsDHT) Find(id peer.ID) (*peer.Peer, *kb.RoutingTable) {
528
	for _, table := range dht.routingTables {
Jeromy's avatar
Jeromy committed
529 530 531 532 533 534 535
		p := table.Find(id)
		if p != nil {
			return p, table
		}
	}
	return nil, nil
}
536 537

func (dht *IpfsDHT) findPeerSingle(p *peer.Peer, id peer.ID, timeout time.Duration, level int) (*PBDHTMessage, error) {
538
	pmes := Message{
539 540
		Type:  PBDHTMessage_FIND_NODE,
		Key:   string(id),
541
		ID:    GenerateMessageID(),
542 543 544 545
		Value: []byte{byte(level)},
	}

	mes := swarm.NewMessage(p, pmes.ToProtobuf())
546
	listenChan := dht.listener.Listen(pmes.ID, 1, time.Minute)
547
	t := time.Now()
548 549 550 551
	dht.network.Send(mes)
	after := time.After(timeout)
	select {
	case <-after:
552
		dht.listener.Unlisten(pmes.ID)
553 554
		return nil, u.ErrTimeout
	case resp := <-listenChan:
555 556
		roundtrip := time.Since(t)
		resp.Peer.SetLatency(roundtrip)
557 558
		pmesOut := new(PBDHTMessage)
		err := proto.Unmarshal(resp.Data, pmesOut)
559 560 561 562
		if err != nil {
			return nil, err
		}

563
		return pmesOut, nil
564 565
	}
}
566

567 568
func (dht *IpfsDHT) printTables() {
	for _, route := range dht.routingTables {
569 570 571
		route.Print()
	}
}
Jeromy's avatar
Jeromy committed
572 573

func (dht *IpfsDHT) findProvidersSingle(p *peer.Peer, key u.Key, level int, timeout time.Duration) (*PBDHTMessage, error) {
574
	pmes := Message{
Jeromy's avatar
Jeromy committed
575 576
		Type:  PBDHTMessage_GET_PROVIDERS,
		Key:   string(key),
577
		ID:    GenerateMessageID(),
Jeromy's avatar
Jeromy committed
578 579 580 581 582
		Value: []byte{byte(level)},
	}

	mes := swarm.NewMessage(p, pmes.ToProtobuf())

583
	listenChan := dht.listener.Listen(pmes.ID, 1, time.Minute)
Jeromy's avatar
Jeromy committed
584 585 586 587
	dht.network.Send(mes)
	after := time.After(timeout)
	select {
	case <-after:
588
		dht.listener.Unlisten(pmes.ID)
Jeromy's avatar
Jeromy committed
589 590
		return nil, u.ErrTimeout
	case resp := <-listenChan:
Jeromy's avatar
Jeromy committed
591
		u.DOut("FindProviders: got response.\n")
592 593
		pmesOut := new(PBDHTMessage)
		err := proto.Unmarshal(resp.Data, pmesOut)
Jeromy's avatar
Jeromy committed
594 595 596 597
		if err != nil {
			return nil, err
		}

598
		return pmesOut, nil
Jeromy's avatar
Jeromy committed
599 600 601 602
	}
}

func (dht *IpfsDHT) addPeerList(key u.Key, peers []*PBDHTMessage_PBPeer) []*peer.Peer {
603
	var provArr []*peer.Peer
Jeromy's avatar
Jeromy committed
604 605 606 607 608 609 610 611
	for _, prov := range peers {
		// Dont add outselves to the list
		if peer.ID(prov.GetId()).Equal(dht.self.ID) {
			continue
		}
		// Dont add someone who is already on the list
		p := dht.network.Find(u.Key(prov.GetId()))
		if p == nil {
612
			u.DOut("given provider %s was not in our network already.\n", peer.ID(prov.GetId()).Pretty())
Jeromy's avatar
Jeromy committed
613 614
			maddr, err := ma.NewMultiaddr(prov.GetAddr())
			if err != nil {
615
				u.PErr("error connecting to new peer: %s\n", err)
Jeromy's avatar
Jeromy committed
616 617 618 619
				continue
			}
			p, err = dht.network.GetConnection(peer.ID(prov.GetId()), maddr)
			if err != nil {
620
				u.PErr("error connecting to new peer: %s\n", err)
Jeromy's avatar
Jeromy committed
621 622 623
				continue
			}
		}
624
		dht.providers.AddProvider(key, p)
625
		provArr = append(provArr, p)
Jeromy's avatar
Jeromy committed
626
	}
627
	return provArr
Jeromy's avatar
Jeromy committed
628
}