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 }