예제 #1
0
파일: routing.go 프로젝트: mappum/go-ipfs
func (dht *IpfsDHT) findPeerMultiple(id peer.ID, timeout time.Duration) (*peer.Peer, error) {
	// Check if were already connected to them
	p, _ := dht.Find(id)
	if p != nil {
		return p, nil
	}

	routeLevel := 0
	peers := dht.routingTables[routeLevel].NearestPeers(kb.ConvertPeerID(id), AlphaValue)
	if len(peers) == 0 {
		return nil, kb.ErrLookupFailure
	}

	found := make(chan *peer.Peer)
	after := time.After(timeout)

	for _, p := range peers {
		go func(p *peer.Peer) {
			pmes, err := dht.findPeerSingle(p, id, timeout, routeLevel)
			if err != nil {
				u.DErr("getPeer error: %v\n", err)
				return
			}
			plist := pmes.GetPeers()
			if len(plist) == 0 {
				routeLevel++
			}
			for _, fp := range plist {
				nxtp, err := dht.peerFromInfo(fp)
				if err != nil {
					u.DErr("findPeer error: %v\n", err)
					continue
				}

				if nxtp.ID.Equal(dht.self.ID) {
					found <- nxtp
					return
				}
			}
		}(p)
	}

	select {
	case p := <-found:
		return p, nil
	case <-after:
		return nil, u.ErrTimeout
	}
}
예제 #2
0
파일: dht.go 프로젝트: mappum/go-ipfs
// 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())
			if err != nil {
				u.PErr("getValue error: %s\n", err)
				continue
			}

			p, err = dht.network.GetConnection(peer.ID(pinfo.GetId()), maddr)
			if err != nil {
				u.PErr("getValue error: %s\n", err)
				continue
			}
		}
		pmes, err := dht.getValueSingle(p, key, timeout, level)
		if err != nil {
			u.DErr("getFromPeers error: %s\n", err)
			continue
		}
		dht.providers.AddProvider(key, p)

		// Make sure it was a successful get
		if pmes.GetSuccess() && pmes.Value != nil {
			return pmes.GetValue(), nil
		}
	}
	return nil, u.ErrNotFound
}
예제 #3
0
파일: routing.go 프로젝트: mappum/go-ipfs
// GetValue searches for the value corresponding to given Key.
// If the search does not succeed, a multiaddr string of a closer peer is
// returned along with util.ErrSearchIncomplete
func (dht *IpfsDHT) GetValue(key u.Key, timeout time.Duration) ([]byte, error) {
	ll := startNewRPC("GET")
	defer func() {
		ll.EndLog()
		ll.Print()
	}()

	// If we have it local, dont bother doing an RPC!
	// NOTE: this might not be what we want to do...
	val, err := dht.getLocal(key)
	if err == nil {
		ll.Success = true
		u.DOut("Found local, returning.\n")
		return val, nil
	}

	routeLevel := 0
	closest := dht.routingTables[routeLevel].NearestPeers(kb.ConvertKey(key), PoolSize)
	if closest == nil || len(closest) == 0 {
		return nil, kb.ErrLookupFailure
	}

	valChan := make(chan []byte)
	npeerChan := make(chan *peer.Peer, 30)
	procPeer := make(chan *peer.Peer, 30)
	errChan := make(chan error)
	after := time.After(timeout)
	pset := newPeerSet()

	for _, p := range closest {
		pset.Add(p)
		npeerChan <- p
	}

	c := counter{}

	count := 0
	go func() {
		defer close(procPeer)
		for {
			select {
			case p, ok := <-npeerChan:
				if !ok {
					return
				}
				count++
				if count >= KValue {
					errChan <- u.ErrNotFound
					return
				}
				c.Increment()

				procPeer <- p
			default:
				if c.Size() <= 0 {
					select {
					case errChan <- u.ErrNotFound:
					default:
					}
					return
				}
			}
		}
	}()

	process := func() {
		defer c.Decrement()
		for p := range procPeer {
			if p == nil {
				return
			}
			val, peers, err := dht.getValueOrPeers(p, key, timeout/4, routeLevel)
			if err != nil {
				u.DErr("%v\n", err.Error())
				continue
			}
			if val != nil {
				select {
				case valChan <- val:
				default:
					u.DOut("Wasnt the first to return the value!")
				}
				return
			}

			for _, np := range peers {
				// TODO: filter out peers that arent closer
				if !pset.Contains(np) && pset.Size() < KValue {
					pset.Add(np) //This is racey... make a single function to do operation
					npeerChan <- np
				}
			}
			c.Decrement()
		}
	}

	for i := 0; i < AlphaValue; i++ {
		go process()
	}

	select {
	case val := <-valChan:
		return val, nil
	case err := <-errChan:
		return nil, err
	case <-after:
		return nil, u.ErrTimeout
	}
}