github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/routing/supernode/server.go (about) 1 package supernode 2 3 import ( 4 "errors" 5 "fmt" 6 7 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" 8 datastore "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore" 9 context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" 10 11 key "github.com/ipfs/go-ipfs/blocks/key" 12 peer "github.com/ipfs/go-ipfs/p2p/peer" 13 dhtpb "github.com/ipfs/go-ipfs/routing/dht/pb" 14 record "github.com/ipfs/go-ipfs/routing/record" 15 proxy "github.com/ipfs/go-ipfs/routing/supernode/proxy" 16 ) 17 18 // Server handles routing queries using a database backend 19 type Server struct { 20 local peer.ID 21 routingBackend datastore.ThreadSafeDatastore 22 peerstore peer.Peerstore 23 *proxy.Loopback // so server can be injected into client 24 } 25 26 // NewServer creates a new Supernode routing Server 27 func NewServer(ds datastore.ThreadSafeDatastore, ps peer.Peerstore, local peer.ID) (*Server, error) { 28 s := &Server{local, ds, ps, nil} 29 s.Loopback = &proxy.Loopback{ 30 Handler: s, 31 Local: local, 32 } 33 return s, nil 34 } 35 36 func (_ *Server) Bootstrap(ctx context.Context) error { 37 return nil 38 } 39 40 // HandleLocalRequest implements the proxy.RequestHandler interface. This is 41 // where requests are received from the outside world. 42 func (s *Server) HandleRequest(ctx context.Context, p peer.ID, req *dhtpb.Message) *dhtpb.Message { 43 _, response := s.handleMessage(ctx, p, req) // ignore response peer. it's local. 44 return response 45 } 46 47 func (s *Server) handleMessage( 48 ctx context.Context, p peer.ID, req *dhtpb.Message) (peer.ID, *dhtpb.Message) { 49 50 defer log.EventBegin(ctx, "routingMessageReceived", req, p).Done() 51 52 var response = dhtpb.NewMessage(req.GetType(), req.GetKey(), req.GetClusterLevel()) 53 switch req.GetType() { 54 55 case dhtpb.Message_GET_VALUE: 56 rawRecord, err := getRoutingRecord(s.routingBackend, key.Key(req.GetKey())) 57 if err != nil { 58 return "", nil 59 } 60 response.Record = rawRecord 61 return p, response 62 63 case dhtpb.Message_PUT_VALUE: 64 // FIXME: verify complains that the peer's ID is not present in the 65 // peerstore. Mocknet problem? 66 // if err := verify(s.peerstore, req.GetRecord()); err != nil { 67 // log.Event(ctx, "validationFailed", req, p) 68 // return "", nil 69 // } 70 putRoutingRecord(s.routingBackend, key.Key(req.GetKey()), req.GetRecord()) 71 return p, req 72 73 case dhtpb.Message_FIND_NODE: 74 p := s.peerstore.PeerInfo(peer.ID(req.GetKey())) 75 pri := []dhtpb.PeerRoutingInfo{ 76 { 77 PeerInfo: p, 78 // Connectedness: TODO 79 }, 80 } 81 response.CloserPeers = dhtpb.PeerRoutingInfosToPBPeers(pri) 82 return p.ID, response 83 84 case dhtpb.Message_ADD_PROVIDER: 85 for _, provider := range req.GetProviderPeers() { 86 providerID := peer.ID(provider.GetId()) 87 if providerID == p { 88 store := []*dhtpb.Message_Peer{provider} 89 storeProvidersToPeerstore(s.peerstore, p, store) 90 if err := putRoutingProviders(s.routingBackend, key.Key(req.GetKey()), store); err != nil { 91 return "", nil 92 } 93 } else { 94 log.Event(ctx, "addProviderBadRequest", p, req) 95 } 96 } 97 return "", nil 98 99 case dhtpb.Message_GET_PROVIDERS: 100 providers, err := getRoutingProviders(s.routingBackend, key.Key(req.GetKey())) 101 if err != nil { 102 return "", nil 103 } 104 response.ProviderPeers = providers 105 return p, response 106 107 case dhtpb.Message_PING: 108 return p, req 109 default: 110 } 111 return "", nil 112 } 113 114 var _ proxy.RequestHandler = &Server{} 115 var _ proxy.Proxy = &Server{} 116 117 func getRoutingRecord(ds datastore.Datastore, k key.Key) (*dhtpb.Record, error) { 118 dskey := k.DsKey() 119 val, err := ds.Get(dskey) 120 if err != nil { 121 return nil, err 122 } 123 recordBytes, ok := val.([]byte) 124 if !ok { 125 return nil, fmt.Errorf("datastore had non byte-slice value for %v", dskey) 126 } 127 var record dhtpb.Record 128 if err := proto.Unmarshal(recordBytes, &record); err != nil { 129 return nil, errors.New("failed to unmarshal dht record from datastore") 130 } 131 return &record, nil 132 } 133 134 func putRoutingRecord(ds datastore.Datastore, k key.Key, value *dhtpb.Record) error { 135 data, err := proto.Marshal(value) 136 if err != nil { 137 return err 138 } 139 dskey := k.DsKey() 140 // TODO namespace 141 if err := ds.Put(dskey, data); err != nil { 142 return err 143 } 144 return nil 145 } 146 147 func putRoutingProviders(ds datastore.Datastore, k key.Key, newRecords []*dhtpb.Message_Peer) error { 148 log.Event(context.Background(), "putRoutingProviders", &k) 149 oldRecords, err := getRoutingProviders(ds, k) 150 if err != nil { 151 return err 152 } 153 mergedRecords := make(map[string]*dhtpb.Message_Peer) 154 for _, provider := range oldRecords { 155 mergedRecords[provider.GetId()] = provider // add original records 156 } 157 for _, provider := range newRecords { 158 mergedRecords[provider.GetId()] = provider // overwrite old record if new exists 159 } 160 var protomsg dhtpb.Message 161 protomsg.ProviderPeers = make([]*dhtpb.Message_Peer, 0, len(mergedRecords)) 162 for _, provider := range mergedRecords { 163 protomsg.ProviderPeers = append(protomsg.ProviderPeers, provider) 164 } 165 data, err := proto.Marshal(&protomsg) 166 if err != nil { 167 return err 168 } 169 return ds.Put(providerKey(k), data) 170 } 171 172 func storeProvidersToPeerstore(ps peer.Peerstore, p peer.ID, providers []*dhtpb.Message_Peer) { 173 for _, provider := range providers { 174 providerID := peer.ID(provider.GetId()) 175 if providerID != p { 176 log.Errorf("provider message came from third-party %s", p) 177 continue 178 } 179 for _, maddr := range provider.Addresses() { 180 // as a router, we want to store addresses for peers who have provided 181 ps.AddAddr(p, maddr, peer.AddressTTL) 182 } 183 } 184 } 185 186 func getRoutingProviders(ds datastore.Datastore, k key.Key) ([]*dhtpb.Message_Peer, error) { 187 e := log.EventBegin(context.Background(), "getProviders", &k) 188 defer e.Done() 189 var providers []*dhtpb.Message_Peer 190 if v, err := ds.Get(providerKey(k)); err == nil { 191 if data, ok := v.([]byte); ok { 192 var msg dhtpb.Message 193 if err := proto.Unmarshal(data, &msg); err != nil { 194 return nil, err 195 } 196 providers = append(providers, msg.GetProviderPeers()...) 197 } 198 } 199 return providers, nil 200 } 201 202 func providerKey(k key.Key) datastore.Key { 203 return datastore.KeyWithNamespaces([]string{"routing", "providers", k.String()}) 204 } 205 206 func verify(ps peer.Peerstore, r *dhtpb.Record) error { 207 v := make(record.Validator) 208 v["pk"] = record.PublicKeyValidator 209 p := peer.ID(r.GetAuthor()) 210 pk := ps.PubKey(p) 211 if pk == nil { 212 return fmt.Errorf("do not have public key for %s", p) 213 } 214 if err := record.CheckRecordSig(r, pk); err != nil { 215 return err 216 } 217 if err := v.VerifyRecord(r); err != nil { 218 return err 219 } 220 return nil 221 }