From e6fc31bbc444d20e758c1ce8301ffe3d454370d3 Mon Sep 17 00:00:00 2001 From: Juan Batiz-Benet Date: Sun, 21 Dec 2014 05:25:18 -0800 Subject: [PATCH] Network: added notion of versions (h1) to h3 --- net/handshake/handshake1.go | 7 +++++++ net/handshake/pb/handshake.pb.go | 9 +++++++++ net/handshake/pb/handshake.proto | 3 +++ net/id.go | 17 ++++++++++++++--- net/id_test.go | 16 ++++++++++++++++ peer/peerstore.go | 22 ++++++++++++++++++++-- 6 files changed, 69 insertions(+), 5 deletions(-) diff --git a/net/handshake/handshake1.go b/net/handshake/handshake1.go index 237f61564..17ca44f09 100644 --- a/net/handshake/handshake1.go +++ b/net/handshake/handshake1.go @@ -54,6 +54,13 @@ func Handshake1Compatible(handshakeA, handshakeB *pb.Handshake1) error { // NewHandshake1 creates a new Handshake1 from the two strings func NewHandshake1(protoVer, agentVer string) *pb.Handshake1 { + if protoVer == "" { + protoVer = IpfsVersion.String() + } + if agentVer == "" { + agentVer = ClientVersion + } + return &pb.Handshake1{ ProtocolVersion: &protoVer, AgentVersion: &agentVer, diff --git a/net/handshake/pb/handshake.pb.go b/net/handshake/pb/handshake.pb.go index 0b00c3352..e4164788d 100644 --- a/net/handshake/pb/handshake.pb.go +++ b/net/handshake/pb/handshake.pb.go @@ -53,6 +53,8 @@ func (m *Handshake1) GetAgentVersion() string { // Handshake3 is delivered _after_ the secure channel is initialized type Handshake3 struct { + // can include all the values in handshake1, for protocol version, etc. + H1 *Handshake1 `protobuf:"bytes,5,opt,name=h1" json:"h1,omitempty"` // publicKey is this node's public key (which also gives its node.ID) // - may not need to be sent, as secure channel implies it has been sent. // - then again, if we change / disable secure channel, may still want it. @@ -72,6 +74,13 @@ func (m *Handshake3) Reset() { *m = Handshake3{} } func (m *Handshake3) String() string { return proto.CompactTextString(m) } func (*Handshake3) ProtoMessage() {} +func (m *Handshake3) GetH1() *Handshake1 { + if m != nil { + return m.H1 + } + return nil +} + func (m *Handshake3) GetPublicKey() []byte { if m != nil { return m.PublicKey diff --git a/net/handshake/pb/handshake.proto b/net/handshake/pb/handshake.proto index ee9e9b1db..8eb699559 100644 --- a/net/handshake/pb/handshake.proto +++ b/net/handshake/pb/handshake.proto @@ -17,6 +17,9 @@ message Handshake1 { // Handshake3 is delivered _after_ the secure channel is initialized message Handshake3 { + // can include all the values in handshake1, for protocol version, etc. + optional Handshake1 h1 = 5; + // publicKey is this node's public key (which also gives its node.ID) // - may not need to be sent, as secure channel implies it has been sent. // - then again, if we change / disable secure channel, may still want it. diff --git a/net/id.go b/net/id.go index a2b271602..40cedd034 100644 --- a/net/id.go +++ b/net/id.go @@ -1,6 +1,7 @@ package net import ( + handshake "github.com/jbenet/go-ipfs/net/handshake" pb "github.com/jbenet/go-ipfs/net/handshake/pb" ggio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/io" @@ -74,9 +75,13 @@ func (ids *IDService) populateMessage(mes *pb.Handshake3, c Conn) { for i, addr := range laddrs { mes.ListenAddrs[i] = addr.Bytes() } + + // set protocol versions + mes.H1 = handshake.NewHandshake1("", "") } func (ids *IDService) consumeMessage(mes *pb.Handshake3, c Conn) { + p := c.RemotePeer() // mes.Protocols // mes.ObservedAddr @@ -87,13 +92,19 @@ func (ids *IDService) consumeMessage(mes *pb.Handshake3, c Conn) { for _, addr := range laddrs { maddr, err := ma.NewMultiaddrBytes(addr) if err != nil { - log.Errorf("%s failed to parse multiaddr from %s %s", ProtocolIdentify, - c.RemotePeer(), c.RemoteMultiaddr()) + log.Errorf("%s failed to parse multiaddr from %s %s", ProtocolIdentify, p, + c.RemoteMultiaddr()) continue } lmaddrs = append(lmaddrs, maddr) } // update our peerstore with the addresses. - ids.Network.Peerstore().AddAddresses(c.RemotePeer(), lmaddrs) + ids.Network.Peerstore().AddAddresses(p, lmaddrs) + + // get protocol versions + pv := *mes.H1.ProtocolVersion + av := *mes.H1.AgentVersion + ids.Network.Peerstore().Put(p, "ProtocolVersion", pv) + ids.Network.Peerstore().Put(p, "AgentVersion", av) } diff --git a/net/id_test.go b/net/id_test.go index bf50b9ade..751e02c15 100644 --- a/net/id_test.go +++ b/net/id_test.go @@ -5,6 +5,7 @@ import ( "time" inet "github.com/jbenet/go-ipfs/net" + handshake "github.com/jbenet/go-ipfs/net/handshake" peer "github.com/jbenet/go-ipfs/peer" testutil "github.com/jbenet/go-ipfs/util/testutil" @@ -57,6 +58,17 @@ func TestIDService(t *testing.T) { } } + testHasProtocolVersions := func(n inet.Network, p peer.ID) { + v, err := n.Peerstore().Get(p, "ProtocolVersion") + if v.(string) != handshake.IpfsVersion.String() { + t.Fatal("protocol mismatch", err) + } + v, err = n.Peerstore().Get(p, "AgentVersion") + if v.(string) != handshake.ClientVersion { + t.Fatal("agent version mismatch", err) + } + } + n1p := n1.LocalPeer() n2p := n2.LocalPeer() @@ -79,4 +91,8 @@ func TestIDService(t *testing.T) { // what we should see now is that both peers know about each others listen addresses. testKnowsAddrs(n1, n2p, n2.Peerstore().Addresses(n2p)) // has them testKnowsAddrs(n2, n1p, n1.Peerstore().Addresses(n1p)) // has them + + // and the protocol versions. + testHasProtocolVersions(n1, n2p) + testHasProtocolVersions(n2, n1p) } diff --git a/peer/peerstore.go b/peer/peerstore.go index bc2182d18..c79bfed44 100644 --- a/peer/peerstore.go +++ b/peer/peerstore.go @@ -6,6 +6,8 @@ import ( ic "github.com/jbenet/go-ipfs/crypto" + ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore" + dssync "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync" ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" ) @@ -23,6 +25,12 @@ type Peerstore interface { // This is a small slice of the information Peerstore has on // that peer, useful to other services. PeerInfo(ID) PeerInfo + + // Get/Put is a simple registry for other peer-related key/value pairs. + // if we find something we use often, it should become its own set of + // methods. this is a last resort. + Get(id ID, key string) (interface{}, error) + Put(id ID, key string, val interface{}) error } // AddressBook tracks the addresses of Peers @@ -177,7 +185,7 @@ type peerstore struct { metrics // store other data, like versions - data map[ID]map[string]interface{} + ds ds.ThreadSafeDatastore } // NewPeerstore creates a threadsafe collection of peers. @@ -186,10 +194,20 @@ func NewPeerstore() Peerstore { keybook: *newKeybook(), addressbook: *newAddressbook(), metrics: *(NewMetrics()).(*metrics), - data: map[ID]map[string]interface{}{}, + ds: dssync.MutexWrap(ds.NewMapDatastore()), } } +func (ps *peerstore) Put(p ID, key string, val interface{}) error { + dsk := ds.NewKey(string(p) + "/" + key) + return ps.ds.Put(dsk, val) +} + +func (ps *peerstore) Get(p ID, key string) (interface{}, error) { + dsk := ds.NewKey(string(p) + "/" + key) + return ps.ds.Get(dsk) +} + func (ps *peerstore) Peers() []ID { set := map[ID]struct{}{} for _, p := range ps.keybook.Peers() {