server.go 6.36 KB
Newer Older
1
package supernode
2 3

import (
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
4
	"errors"
5 6
	"fmt"

7 8 9 10 11 12 13 14
	proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
	datastore "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
	peer "github.com/ipfs/go-ipfs/p2p/peer"
	dhtpb "github.com/ipfs/go-ipfs/routing/dht/pb"
	record "github.com/ipfs/go-ipfs/routing/record"
	proxy "github.com/ipfs/go-ipfs/routing/supernode/proxy"
	util "github.com/ipfs/go-ipfs/util"
15 16 17 18 19
)

// Server handles routing queries using a database backend
type Server struct {
	local           peer.ID
20
	routingBackend  datastore.ThreadSafeDatastore
21 22 23 24
	peerstore       peer.Peerstore
	*proxy.Loopback // so server can be injected into client
}

25
// NewServer creates a new Supernode routing Server
26 27
func NewServer(ds datastore.ThreadSafeDatastore, ps peer.Peerstore, local peer.ID) (*Server, error) {
	s := &Server{local, ds, ps, nil}
28 29 30 31 32 33 34
	s.Loopback = &proxy.Loopback{
		Handler: s,
		Local:   local,
	}
	return s, nil
}

35 36 37 38
func (_ *Server) Bootstrap(ctx context.Context) error {
	return nil
}

39 40 41 42 43 44 45 46 47 48
// HandleLocalRequest implements the proxy.RequestHandler interface. This is
// where requests are received from the outside world.
func (s *Server) HandleRequest(ctx context.Context, p peer.ID, req *dhtpb.Message) *dhtpb.Message {
	_, response := s.handleMessage(ctx, p, req) // ignore response peer. it's local.
	return response
}

func (s *Server) handleMessage(
	ctx context.Context, p peer.ID, req *dhtpb.Message) (peer.ID, *dhtpb.Message) {

49
	defer log.EventBegin(ctx, "routingMessageReceived", req, p).Done()
Brian Tiger Chow's avatar
Brian Tiger Chow committed
50

51 52 53 54
	var response = dhtpb.NewMessage(req.GetType(), req.GetKey(), req.GetClusterLevel())
	switch req.GetType() {

	case dhtpb.Message_GET_VALUE:
55
		rawRecord, err := getRoutingRecord(s.routingBackend, util.Key(req.GetKey()))
56 57 58
		if err != nil {
			return "", nil
		}
59
		response.Record = rawRecord
60 61 62
		return p, response

	case dhtpb.Message_PUT_VALUE:
Brian Tiger Chow's avatar
Brian Tiger Chow committed
63 64 65 66 67 68
		// FIXME: verify complains that the peer's ID is not present in the
		// peerstore. Mocknet problem?
		// if err := verify(s.peerstore, req.GetRecord()); err != nil {
		// 	log.Event(ctx, "validationFailed", req, p)
		// 	return "", nil
		// }
69
		putRoutingRecord(s.routingBackend, util.Key(req.GetKey()), req.GetRecord())
70
		return p, req
71 72 73

	case dhtpb.Message_FIND_NODE:
		p := s.peerstore.PeerInfo(peer.ID(req.GetKey()))
74 75 76 77 78 79 80
		pri := []dhtpb.PeerRoutingInfo{
			dhtpb.PeerRoutingInfo{
				PeerInfo: p,
				// Connectedness: TODO
			},
		}
		response.CloserPeers = dhtpb.PeerRoutingInfosToPBPeers(pri)
81 82 83
		return p.ID, response

	case dhtpb.Message_ADD_PROVIDER:
84 85 86 87 88 89 90 91 92 93 94
		for _, provider := range req.GetProviderPeers() {
			providerID := peer.ID(provider.GetId())
			if providerID == p {
				store := []*dhtpb.Message_Peer{provider}
				storeProvidersToPeerstore(s.peerstore, p, store)
				if err := putRoutingProviders(s.routingBackend, util.Key(req.GetKey()), store); err != nil {
					return "", nil
				}
			} else {
				log.Event(ctx, "addProviderBadRequest", p, req)
			}
95 96 97 98
		}
		return "", nil

	case dhtpb.Message_GET_PROVIDERS:
Brian Tiger Chow's avatar
Brian Tiger Chow committed
99
		providers, err := getRoutingProviders(s.routingBackend, util.Key(req.GetKey()))
100 101
		if err != nil {
			return "", nil
102
		}
103
		response.ProviderPeers = providers
104 105 106 107 108 109 110 111 112 113 114
		return p, response

	case dhtpb.Message_PING:
		return p, req
	default:
	}
	return "", nil
}

