github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/routing/dht/dht.go (about)

     1  // Package dht implements a distributed hash table that satisfies the ipfs routing
     2  // interface. This DHT is modeled after kademlia with Coral and S/Kademlia modifications.
     3  package dht
     4  
     5  import (
     6  	"bytes"
     7  	"errors"
     8  	"fmt"
     9  	"sync"
    10  	"time"
    11  
    12  	key "github.com/ipfs/go-ipfs/blocks/key"
    13  	ci "github.com/ipfs/go-ipfs/p2p/crypto"
    14  	host "github.com/ipfs/go-ipfs/p2p/host"
    15  	peer "github.com/ipfs/go-ipfs/p2p/peer"
    16  	protocol "github.com/ipfs/go-ipfs/p2p/protocol"
    17  	routing "github.com/ipfs/go-ipfs/routing"
    18  	pb "github.com/ipfs/go-ipfs/routing/dht/pb"
    19  	kb "github.com/ipfs/go-ipfs/routing/kbucket"
    20  	record "github.com/ipfs/go-ipfs/routing/record"
    21  	"github.com/ipfs/go-ipfs/thirdparty/eventlog"
    22  	u "github.com/ipfs/go-ipfs/util"
    23  
    24  	proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
    25  	ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
    26  	goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
    27  	goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
    28  	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
    29  )
    30  
    31  var log = eventlog.Logger("dht")
    32  
    33  var ProtocolDHT protocol.ID = "/ipfs/dht"
    34  
    35  // NumBootstrapQueries defines the number of random dht queries to do to
    36  // collect members of the routing table.
    37  const NumBootstrapQueries = 5
    38  
    39  // TODO. SEE https://github.com/jbenet/node-ipfs/blob/master/submodules/ipfs-dht/index.js
    40  
    41  // IpfsDHT is an implementation of Kademlia with Coral and S/Kademlia modifications.
    42  // It is used to implement the base IpfsRouting module.
    43  type IpfsDHT struct {
    44  	host      host.Host      // the network services we need
    45  	self      peer.ID        // Local peer (yourself)
    46  	peerstore peer.Peerstore // Peer Registry
    47  
    48  	datastore ds.ThreadSafeDatastore // Local data
    49  
    50  	routingTable *kb.RoutingTable // Array of routing tables for differently distanced nodes
    51  	providers    *ProviderManager
    52  
    53  	birth    time.Time  // When this peer started up
    54  	diaglock sync.Mutex // lock to make diagnostics work better
    55  
    56  	Validator record.Validator // record validator funcs
    57  
    58  	ctx  context.Context
    59  	proc goprocess.Process
    60  }
    61  
    62  // NewDHT creates a new DHT object with the given peer as the 'local' host
    63  func NewDHT(ctx context.Context, h host.Host, dstore ds.ThreadSafeDatastore) *IpfsDHT {
    64  	dht := new(IpfsDHT)
    65  	dht.datastore = dstore
    66  	dht.self = h.ID()
    67  	dht.peerstore = h.Peerstore()
    68  	dht.host = h
    69  
    70  	// register for network notifs.
    71  	dht.host.Network().Notify((*netNotifiee)(dht))
    72  
    73  	dht.proc = goprocess.WithTeardown(func() error {
    74  		// remove ourselves from network notifs.
    75  		dht.host.Network().StopNotify((*netNotifiee)(dht))
    76  		return nil
    77  	})
    78  
    79  	dht.ctx = ctx
    80  
    81  	h.SetStreamHandler(ProtocolDHT, dht.handleNewStream)
    82  	dht.providers = NewProviderManager(dht.ctx, dht.self)
    83  	dht.proc.AddChild(dht.providers.proc)
    84  	goprocessctx.CloseAfterContext(dht.proc, ctx)
    85  
    86  	dht.routingTable = kb.NewRoutingTable(20, kb.ConvertPeerID(dht.self), time.Minute, dht.peerstore)
    87  	dht.birth = time.Now()
    88  
    89  	dht.Validator = make(record.Validator)
    90  	dht.Validator["pk"] = record.PublicKeyValidator
    91  
    92  	return dht
    93  }
    94  
    95  // LocalPeer returns the peer.Peer of the dht.
    96  func (dht *IpfsDHT) LocalPeer() peer.ID {
    97  	return dht.self
    98  }
    99  
   100  // log returns the dht's logger
   101  func (dht *IpfsDHT) log() eventlog.EventLogger {
   102  	return log // TODO rm
   103  }
   104  
   105  // putValueToPeer stores the given key/value pair at the peer 'p'
   106  func (dht *IpfsDHT) putValueToPeer(ctx context.Context, p peer.ID,
   107  	key key.Key, rec *pb.Record) error {
   108  
   109  	pmes := pb.NewMessage(pb.Message_PUT_VALUE, string(key), 0)
   110  	pmes.Record = rec
   111  	rpmes, err := dht.sendRequest(ctx, p, pmes)
   112  	if err != nil {
   113  		return err
   114  	}
   115  
   116  	if !bytes.Equal(rpmes.GetRecord().Value, pmes.GetRecord().Value) {
   117  		return errors.New("value not put correctly")
   118  	}
   119  	return nil
   120  }
   121  
   122  // putProvider sends a message to peer 'p' saying that the local node
   123  // can provide the value of 'key'
   124  func (dht *IpfsDHT) putProvider(ctx context.Context, p peer.ID, skey string) error {
   125  
   126  	// add self as the provider
   127  	pi := peer.PeerInfo{
   128  		ID:    dht.self,
   129  		Addrs: dht.host.Addrs(),
   130  	}
   131  
   132  	// // only share WAN-friendly addresses ??
   133  	// pi.Addrs = addrutil.WANShareableAddrs(pi.Addrs)
   134  	if len(pi.Addrs) < 1 {
   135  		// log.Infof("%s putProvider: %s for %s error: no wan-friendly addresses", dht.self, p, key.Key(key), pi.Addrs)
   136  		return fmt.Errorf("no known addresses for self. cannot put provider.")
   137  	}
   138  
   139  	pmes := pb.NewMessage(pb.Message_ADD_PROVIDER, skey, 0)
   140  	pmes.ProviderPeers = pb.RawPeerInfosToPBPeers([]peer.PeerInfo{pi})
   141  	err := dht.sendMessage(ctx, p, pmes)
   142  	if err != nil {
   143  		return err
   144  	}
   145  
   146  	log.Debugf("%s putProvider: %s for %s (%s)", dht.self, p, key.Key(skey), pi.Addrs)
   147  	return nil
   148  }
   149  
   150  // getValueOrPeers queries a particular peer p for the value for
   151  // key. It returns either the value or a list of closer peers.
   152  // NOTE: it will update the dht's peerstore with any new addresses
   153  // it finds for the given peer.
   154  func (dht *IpfsDHT) getValueOrPeers(ctx context.Context, p peer.ID,
   155  	key key.Key) ([]byte, []peer.PeerInfo, error) {
   156  
   157  	pmes, err := dht.getValueSingle(ctx, p, key)
   158  	if err != nil {
   159  		return nil, nil, err
   160  	}
   161  
   162  	if record := pmes.GetRecord(); record != nil {
   163  		// Success! We were given the value
   164  		log.Debug("getValueOrPeers: got value")
   165  
   166  		// make sure record is valid.
   167  		err = dht.verifyRecordOnline(ctx, record)
   168  		if err != nil {
   169  			log.Info("Received invalid record! (discarded)")
   170  			return nil, nil, err
   171  		}
   172  		return record.GetValue(), nil, nil
   173  	}
   174  
   175  	// Perhaps we were given closer peers
   176  	peers := pb.PBPeersToPeerInfos(pmes.GetCloserPeers())
   177  	if len(peers) > 0 {
   178  		log.Debug("getValueOrPeers: peers")
   179  		return nil, peers, nil
   180  	}
   181  
   182  	log.Warning("getValueOrPeers: routing.ErrNotFound")
   183  	return nil, nil, routing.ErrNotFound
   184  }
   185  
   186  // getValueSingle simply performs the get value RPC with the given parameters
   187  func (dht *IpfsDHT) getValueSingle(ctx context.Context, p peer.ID,
   188  	key key.Key) (*pb.Message, error) {
   189  	defer log.EventBegin(ctx, "getValueSingle", p, &key).Done()
   190  
   191  	pmes := pb.NewMessage(pb.Message_GET_VALUE, string(key), 0)
   192  	return dht.sendRequest(ctx, p, pmes)
   193  }
   194  
   195  // getLocal attempts to retrieve the value from the datastore
   196  func (dht *IpfsDHT) getLocal(key key.Key) ([]byte, error) {
   197  
   198  	log.Debug("getLocal %s", key)
   199  	v, err := dht.datastore.Get(key.DsKey())
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  	log.Debug("found in db")
   204  
   205  	byt, ok := v.([]byte)
   206  	if !ok {
   207  		return nil, errors.New("value stored in datastore not []byte")
   208  	}
   209  	rec := new(pb.Record)
   210  	err = proto.Unmarshal(byt, rec)
   211  	if err != nil {
   212  		return nil, err
   213  	}
   214  
   215  	// TODO: 'if paranoid'
   216  	if u.Debug {
   217  		err = dht.verifyRecordLocally(rec)
   218  		if err != nil {
   219  			log.Debugf("local record verify failed: %s (discarded)", err)
   220  			return nil, err
   221  		}
   222  	}
   223  
   224  	return rec.GetValue(), nil
   225  }
   226  
   227  // getOwnPrivateKey attempts to load the local peers private
   228  // key from the peerstore.
   229  func (dht *IpfsDHT) getOwnPrivateKey() (ci.PrivKey, error) {
   230  	sk := dht.peerstore.PrivKey(dht.self)
   231  	if sk == nil {
   232  		log.Warningf("%s dht cannot get own private key!", dht.self)
   233  		return nil, fmt.Errorf("cannot get private key to sign record!")
   234  	}
   235  	return sk, nil
   236  }
   237  
   238  // putLocal stores the key value pair in the datastore
   239  func (dht *IpfsDHT) putLocal(key key.Key, rec *pb.Record) error {
   240  	data, err := proto.Marshal(rec)
   241  	if err != nil {
   242  		return err
   243  	}
   244  
   245  	return dht.datastore.Put(key.DsKey(), data)
   246  }
   247  
   248  // Update signals the routingTable to Update its last-seen status
   249  // on the given peer.
   250  func (dht *IpfsDHT) Update(ctx context.Context, p peer.ID) {
   251  	log.Event(ctx, "updatePeer", p)
   252  	dht.routingTable.Update(p)
   253  }
   254  
   255  // FindLocal looks for a peer with a given ID connected to this dht and returns the peer and the table it was found in.
   256  func (dht *IpfsDHT) FindLocal(id peer.ID) peer.PeerInfo {
   257  	p := dht.routingTable.Find(id)
   258  	if p != "" {
   259  		return dht.peerstore.PeerInfo(p)
   260  	}
   261  	return peer.PeerInfo{}
   262  }
   263  
   264  // findPeerSingle asks peer 'p' if they know where the peer with id 'id' is
   265  func (dht *IpfsDHT) findPeerSingle(ctx context.Context, p peer.ID, id peer.ID) (*pb.Message, error) {
   266  	defer log.EventBegin(ctx, "findPeerSingle", p, id).Done()
   267  
   268  	pmes := pb.NewMessage(pb.Message_FIND_NODE, string(id), 0)
   269  	return dht.sendRequest(ctx, p, pmes)
   270  }
   271  
   272  func (dht *IpfsDHT) findProvidersSingle(ctx context.Context, p peer.ID, key key.Key) (*pb.Message, error) {
   273  	defer log.EventBegin(ctx, "findProvidersSingle", p, &key).Done()
   274  
   275  	pmes := pb.NewMessage(pb.Message_GET_PROVIDERS, string(key), 0)
   276  	return dht.sendRequest(ctx, p, pmes)
   277  }
   278  
   279  // nearestPeersToQuery returns the routing tables closest peers.
   280  func (dht *IpfsDHT) nearestPeersToQuery(pmes *pb.Message, count int) []peer.ID {
   281  	key := key.Key(pmes.GetKey())
   282  	closer := dht.routingTable.NearestPeers(kb.ConvertKey(key), count)
   283  	return closer
   284  }
   285  
   286  // betterPeerToQuery returns nearestPeersToQuery, but iff closer than self.
   287  func (dht *IpfsDHT) betterPeersToQuery(pmes *pb.Message, p peer.ID, count int) []peer.ID {
   288  	closer := dht.nearestPeersToQuery(pmes, count)
   289  
   290  	// no node? nil
   291  	if closer == nil {
   292  		return nil
   293  	}
   294  
   295  	// == to self? thats bad
   296  	for _, p := range closer {
   297  		if p == dht.self {
   298  			log.Debug("Attempted to return self! this shouldnt happen...")
   299  			return nil
   300  		}
   301  	}
   302  
   303  	var filtered []peer.ID
   304  	for _, clp := range closer {
   305  		// Dont send a peer back themselves
   306  		if p == clp {
   307  			continue
   308  		}
   309  
   310  		// must all be closer than self
   311  		key := key.Key(pmes.GetKey())
   312  		if !kb.Closer(dht.self, clp, key) {
   313  			filtered = append(filtered, clp)
   314  		}
   315  	}
   316  
   317  	// ok seems like closer nodes
   318  	return filtered
   319  }
   320  
   321  // Context return dht's context
   322  func (dht *IpfsDHT) Context() context.Context {
   323  	return dht.ctx
   324  }
   325  
   326  // Process return dht's process
   327  func (dht *IpfsDHT) Process() goprocess.Process {
   328  	return dht.proc
   329  }
   330  
   331  // Close calls Process Close
   332  func (dht *IpfsDHT) Close() error {
   333  	return dht.proc.Close()
   334  }