var _ proxy.RequestHandler = &Server{}
var _ proxy.Proxy = &Server{}
115 116 117 118 119

func getRoutingRecord(ds datastore.Datastore, k util.Key) (*dhtpb.Record, error) {
	dskey := k.DsKey()
	val, err := ds.Get(dskey)
	if err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
120
		return nil, err
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
	}
	recordBytes, ok := val.([]byte)
	if !ok {
		return nil, fmt.Errorf("datastore had non byte-slice value for %v", dskey)
	}
	var record dhtpb.Record
	if err := proto.Unmarshal(recordBytes, &record); err != nil {
		return nil, errors.New("failed to unmarshal dht record from datastore")
	}
	return &record, nil
}

func putRoutingRecord(ds datastore.Datastore, k util.Key, value *dhtpb.Record) error {
	data, err := proto.Marshal(value)
	if err != nil {
		return err
	}
	dskey := k.DsKey()
	// TODO namespace
	if err := ds.Put(dskey, data); err != nil {
		return err
	}
	return nil
}

146
func putRoutingProviders(ds datastore.Datastore, k util.Key, newRecords []*dhtpb.Message_Peer) error {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
147
	log.Event(context.Background(), "putRoutingProviders", &k)
148
	oldRecords, err := getRoutingProviders(ds, k)
149 150
	if err != nil {
		return err
151
	}
152 153 154 155 156 157 158
	mergedRecords := make(map[string]*dhtpb.Message_Peer)
	for _, provider := range oldRecords {
		mergedRecords[provider.GetId()] = provider // add original records
	}
	for _, provider := range newRecords {
		mergedRecords[provider.GetId()] = provider // overwrite old record if new exists
	}
159
	var protomsg dhtpb.Message
160 161 162 163
	protomsg.ProviderPeers = make([]*dhtpb.Message_Peer, 0, len(mergedRecords))
	for _, provider := range mergedRecords {
		protomsg.ProviderPeers = append(protomsg.ProviderPeers, provider)
	}
164 165 166 167
	data, err := proto.Marshal(&protomsg)
	if err != nil {
		return err
	}
168
	return ds.Put(providerKey(k), data)
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
}

func storeProvidersToPeerstore(ps peer.Peerstore, p peer.ID, providers []*dhtpb.Message_Peer) {
	for _, provider := range providers {
		providerID := peer.ID(provider.GetId())
		if providerID != p {
			log.Errorf("provider message came from third-party %s", p)
			continue
		}
		for _, maddr := range provider.Addresses() {
			// as a router, we want to store addresses for peers who have provided
			ps.AddAddr(p, maddr, peer.AddressTTL)
		}
	}
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
185
func getRoutingProviders(ds datastore.Datastore, k util.Key) ([]*dhtpb.Message_Peer, error) {
186 187
	e := log.EventBegin(context.Background(), "getProviders", &k)
	defer e.Done()
188
	var providers []*dhtpb.Message_Peer
189
	if v, err := ds.Get(providerKey(k)); err == nil {
190 191 192 193 194 195 196 197 198 199
		if data, ok := v.([]byte); ok {
			var msg dhtpb.Message
			if err := proto.Unmarshal(data, &msg); err != nil {
				return nil, err
			}
			providers = append(providers, msg.GetProviderPeers()...)
		}
	}
	return providers, nil
}
200 201 202 203

func providerKey(k util.Key) datastore.Key {
	return datastore.KeyWithNamespaces([]string{"routing", "providers", k.String()})
}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
204 205 206

func verify(ps peer.Peerstore, r *dhtpb.Record) error {
	v := make(record.Validator)
207
	v["pk"] = record.PublicKeyValidator
Brian Tiger Chow's avatar
Brian Tiger Chow committed
208 209 210 211 212
	p := peer.ID(r.GetAuthor())
	pk := ps.PubKey(p)
	if pk == nil {
		return fmt.Errorf("do not have public key for %s", p)
	}
Jeromy's avatar
Jeromy committed
213 214 215 216
	if err := record.CheckRecordSig(r, pk); err != nil {
		return err
	}
	if err := v.VerifyRecord(r); err != nil {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
217 218 219 220
		return err
	}
	return nil
}