@cryptotaxi247 / kubo / commits / c84a714b1

peer change: peer.Peer -> peer.ID

this is a major refactor of the entire codebase it changes the monolithic peer.Peer into using a peer.ID and a peer.Peerstore. Other changes: - removed handshake3. - testutil vastly simplified peer - secio bugfix + debugging logs - testutil: RandKeyPair - backpressure bugfix: w.o.w. - peer: added hex enc/dec - peer: added a PeerInfo struct PeerInfo is a small struct used to pass around a peer with a set of addresses and keys. This is not meant to be a complete view of the system, but rather to model updates to the peerstore. It is used by things like the routing system. - updated peer/queue + peerset - latency metrics - testutil: use crand for PeerID gen RandPeerID generates random "valid" peer IDs. it does not NEED to generate keys because it is as if we lost the key right away. fine to read some randomness and hash it. to generate proper keys and an ID, use: sk, pk, _ := testutil.RandKeyPair() id, _ := peer.IDFromPublicKey(pk) Also added RandPeerIDFatal helper - removed old spipe - updated seccat - core: cleanup initIdentity - removed old getFromPeerList

Juan Batiz-Benet committed Dec 19, 2014 at 12:19 UTC c84a714b167609c54387695f5bce4c5d321601bf
106 files changed +2774 -3104
cmd/ipfs/init.go
+1 -1
@@ -266,7 +266,7 @@ func identityConfig(nbits int) (config.Identity, error) {
266 }
267 ident.PrivKey = base64.StdEncoding.EncodeToString(skbytes)
268
269 - id, err := peer.IDFromPubKey(pk)
269 + id, err := peer.IDFromPublicKey(pk)
270 if err != nil {
271 return ident, err
272 }
cmd/seccat/seccat.go
+15 -10
@@ -109,24 +109,28 @@ func main() {
109 }
110 }
111
112 -func setupPeer(a args) (peer.Peer, peer.Peerstore, error) {
112 +func setupPeer(a args) (peer.ID, peer.Peerstore, error) {
113 if a.keybits < 1024 {
114 - return nil, nil, errors.New("Bitsize less than 1024 is considered unsafe.")
114 + return "", nil, errors.New("Bitsize less than 1024 is considered unsafe.")
115 }
116
117 out("generating key pair...")
118 sk, pk, err := ci.GenerateKeyPair(ci.RSA, a.keybits)
119 if err != nil {
120 - return nil, nil, err
120 + return "", nil, err
121 }
122
123 - ps := peer.NewPeerstore()
124 - peer, err := ps.WithKeyPair(sk, pk)
123 + p, err := peer.IDFromPublicKey(pk)
124 if err != nil {
126 - return nil, nil, err
125 + return "", nil, err
126 }
128 - out("local peer id: %s", peer.ID())
129 - return peer, ps, nil
127 +
128 + ps := peer.NewPeerstore()
129 + ps.AddPrivKey(p, sk)
130 + ps.AddPubKey(p, pk)
131 +
132 + out("local peer id: %s", p)
133 + return p, ps, nil
134 }
135
136 func connect(args args) error {
@@ -149,12 +153,13 @@ func connect(args args) error {
153 rwc := &logRW{n: "conn", rw: conn}
154
155 // OK, let's setup the channel.
152 - sg := secio.SessionGenerator{Local: p, Peerstore: ps}
156 + sk := ps.PrivKey(p)
157 + sg := secio.SessionGenerator{LocalID: p, PrivateKey: sk}
158 sess, err := sg.NewSession(nil, rwc)
159 if err != nil {
160 return err
161 }
157 - out("remote peer id: %s", sess.RemotePeer().ID())
162 + out("remote peer id: %s", sess.RemotePeer())
163 netcat(sess.ReadWriter().(io.ReadWriteCloser))
164 return nil
165 }
config/config.go
+3 -4
@@ -2,12 +2,11 @@
2 package config
3
4 import (
5 - "crypto"
6 - "crypto/x509"
5 "encoding/base64"
6 "os"
7 "path/filepath"
8
9 + ic "github.com/jbenet/go-ipfs/crypto"
10 u "github.com/jbenet/go-ipfs/util"
11 "github.com/jbenet/go-ipfs/util/debugerror"
12 )
@@ -132,7 +131,7 @@ func Filename(configroot string) (string, error) {
131 }
132
133 // DecodePrivateKey is a helper to decode the users PrivateKey
135 -func (i *Identity) DecodePrivateKey(passphrase string) (crypto.PrivateKey, error) {
134 +func (i *Identity) DecodePrivateKey(passphrase string) (ic.PrivKey, error) {
135 pkb, err := base64.StdEncoding.DecodeString(i.PrivKey)
136 if err != nil {
137 return nil, err
@@ -140,7 +139,7 @@ func (i *Identity) DecodePrivateKey(passphrase string) (crypto.PrivateKey, error
139
140 // currently storing key unencrypted. in the future we need to encrypt it.
141 // TODO(security)
143 - return x509.ParsePKCS1PrivateKey(pkb)
142 + return ic.UnmarshalPrivateKey(pkb)
143 }
144
145 // Load reads given file and returns the read config, or error.
core/bootstrap.go
+24 -24
@@ -54,30 +54,30 @@ func bootstrap(ctx context.Context,
54 }
55 numCxnsToCreate := recoveryThreshold - len(connectedPeers)
56
57 - var bootstrapPeers []peer.Peer
57 + var bootstrapPeers []peer.PeerInfo
58 for _, bootstrap := range boots {
59 - p, err := toPeer(ps, bootstrap)
59 + p, err := toPeer(bootstrap)
60 if err != nil {
61 return err
62 }
63 bootstrapPeers = append(bootstrapPeers, p)
64 }
65
66 - var notConnected []peer.Peer
66 + var notConnected []peer.PeerInfo
67 for _, p := range bootstrapPeers {
68 - if n.Connectedness(p) != inet.Connected {
68 + if n.Connectedness(p.ID) != inet.Connected {
69 notConnected = append(notConnected, p)
70 }
71 }
72
73 var randomSubset = randomSubsetOfPeers(notConnected, numCxnsToCreate)
74 - if err := connect(ctx, r, randomSubset); err != nil {
74 + if err := connect(ctx, ps, r, randomSubset); err != nil {
75 return err
76 }
77 return nil
78 }
79
80 -func connect(ctx context.Context, r *dht.IpfsDHT, peers []peer.Peer) error {
80 +func connect(ctx context.Context, ps peer.Peerstore, r *dht.IpfsDHT, peers []peer.PeerInfo) error {
81 var wg sync.WaitGroup
82 for _, p := range peers {
83
@@ -86,42 +86,42 @@ func connect(ctx context.Context, r *dht.IpfsDHT, peers []peer.Peer) error {
86 // fail/abort due to an expiring context.
87
88 wg.Add(1)
89 - go func(p peer.Peer) {
89 + go func(p peer.PeerInfo) {
90 defer wg.Done()
91 - err := r.Connect(ctx, p)
91 + ps.AddAddresses(p.ID, p.Addrs)
92 + err := r.Connect(ctx, p.ID)
93 if err != nil {
93 - log.Event(ctx, "bootstrapFailed", p)
94 - log.Criticalf("failed to bootstrap with %v", p)
94 + log.Event(ctx, "bootstrapFailed", p.ID)
95 + log.Criticalf("failed to bootstrap with %v", p.ID)
96 return
97 }
97 - log.Event(ctx, "bootstrapSuccess", p)
98 - log.Infof("bootstrapped with %v", p)
98 + log.Event(ctx, "bootstrapSuccess", p.ID)
99 + log.Infof("bootstrapped with %v", p.ID)
100 }(p)
101 }
102 wg.Wait()
103 return nil
104 }
105
105 -func toPeer(ps peer.Peerstore, bootstrap *config.BootstrapPeer) (peer.Peer, error) {
106 - id, err := peer.DecodePrettyID(bootstrap.PeerID)
106 +func toPeer(bootstrap *config.BootstrapPeer) (p peer.PeerInfo, err error) {
107 + id, err := peer.IDB58Decode(bootstrap.PeerID)
108 if err != nil {
108 - return nil, err
109 - }
110 - p, err := ps.FindOrCreate(id)
111 - if err != nil {
112 - return nil, err
109 + return
110 }
111 maddr, err := ma.NewMultiaddr(bootstrap.Address)
112 if err != nil {
116 - return nil, err
113 + return
114 + }
115 + p = peer.PeerInfo{
116 + ID: id,
117 + Addrs: []ma.Multiaddr{maddr},
118 }
118 - p.AddAddress(maddr)
119 - return p, nil
119 + return
120 }
121
122 -func randomSubsetOfPeers(in []peer.Peer, max int) []peer.Peer {
122 +func randomSubsetOfPeers(in []peer.PeerInfo, max int) []peer.PeerInfo {
123 n := math2.IntMin(max, len(in))
124 - var out []peer.Peer
124 + var out []peer.PeerInfo
125 for _, val := range rand.Perm(n) {
126 out = append(out, in[val])
127 }
core/bootstrap_test.go
+7 -2
@@ -8,10 +8,15 @@ import (
8 )
9
10 func TestSubsetWhenMaxIsGreaterThanLengthOfSlice(t *testing.T) {
11 - var ps []peer.Peer
11 + var ps []peer.PeerInfo
12 sizeofSlice := 100
13 for i := 0; i < sizeofSlice; i++ {
14 - ps = append(ps, testutil.RandPeer())
14 + pid, err := testutil.RandPeerID()
15 + if err != nil {
16 + t.Fatal(err)
17 + }
18 +
19 + ps = append(ps, peer.PeerInfo{ID: pid})
20 }
21 out := randomSubsetOfPeers(ps, 2*sizeofSlice)
22 if len(out) != len(ps) {
core/commands/id.go
+21 -11
@@ -11,6 +11,7 @@ import (
11 b58 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
12
13 cmds "github.com/jbenet/go-ipfs/commands"
14 + ic "github.com/jbenet/go-ipfs/crypto"
15 "github.com/jbenet/go-ipfs/peer"
16 kb "github.com/jbenet/go-ipfs/routing/kbucket"
17 u "github.com/jbenet/go-ipfs/util"
@@ -49,7 +50,7 @@ if no peer is specified, prints out local peers info.
50 }
51
52 if len(req.Arguments()) == 0 {
52 - return printPeer(node.Identity)
53 + return printPeer(node.Peerstore, node.Identity)
54 }
55
56 pid := req.Arguments()[0]
@@ -72,7 +73,7 @@ if no peer is specified, prints out local peers info.
73 if err != nil {
74 return nil, err
75 }
75 - return printPeer(p)
76 + return printPeer(node.Peerstore, p.ID)
77 },
78 Marshalers: cmds.MarshalerMap{
79 cmds.Text: func(res cmds.Response) ([]byte, error) {
@@ -87,27 +88,36 @@ if no peer is specified, prints out local peers info.
88 Type: &IdOutput{},
89 }
90
90 -func printPeer(p peer.Peer) (interface{}, error) {
91 - if p == nil {
91 +func printPeer(ps peer.Peerstore, p peer.ID) (interface{}, error) {
92 + if p == "" {
93 return nil, errors.New("Attempted to print nil peer!")
94 }
95 +
96 info := new(IdOutput)
97 + info.ID = p.Pretty()
98
96 - info.ID = p.ID().String()
97 - if p.PubKey() != nil {
98 - pkb, err := p.PubKey().Bytes()
99 + if pk := ps.PubKey(p); pk != nil {
100 + pkb, err := ic.MarshalPublicKey(pk)
101 if err != nil {
102 return nil, err
103 }
104 info.PublicKey = base64.StdEncoding.EncodeToString(pkb)
105 }
104 - for _, a := range p.Addresses() {
106 +
107 + for _, a := range ps.Addresses(p) {
108 info.Addresses = append(info.Addresses, a.String())
109 }
110
108 - agent, protocol := p.GetVersions()
109 - info.AgentVersion = agent
110 - info.ProtocolVersion = protocol
111 + if v, err := ps.Get(p, "ProtocolVersion"); err == nil {
112 + if vs, ok := v.(string); ok {
113 + info.AgentVersion = vs
114 + }
115 + }
116 + if v, err := ps.Get(p, "AgentVersion"); err == nil {
117 + if vs, ok := v.(string); ok {
118 + info.ProtocolVersion = vs
119 + }
120 + }
121
122 return info, nil
123 }
core/commands/publish.go
+2 -3
@@ -57,7 +57,7 @@ Publish a <ref> to another public key:
57 return nil, errNotOnline
58 }
59
60 - if n.Identity == nil {
60 + if n.Identity == "" {
61 return nil, errors.New("Identity not loaded!")
62 }
63
@@ -75,8 +75,7 @@ Publish a <ref> to another public key:
75 }
76
77 // TODO n.Keychain.Get(name).PrivKey
78 - k := n.Identity.PrivKey()
79 - return publish(n, k, ref)
78 + return publish(n, n.PrivateKey, ref)
79 },
80 Marshalers: cmds.MarshalerMap{
81 cmds.Text: func(res cmds.Response) ([]byte, error) {
core/commands/resolve.go
+2 -2
@@ -52,10 +52,10 @@ Resolve te value of another name:
52 }
53
54 if len(req.Arguments()) == 0 {
55 - if n.Identity == nil {
55 + if n.Identity == "" {
56 return nil, errors.New("Identity not loaded!")
57 }
58 - name = n.Identity.ID().String()
58 + name = n.Identity.Pretty()
59
60 } else {
61 name = req.Arguments()[0]
core/commands/swarm.go
+7 -14
@@ -58,7 +58,7 @@ ipfs swarm peers lists the set of peers this node is connected to.
58 conns := n.Network.Conns()
59 addrs := make([]string, len(conns))
60 for i, c := range conns {
61 - pid := c.RemotePeer().ID()
61 + pid := c.RemotePeer()
62 addr := c.RemoteMultiaddr()
63 addrs[i] = fmt.Sprintf("%s/%s", addr, pid)
64 }
@@ -106,7 +106,7 @@ ipfs swarm connect /ip4/104.131.131.82/tcp/4001/QmaCpDMGvV2BGHeYERUEnRQAwe3N8Szb
106
107 output := make([]string, len(peers))
108 for i, p := range peers {
109 - output[i] = "connect " + p.ID().String()
109 + output[i] = "connect " + p.Pretty()
110
111 err := n.Network.DialPeer(ctx, p)
112 if err != nil {
@@ -149,7 +149,7 @@ func splitAddresses(addrs []string) (maddrs []ma.Multiaddr, pids []peer.ID, err
149 if err != nil {
150 return nil, nil, cmds.ClientError("invalid peer address: " + err.Error())
151 }
152 - id, err := peer.DecodePrettyID(path.Base(addr))
152 + id, err := peer.IDB58Decode(path.Base(addr))
153 if err != nil {
154 return nil, nil, err
155 }
@@ -161,21 +161,14 @@ func splitAddresses(addrs []string) (maddrs []ma.Multiaddr, pids []peer.ID, err
161
162 // peersWithAddresses is a function that takes in a slice of string peer addresses
163 // (multiaddr + peerid) and returns a slice of properly constructed peers
164 -func peersWithAddresses(ps peer.Peerstore, addrs []string) ([]peer.Peer, error) {
164 +func peersWithAddresses(ps peer.Peerstore, addrs []string) ([]peer.ID, error) {
165 maddrs, pids, err := splitAddresses(addrs)
166 if err != nil {
167 return nil, err
168 }
169
170 - peers := make([]peer.Peer, len(pids))
171 - for i, pid := range pids {
172 - p, err := ps.FindOrCreate(pid)
173 - if err != nil {
174 - return nil, err
175 - }
176 -
177 - p.AddAddress(maddrs[i])
178 - peers[i] = p
170 + for i, p := range pids {
171 + ps.AddAddress(p, maddrs[i])
172 }
180 - return peers, nil
173 + return pids, nil
174 }
core/core.go
+37 -27
@@ -1,7 +1,6 @@
1 package core
2
3 import (
4 - "encoding/base64"
4 "fmt"
5
6 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
@@ -12,6 +11,7 @@ import (
11 bstore "github.com/jbenet/go-ipfs/blocks/blockstore"
12 bserv "github.com/jbenet/go-ipfs/blockservice"
13 config "github.com/jbenet/go-ipfs/config"
14 + ic "github.com/jbenet/go-ipfs/crypto"
15 diag "github.com/jbenet/go-ipfs/diagnostics"
16 exchange "github.com/jbenet/go-ipfs/exchange"
17 bitswap "github.com/jbenet/go-ipfs/exchange/bitswap"
@@ -21,7 +21,6 @@ import (
21 merkledag "github.com/jbenet/go-ipfs/merkledag"
22 namesys "github.com/jbenet/go-ipfs/namesys"
23 inet "github.com/jbenet/go-ipfs/net"
24 - handshake "github.com/jbenet/go-ipfs/net/handshake"
24 path "github.com/jbenet/go-ipfs/path"
25 peer "github.com/jbenet/go-ipfs/peer"
26 pin "github.com/jbenet/go-ipfs/pin"
@@ -42,7 +41,8 @@ type IpfsNode struct {
41
42 // Self
43 Config *config.Config // the node's configuration
45 - Identity peer.Peer // the local node's identity
44 + Identity peer.ID // the local node's identity
45 + PrivateKey ic.PrivKey // the local node's private Key
46 onlineMode bool // alternatively, offline
47
48 // Local node
@@ -97,13 +97,18 @@ func NewIpfsNode(ctx context.Context, cfg *config.Config, online bool) (n *IpfsN
97 return nil, debugerror.Wrap(err)
98 }
99
100 - // setup peerstore + local peer identity
101 - n.Peerstore = peer.NewPeerstore()
102 - n.Identity, err = initIdentity(&n.Config.Identity, n.Peerstore, online)
100 + // setup local peer identity
101 + n.Identity, n.PrivateKey, err = initIdentity(&n.Config.Identity, online)
102 if err != nil {
103 return nil, debugerror.Wrap(err)
104 }
105
106 + // setup Peerstore
107 + n.Peerstore = peer.NewPeerstore()
108 + if n.PrivateKey != nil {
109 + n.Peerstore.AddPrivKey(n.Identity, n.PrivateKey)
110 + }
111 +
112 blockstore, err := bstore.WriteCached(bstore.NewBlockstore(n.Datastore), kSizeBlockstoreWriteCache)
113 n.Exchange = offline.Exchange(blockstore)
114
@@ -126,7 +131,7 @@ func NewIpfsNode(ctx context.Context, cfg *config.Config, online bool) (n *IpfsN
131 n.Diagnostics = diag.NewDiagnostics(n.Identity, n.Network)
132
133 // setup routing service
129 - dhtRouting := dht.NewDHT(ctx, n.Identity, n.Peerstore, n.Network, n.Datastore)
134 + dhtRouting := dht.NewDHT(ctx, n.Identity, n.Network, n.Datastore)
135 dhtRouting.Validators[IpnsValidatorTag] = namesys.ValidateIpnsRecord
136
137 // TODO(brian): perform this inside NewDHT factory method
@@ -178,42 +183,47 @@ func (n *IpfsNode) OnlineMode() bool {
183 return n.onlineMode
184 }
185
181 -func initIdentity(cfg *config.Identity, peers peer.Peerstore, online bool) (peer.Peer, error) {
186 +func initIdentity(cfg *config.Identity, online bool) (peer.ID, ic.PrivKey, error) {
187 +
188 if cfg.PeerID == "" {
183 - return nil, debugerror.New("Identity was not set in config (was ipfs init run?)")
189 + return "", nil, debugerror.New("Identity was not set in config (was ipfs init run?)")
190 }
191
192 if len(cfg.PeerID) == 0 {
187 - return nil, debugerror.New("No peer ID in config! (was ipfs init run?)")
193 + return "", nil, debugerror.New("No peer ID in config! (was ipfs init run?)")
194 }
195
190 - // get peer from peerstore (so it is constructed there)
196 id := peer.ID(b58.Decode(cfg.PeerID))
192 - self, err := peers.FindOrCreate(id)
197 +
198 + // when not online, don't need to parse private keys (yet)
199 + if !online {
200 + return id, nil, nil
201 + }
202 +
203 + sk, err := loadPrivateKey(cfg, id)
204 if err != nil {
194 - return nil, err
205 + return "", nil, err
206 }
196 - self.SetType(peer.Local)
197 - self, err = peers.Add(self)
207 +
208 + return id, sk, nil
209 +}
210 +
211 +func loadPrivateKey(cfg *config.Identity, id peer.ID) (ic.PrivKey, error) {
212 + sk, err := cfg.DecodePrivateKey("passphrase todo!")
213 if err != nil {
214 return nil, err
215 }
216
202 - self.SetVersions(handshake.ClientVersion, handshake.IpfsVersion.String())
203 -
204 - // when not online, don't need to parse private keys (yet)
205 - if online {
206 - skb, err := base64.StdEncoding.DecodeString(cfg.PrivKey)
207 - if err != nil {
208 - return nil, err
209 - }
217 + id2, err := peer.IDFromPrivateKey(sk)
218 + if err != nil {
219 + return nil, err
220 + }
221
211 - if err := self.LoadAndVerifyKeyPair(skb); err != nil {
212 - return nil, err
213 - }
222 + if id2 != id {
223 + return nil, fmt.Errorf("private key in config does not match id: %s != %s", id, id2)
224 }
225
216 - return self, nil
226 + return sk, nil
227 }
228
229 func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) {
core/core_test.go
+1 -18
@@ -3,9 +3,8 @@ package core
3 import (
4 "testing"
5
6 - config "github.com/jbenet/go-ipfs/config"
7 - "github.com/jbenet/go-ipfs/peer"
6 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
7 + config "github.com/jbenet/go-ipfs/config"
8 )
9
10 func TestInitialization(t *testing.T) {
@@ -60,22 +59,6 @@ func TestInitialization(t *testing.T) {
59 }
60 }
61
63 -func TestPeerIsLocal(t *testing.T) {
64 - t.Log("Ensure that peer is Local after initializing identity")
65 -
66 - online := false
67 - peers := peer.NewPeerstore()
68 -
69 - cfg := testIdentity
70 - p, err := initIdentity(&cfg, peers, online)
71 - if err != nil {
72 - t.Fatal(err)
73 - }
74 - if p.GetType() != peer.Local {
75 - t.Fail()
76 - }
77 -}
78 -
62 var testIdentity = config.Identity{
63 PeerID: "QmNgdzLieYi8tgfo2WfTUzNVH5hQK9oAYGVf6dxN12NrHt",
64 PrivKey: "CAASrRIwggkpAgEAAoICAQCwt67GTUQ8nlJhks6CgbLKOx7F5tl1r9zF4m3TUrG3Pe8h64vi+ILDRFd7QJxaJ/n8ux9RUDoxLjzftL4uTdtv5UXl2vaufCc/C0bhCRvDhuWPhVsD75/DZPbwLsepxocwVWTyq7/ZHsCfuWdoh/KNczfy+Gn33gVQbHCnip/uhTVxT7ARTiv8Qa3d7qmmxsR+1zdL/IRO0mic/iojcb3Oc/PRnYBTiAZFbZdUEit/99tnfSjMDg02wRayZaT5ikxa6gBTMZ16Yvienq7RwSELzMQq2jFA4i/TdiGhS9uKywltiN2LrNDBcQJSN02pK12DKoiIy+wuOCRgs2NTQEhU2sXCk091v7giTTOpFX2ij9ghmiRfoSiBFPJA5RGwiH6ansCHtWKY1K8BS5UORM0o3dYk87mTnKbCsdz4bYnGtOWafujYwzueGx8r+IWiys80IPQKDeehnLW6RgoyjszKgL/2XTyP54xMLSW+Qb3BPgDcPaPO0hmop1hW9upStxKsefW2A2d46Ds4HEpJEry7PkS5M4gKL/zCKHuxuXVk14+fZQ1rstMuvKjrekpAC2aVIKMI9VRA3awtnje8HImQMdj+r+bPmv0N8rTTr3eS4J8Yl7k12i95LLfK+fWnmUh22oTNzkRlaiERQrUDyE4XNCtJc0xs1oe1yXGqazCIAQIDAQABAoICAQCk1N/ftahlRmOfAXk//8wNl7FvdJD3le6+YSKBj0uWmN1ZbUSQk64chr12iGCOM2WY180xYjy1LOS44PTXaeW5bEiTSnb3b3SH+HPHaWCNM2EiSogHltYVQjKW+3tfH39vlOdQ9uQ+l9Gh6iTLOqsCRyszpYPqIBwi1NMLY2Ej8PpVU7ftnFWouHZ9YKS7nAEiMoowhTu/7cCIVwZlAy3AySTuKxPMVj9LORqC32PVvBHZaMPJ+X1Xyijqg6aq39WyoztkXg3+Xxx5j5eOrK6vO/Lp6ZUxaQilHDXoJkKEJjgIBDZpluss08UPfOgiWAGkW+L4fgUxY0qDLDAEMhyEBAn6KOKVL1JhGTX6GjhWziI94bddSpHKYOEIDzUy4H8BXnKhtnyQV6ELS65C2hj9D0IMBTj7edCF1poJy0QfdK0cuXgMvxHLeUO5uc2YWfbNosvKxqygB9rToy4b22YvNwsZUXsTY6Jt+p9V2OgXSKfB5VPeRbjTJL6xqvvUJpQytmII/C9JmSDUtCbYceHj6X9jgigLk20VV6nWHqCTj3utXD6NPAjoycVpLKDlnWEgfVELDIk0gobxUqqSm3jTPEKRPJgxkgPxbwxYumtw++1UY2y35w3WRDc2xYPaWKBCQeZy+mL6ByXp9bWlNvxS3Knb6oZp36/ovGnf2pGvdQKCAQEAyKpipz2lIUySDyE0avVWAmQb2tWGKXALPohzj7AwkcfEg2GuwoC6GyVE2sTJD1HRazIjOKn3yQORg2uOPeG7sx7EKHxSxCKDrbPawkvLCq8JYSy9TLvhqKUVVGYPqMBzu2POSLEA81QXas+aYjKOFWA2Zrjq26zV9ey3+6Lc6WULePgRQybU8+RHJc6fdjUCCfUxgOrUO2IQOuTJ+FsDpVnrMUGlokmWn23OjL4qTL9wGDnWGUs2pjSzNbj3qA0d8iqaiMUyHX/D/VS0wpeT1osNBSm8suvSibYBn+7wbIApbwXUxZaxMv2OHGz3empae4ckvNZs7r8wsI9UwFt8mwKCAQEA4XK6gZkv9t+3YCcSPw2ensLvL/xU7i2bkC9tfTGdjnQfzZXIf5KNdVuj/SerOl2S1s45NMs3ysJbADwRb4ahElD/V71nGzV8fpFTitC20ro9fuX4J0+twmBolHqeH9pmeGTjAeL1rvt6vxs4FkeG/yNft7GdXpXTtEGaObn8Mt0tPY+aB3UnKrnCQoQAlPyGHFrVRX0UEcp6wyyNGhJCNKeNOvqCHTFObhbhO+KWpWSN0MkVHnqaIBnIn1Te8FtvP/iTwXGnKc0YXJUG6+LM6LmOguW6tg8ZqiQeYyyR+e9eCFH4csLzkrTl1GxCxwEsoSLIMm7UDcjttW6tYEghkwKCAQEAmeCO5lCPYImnN5Lu71ZTLmI2OgmjaANTnBBnDbi+hgv61gUCToUIMejSdDCTPfwv61P3TmyIZs0luPGxkiKYHTNqmOE9Vspgz8Mr7fLRMNApESuNvloVIY32XVImj/GEzh4rAfM6F15U1sN8T/EUo6+0B/Glp+9R49QzAfRSE2g48/rGwgf1JVHYfVWFUtAzUA+GdqWdOixo5cCsYJbqpNHfWVZN/bUQnBFIYwUwysnC29D+LUdQEQQ4qOm+gFAOtrWU62zMkXJ4iLt8Ify6kbrvsRXgbhQIzzGS7WH9XDarj0eZciuslr15TLMC1Azadf+cXHLR9gMHA13mT9vYIQKCAQA/DjGv8cKCkAvf7s2hqROGYAs6Jp8yhrsN1tYOwAPLRhtnCs+rLrg17M2vDptLlcRuI/vIElamdTmylRpjUQpX7yObzLO73nfVhpwRJVMdGU394iBIDncQ+JoHfUwgqJskbUM40dvZdyjbrqc/Q/4z+hbZb+oN/GXb8sVKBATPzSDMKQ/xqgisYIw+wmDPStnPsHAaIWOtni47zIgilJzD0WEk78/YjmPbUrboYvWziK5JiRRJFA1rkQqV1c0M+OXixIm+/yS8AksgCeaHr0WUieGcJtjT9uE8vyFop5ykhRiNxy9wGaq6i7IEecsrkd6DqxDHWkwhFuO1bSE83q/VAoIBAEA+RX1i/SUi08p71ggUi9WFMqXmzELp1L3hiEjOc2AklHk2rPxsaTh9+G95BvjhP7fRa/Yga+yDtYuyjO99nedStdNNSg03aPXILl9gs3r2dPiQKUEXZJ3FrH6tkils/8BlpOIRfbkszrdZIKTO9GCdLWQ30dQITDACs8zV/1GFGrHFrqnnMe/NpIFHWNZJ0/WZMi8wgWO6Ik8jHEpQtVXRiXLqy7U6hk170pa4GHOzvftfPElOZZjy9qn7KjdAQqy6spIrAE94OEL+fBgbHQZGLpuTlj6w6YGbMtPU8uo7sXKoc6WOCb68JWft3tejGLDa1946HAWqVM9B/UcneNc=",
core/mock.go
+7 -8
@@ -25,24 +25,23 @@ func NewMockNode() (*IpfsNode, error) {
25 return nil, err
26 }
27
28 - nd.Peerstore = peer.NewPeerstore()
29 -
30 - p, err := nd.Peerstore.WithKeyPair(sk, pk)
28 + p, err := peer.IDFromPublicKey(pk)
29 if err != nil {
30 return nil, err
31 }
32
35 - nd.Identity, err = nd.Peerstore.Add(p)
36 - if err != nil {
37 - return nil, err
38 - }
33 + nd.Identity = p
34 + nd.PrivateKey = sk
35 + nd.Peerstore = peer.NewPeerstore()
36 + nd.Peerstore.AddPrivKey(p, sk)
37 + nd.Peerstore.AddPubKey(p, pk)
38
39 // Temp Datastore
40 dstore := ds.NewMapDatastore()
41 nd.Datastore = ds2.CloserWrap(syncds.MutexWrap(dstore))
42
43 // Routing
45 - dht := mdht.NewServer().ClientWithDatastore(nd.Identity, nd.Datastore)
44 + dht := mdht.NewServer().ClientWithDatastore(peer.PeerInfo{ID: p}, nd.Datastore)
45 nd.Routing = dht
46
47 // Bitswap
crypto/key.go
+36 -1
@@ -5,6 +5,7 @@ package crypto
5
6 import (
7 "bytes"
8 + "encoding/base64"
9 "errors"
10 "fmt"
11
@@ -82,7 +83,7 @@ func GenerateKeyPair(typ, bits int) (PrivKey, PubKey, error) {
83 return nil, nil, err
84 }
85 pk := &priv.PublicKey
85 - return &RsaPrivateKey{priv}, &RsaPublicKey{pk}, nil
86 + return &RsaPrivateKey{sk: priv}, &RsaPublicKey{pk}, nil
87 default:
88 return nil, nil, ErrBadKeyType
89 }
@@ -239,6 +240,20 @@ func UnmarshalPublicKey(data []byte) (PubKey, error) {
240 }
241 }
242
243 +// MarshalPublicKey converts a public key object into a protobuf serialized
244 +// public key
245 +func MarshalPublicKey(k PubKey) ([]byte, error) {
246 + b, err := MarshalRsaPublicKey(k.(*RsaPublicKey))
247 + if err != nil {
248 + return nil, err
249 + }
250 + pmes := new(pb.PublicKey)
251 + typ := pb.KeyType_RSA // for now only type.
252 + pmes.Type = &typ
253 + pmes.Data = b
254 + return proto.Marshal(pmes)
255 +}
256 +
257 // UnmarshalPrivateKey converts a protobuf serialized private key into its
258 // representative object
259 func UnmarshalPrivateKey(data []byte) (PrivKey, error) {
@@ -256,6 +271,26 @@ func UnmarshalPrivateKey(data []byte) (PrivKey, error) {
271 }
272 }
273
274 +// MarshalPrivateKey converts a key object into its protobuf serialized form.
275 +func MarshalPrivateKey(k PrivKey) ([]byte, error) {
276 + b := MarshalRsaPrivateKey(k.(*RsaPrivateKey))
277 + pmes := new(pb.PrivateKey)
278 + typ := pb.KeyType_RSA // for now only type.
279 + pmes.Type = &typ
280 + pmes.Data = b
281 + return proto.Marshal(pmes)
282 +}
283 +
284 +// ConfigDecodeKey decodes from b64 (for config file), and unmarshals.
285 +func ConfigDecodeKey(b string) ([]byte, error) {
286 + return base64.StdEncoding.DecodeString(b)
287 +}
288 +
289 +// ConfigEncodeKey encodes to b64 (for config file), and marshals.
290 +func ConfigEncodeKey(b []byte) string {
291 + return base64.StdEncoding.EncodeToString(b)
292 +}
293 +
294 // KeyEqual checks whether two
295 func KeyEqual(k1, k2 Key) bool {
296 if k1 == k2 {
crypto/key_test.go
+26 -5
@@ -1,6 +1,9 @@
1 package crypto
2
3 -import "testing"
3 +import (
4 + "bytes"
5 + "testing"
6 +)
7
8 func TestRsaKeys(t *testing.T) {
9 sk, pk, err := GenerateKeyPair(RSA, 512)
@@ -33,26 +36,44 @@ func testKeySignature(t *testing.T, sk PrivKey) {
36 }
37
38 func testKeyEncoding(t *testing.T, sk PrivKey) {
36 - skb, err := sk.Bytes()
39 + skbm, err := MarshalPrivateKey(sk)
40 if err != nil {
41 t.Fatal(err)
42 }
43
41 - _, err = UnmarshalPrivateKey(skb)
44 + sk2, err := UnmarshalPrivateKey(skbm)
45 if err != nil {
46 t.Fatal(err)
47 }
48
49 + skbm2, err := MarshalPrivateKey(sk2)
50 + if err != nil {
51 + t.Fatal(err)
52 + }
53 +
54 + if !bytes.Equal(skbm, skbm2) {
55 + t.Error("skb -> marshal -> unmarshal -> skb failed.\n", skbm, "\n", skbm2)
56 + }
57 +
58 pk := sk.GetPublic()
47 - pkb, err := pk.Bytes()
59 + pkbm, err := MarshalPublicKey(pk)
60 if err != nil {
61 t.Fatal(err)
62 }
63
52 - _, err = UnmarshalPublicKey(pkb)
64 + _, err = UnmarshalPublicKey(pkbm)
65 if err != nil {
66 t.Fatal(err)
67 }
68 +
69 + pkbm2, err := MarshalPublicKey(pk)
70 + if err != nil {
71 + t.Fatal(err)
72 + }
73 +
74 + if !bytes.Equal(pkbm, pkbm2) {
75 + t.Error("skb -> marshal -> unmarshal -> skb failed.\n", pkbm, "\n", pkbm2)
76 + }
77 }
78
79 func testKeyEquals(t *testing.T, k Key) {
crypto/rsa.go
+18 -6
@@ -14,7 +14,8 @@ import (
14 )
15
16 type RsaPrivateKey struct {
17 - k *rsa.PrivateKey
17 + sk *rsa.PrivateKey
18 + pk *rsa.PublicKey
19 }
20
21 type RsaPublicKey struct {
@@ -64,19 +65,22 @@ func (sk *RsaPrivateKey) GenSecret() []byte {
65
66 func (sk *RsaPrivateKey) Sign(message []byte) ([]byte, error) {
67 hashed := sha256.Sum256(message)
67 - return rsa.SignPKCS1v15(rand.Reader, sk.k, crypto.SHA256, hashed[:])
68 + return rsa.SignPKCS1v15(rand.Reader, sk.sk, crypto.SHA256, hashed[:])
69 }
70
71 func (sk *RsaPrivateKey) GetPublic() PubKey {
71 - return &RsaPublicKey{&sk.k.PublicKey}
72 + if sk.pk == nil {
73 + sk.pk = &sk.sk.PublicKey
74 + }
75 + return &RsaPublicKey{sk.pk}
76 }
77
78 func (sk *RsaPrivateKey) Decrypt(b []byte) ([]byte, error) {
75 - return rsa.DecryptPKCS1v15(rand.Reader, sk.k, b)
79 + return rsa.DecryptPKCS1v15(rand.Reader, sk.sk, b)
80 }
81
82 func (sk *RsaPrivateKey) Bytes() ([]byte, error) {
79 - b := x509.MarshalPKCS1PrivateKey(sk.k)
83 + b := x509.MarshalPKCS1PrivateKey(sk.sk)
84 pbmes := new(pb.PrivateKey)
85 typ := pb.KeyType_RSA
86 pbmes.Type = &typ
@@ -98,7 +102,11 @@ func UnmarshalRsaPrivateKey(b []byte) (*RsaPrivateKey, error) {
102 if err != nil {
103 return nil, err
104 }
101 - return &RsaPrivateKey{sk}, nil
105 + return &RsaPrivateKey{sk: sk}, nil
106 +}
107 +
108 +func MarshalRsaPrivateKey(k *RsaPrivateKey) []byte {
109 + return x509.MarshalPKCS1PrivateKey(k.sk)
110 }
111
112 func UnmarshalRsaPublicKey(b []byte) (*RsaPublicKey, error) {
@@ -112,3 +120,7 @@ func UnmarshalRsaPublicKey(b []byte) (*RsaPublicKey, error) {
120 }
121 return &RsaPublicKey{pk}, nil
122 }
123 +
124 +func MarshalRsaPublicKey(k *RsaPublicKey) ([]byte, error) {
125 + return x509.MarshalPKIXPublicKey(k.k)
126 +}
crypto/secio/interface.go
+30 -8
@@ -4,6 +4,8 @@ package secio
4 import (
5 "io"
6
7 + ci "github.com/jbenet/go-ipfs/crypto"
8 +
9 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
10 msgio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio"
11
@@ -12,8 +14,8 @@ import (
14
15 // SessionGenerator constructs secure communication sessions for a peer.
16 type SessionGenerator struct {
15 - Local peer.Peer
16 - Peerstore peer.Peerstore
17 + LocalID peer.ID
18 + PrivateKey ci.PrivKey
19 }
20
21 // NewSession takes an insecure io.ReadWriter, performs a TLS-like
@@ -23,12 +25,15 @@ type SessionGenerator struct {
25 func (sg *SessionGenerator) NewSession(ctx context.Context,
26 insecure io.ReadWriter) (Session, error) {
27
28 + ss, err := newSecureSession(sg.LocalID, sg.PrivateKey)
29 + if err != nil {
30 + return nil, err
31 + }
32 +
33 if ctx == nil {
34 ctx = context.Background()
35 }
36 ctx, cancel := context.WithCancel(ctx)
30 -
31 - ss := newSecureSession(sg.Local, sg.Peerstore)
37 if err := ss.handshake(ctx, insecure); err != nil {
38 cancel()
39 return nil, err
@@ -42,10 +47,17 @@ type Session interface {
47 ReadWriter() msgio.ReadWriteCloser
48
49 // LocalPeer retrieves the local peer.
45 - LocalPeer() peer.Peer
50 + LocalPeer() peer.ID
51 +
52 + // LocalPrivateKey retrieves the local private key
53 + LocalPrivateKey() ci.PrivKey
54
55 // RemotePeer retrieves the remote peer.
48 - RemotePeer() peer.Peer
56 + RemotePeer() peer.ID
57 +
58 + // RemotePublicKey retrieves the remote's public key
59 + // which was received during the handshake.
60 + RemotePublicKey() ci.PubKey
61
62 // Close closes the secure session
63 Close() error
@@ -57,15 +69,25 @@ func (s *secureSession) ReadWriter() msgio.ReadWriteCloser {
69 }
70
71 // LocalPeer retrieves the local peer.
60 -func (s *secureSession) LocalPeer() peer.Peer {
72 +func (s *secureSession) LocalPeer() peer.ID {
73 return s.localPeer
74 }
75
76 +// LocalPrivateKey retrieves the local peer's PrivateKey
77 +func (s *secureSession) LocalPrivateKey() ci.PrivKey {
78 + return s.localKey
79 +}
80 +
81 // RemotePeer retrieves the remote peer.
65 -func (s *secureSession) RemotePeer() peer.Peer {
82 +func (s *secureSession) RemotePeer() peer.ID {
83 return s.remotePeer
84 }
85
86 +// RemotePeer retrieves the remote peer.
87 +func (s *secureSession) RemotePublicKey() ci.PubKey {
88 + return s.remote.permanentPubKey
89 +}
90 +
91 // Close closes the secure session
92 func (s *secureSession) Close() error {
93 return s.secure.Close()
crypto/secio/pb/Makefile renamed
crypto/secio/pb/spipe.pb.go renamed
crypto/secio/pb/spipe.proto renamed
crypto/secio/protocol.go
+48 -35
@@ -11,7 +11,7 @@ import (
11 msgio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio"
12
13 ci "github.com/jbenet/go-ipfs/crypto"
14 - pb "github.com/jbenet/go-ipfs/crypto/spipe/internal/pb"
14 + pb "github.com/jbenet/go-ipfs/crypto/secio/internal/pb"
15 peer "github.com/jbenet/go-ipfs/peer"
16 u "github.com/jbenet/go-ipfs/util"
17 eventlog "github.com/jbenet/go-ipfs/util/eventlog"
@@ -36,9 +36,9 @@ type secureSession struct {
36 insecure io.ReadWriter
37 insecureM msgio.ReadWriter
38
39 - peers peer.Peerstore
40 - localPeer peer.Peer
41 - remotePeer peer.Peer
39 + localKey ci.PrivKey
40 + localPeer peer.ID
41 + remotePeer peer.ID
42
43 local encParams
44 remote encParams
@@ -46,8 +46,19 @@ type secureSession struct {
46 sharedSecret []byte
47 }
48
49 -func newSecureSession(local peer.Peer, peers peer.Peerstore) *secureSession {
50 - return &secureSession{peers: peers, localPeer: local}
49 +func newSecureSession(local peer.ID, key ci.PrivKey) (*secureSession, error) {
50 + s := &secureSession{localPeer: local, localKey: key}
51 +
52 + switch {
53 + case s.localPeer == "":
54 + return nil, errors.New("no local id provided")
55 + case s.localKey == nil:
56 + return nil, errors.New("no local private key provided")
57 + case !s.localPeer.MatchesPrivateKey(s.localKey):
58 + return nil, fmt.Errorf("peer.ID does not match PrivateKey")
59 + }
60 +
61 + return s, nil
62 }
63
64 // handsahke performs initial communication over insecure channel to share
@@ -71,7 +82,7 @@ func (s *secureSession) handshake(ctx context.Context, insecure io.ReadWriter) e
82
83 log.Debugf("handshake: %s <--start--> %s", s.localPeer, s.remotePeer)
84 log.Event(ctx, "secureHandshakeStart", s.localPeer)
74 - s.local.permanentPubKey = s.localPeer.PubKey()
85 + s.local.permanentPubKey = s.localKey.GetPublic()
86 myPubKeyBytes, err := s.local.permanentPubKey.Bytes()
87 if err != nil {
88 return err
@@ -84,6 +95,9 @@ func (s *secureSession) handshake(ctx context.Context, insecure io.ReadWriter) e
95 proposeOut.Ciphers = &SupportedCiphers
96 proposeOut.Hashes = &SupportedHashes
97
98 + // log.Debugf("1.0 Propose: nonce:%s exchanges:%s ciphers:%s hashes:%s",
99 + // nonceOut, SupportedExchanges, SupportedCiphers, SupportedHashes)
100 +
101 // Send Propose packet (respects ctx)
102 proposeOutBytes, err := writeMsgCtx(ctx, s.insecureM, proposeOut)
103 if err != nil {
@@ -97,6 +111,9 @@ func (s *secureSession) handshake(ctx context.Context, insecure io.ReadWriter) e
111 return err
112 }
113
114 + // log.Debugf("1.0.1 Propose recv: nonce:%s exchanges:%s ciphers:%s hashes:%s",
115 + // proposeIn.GetRand(), proposeIn.GetExchanges(), proposeIn.GetCiphers(), proposeIn.GetHashes())
116 +
117 // =============================================================================
118 // step 1.1 Identify -- get identity from their key
119
@@ -106,12 +123,13 @@ func (s *secureSession) handshake(ctx context.Context, insecure io.ReadWriter) e
123 return err
124 }
125
109 - // get or construct peer
110 - s.remotePeer, err = getOrConstructPeer(s.peers, s.remote.permanentPubKey)
126 + // get peer id
127 + s.remotePeer, err = peer.IDFromPublicKey(s.remote.permanentPubKey)
128 if err != nil {
129 return err
130 }
114 - // log.Debugf("%s Remote Peer Identified as %s", s.localPeer, s.remotePeer)
131 +
132 + log.Debugf("1.1 Identify: %s Remote Peer Identified as %s", s.localPeer, s.remotePeer)
133
134 // =============================================================================
135 // step 1.2 Selection -- select/agree on best encryption parameters
@@ -141,6 +159,9 @@ func (s *secureSession) handshake(ctx context.Context, insecure io.ReadWriter) e
159 s.remote.cipherT = s.local.cipherT
160 s.remote.hashT = s.local.hashT
161
162 + // log.Debugf("1.2 selection: exchange:%s cipher:%s hash:%s",
163 + // s.local.curveT, s.local.cipherT, s.local.hashT)
164 +
165 // =============================================================================
166 // step 2. Exchange -- exchange (signed) ephemeral keys. verify signatures.
167
@@ -155,9 +176,10 @@ func (s *secureSession) handshake(ctx context.Context, insecure io.ReadWriter) e
176 selectionOut.Write(s.local.ephemeralPubKey)
177 selectionOutBytes := selectionOut.Bytes()
178
179 + // log.Debugf("2.0 exchange: %v", selectionOutBytes)
180 exchangeOut := new(pb.Exchange)
181 exchangeOut.Epubkey = s.local.ephemeralPubKey
160 - exchangeOut.Signature, err = s.localPeer.PrivKey().Sign(selectionOutBytes)
182 + exchangeOut.Signature, err = s.localKey.Sign(selectionOutBytes)
183 if err != nil {
184 return err
185 }
@@ -184,16 +206,21 @@ func (s *secureSession) handshake(ctx context.Context, insecure io.ReadWriter) e
206 selectionIn.Write(proposeOutBytes)
207 selectionIn.Write(s.remote.ephemeralPubKey)
208 selectionInBytes := selectionIn.Bytes()
209 + // log.Debugf("2.0.1 exchange recv: %v", selectionInBytes)
210
211 // u.POut("Remote Peer Identified as %s\n", s.remote)
189 - sigOK, err := s.remotePeer.PubKey().Verify(selectionInBytes, exchangeIn.GetSignature())
212 + sigOK, err := s.remote.permanentPubKey.Verify(selectionInBytes, exchangeIn.GetSignature())
213 if err != nil {
214 + // log.Error("2.1 Verify: failed: %s", err)
215 return err
216 }
217
218 if !sigOK {
195 - return errors.New("Bad signature!")
219 + err := errors.New("Bad signature!")
220 + // log.Error("2.1 Verify: failed: %s", err)
221 + return err
222 }
223 + // log.Debugf("2.1 Verify: signature verified.")
224
225 // =============================================================================
226 // step 2.2. Keys -- generate keys for mac + encryption
@@ -223,6 +250,9 @@ func (s *secureSession) handshake(ctx context.Context, insecure io.ReadWriter) e
250 s.local.keys = k1
251 s.remote.keys = k2
252
253 + // log.Debug("2.2 keys:\n\tshared: %v\n\tk1: %v\n\tk2: %v",
254 + // s.sharedSecret, s.local.keys, s.remote.keys)
255 +
256 // =============================================================================
257 // step 2.3. MAC + Cipher -- prepare MAC + cipher
258
@@ -234,6 +264,8 @@ func (s *secureSession) handshake(ctx context.Context, insecure io.ReadWriter) e
264 return err
265 }
266
267 + // log.Debug("2.3 mac + cipher.")
268 +
269 // =============================================================================
270 // step 3. Finish -- send expected message (the nonces), verify encryption works
271
@@ -242,6 +274,7 @@ func (s *secureSession) handshake(ctx context.Context, insecure io.ReadWriter) e
274 r := NewETMReader(s.insecure, s.remote.cipher, s.remote.mac)
275 s.secure = msgio.Combine(w, r).(msgio.ReadWriteCloser)
276
277 + // log.Debug("3.0 finish. sending: %v", proposeIn.GetRand())
278 // send their Nonce.
279 if _, err := s.secure.Write(proposeIn.GetRand()); err != nil {
280 return fmt.Errorf("Failed to write Finish nonce: %s", err)
@@ -252,6 +285,8 @@ func (s *secureSession) handshake(ctx context.Context, insecure io.ReadWriter) e
285 if _, err := io.ReadFull(s.secure, nonceOut2); err != nil {
286 return fmt.Errorf("Failed to read Finish nonce: %s", err)
287 }
288 +
289 + // log.Debug("3.0 finish.\n\texpect: %v\n\tactual: %v", nonceOut, nonceOut2)
290 if !bytes.Equal(nonceOut, nonceOut2) {
291 return fmt.Errorf("Failed to read our encrypted nonce: %s != %s", nonceOut2, nonceOut)
292 }
@@ -261,25 +296,3 @@ func (s *secureSession) handshake(ctx context.Context, insecure io.ReadWriter) e
296 log.Event(ctx, "secureHandshakeFinish", s.localPeer, s.remotePeer)
297 return nil
298 }
264 -
265 -// getOrConstructPeer attempts to fetch a peer from a peerstore.
266 -// if succeeds, verify ID and PubKey match.
267 -// else, construct it.
268 -func getOrConstructPeer(peers peer.Peerstore, rpk ci.PubKey) (peer.Peer, error) {
269 -
270 - rid, err := peer.IDFromPubKey(rpk)
271 - if err != nil {
272 - return nil, err
273 - }
274 -
275 - npeer, err := peers.FindOrCreate(rid)
276 - if err != nil {
277 - return nil, err // unexpected error happened.
278 - }
279 -
280 - // public key verification happens in Peer.VerifyAndSetPubKey
281 - if err := npeer.VerifyAndSetPubKey(rpk); err != nil {
282 - return nil, err // pubkey mismatch or other problem
283 - }
284 - return npeer, nil
285 -}
crypto/spipe/handshake.go deleted
-389
@@ -1,389 +0,0 @@
1 -// package spipe handles establishing secure communication between two peers.
2 -package spipe
3 -
4 -import (
5 - "bytes"
6 - "errors"
7 - "fmt"
8 - "strings"
9 -
10 - "crypto/aes"
11 - "crypto/cipher"
12 - "crypto/hmac"
13 - "crypto/rand"
14 - "crypto/sha1"
15 - "crypto/sha256"
16 - "crypto/sha512"
17 - "hash"
18 -
19 - bfish "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.crypto/blowfish"
20 -
21 - proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
22 -
23 - ci "github.com/jbenet/go-ipfs/crypto"
24 - pb "github.com/jbenet/go-ipfs/crypto/spipe/internal/pb"
25 - peer "github.com/jbenet/go-ipfs/peer"
26 - u "github.com/jbenet/go-ipfs/util"
27 -)
28 -
29 -var log = u.Logger("handshake")
30 -
31 -// List of supported ECDH curves
32 -var SupportedExchanges = "P-256,P-224,P-384,P-521"
33 -
34 -// List of supported Ciphers
35 -var SupportedCiphers = "AES-256,AES-128,Blowfish"
36 -
37 -// List of supported Hashes
38 -var SupportedHashes = "SHA256,SHA512"
39 -
40 -// ErrUnsupportedKeyType is returned when a private key cast/type switch fails.
41 -var ErrUnsupportedKeyType = errors.New("unsupported key type")
42 -
43 -// ErrClosed signals the closing of a connection.
44 -var ErrClosed = errors.New("connection closed")
45 -
46 -// handsahke performs initial communication over insecure channel to share
47 -// keys, IDs, and initiate communication.
48 -func (s *SecurePipe) handshake() error {
49 - // Generate and send Hello packet.
50 - // Hello = (rand, PublicKey, Supported)
51 - nonce := make([]byte, 16)
52 - _, err := rand.Read(nonce)
53 - if err != nil {
54 - return err
55 - }
56 -
57 - log.Debugf("handshake: %s <--> %s", s.local, s.remote)
58 - myPubKey, err := s.local.PubKey().Bytes()
59 - if err != nil {
60 - return err
61 - }
62 -
63 - proposeMsg := new(pb.Propose)
64 - proposeMsg.Rand = nonce
65 - proposeMsg.Pubkey = myPubKey
66 - proposeMsg.Exchanges = &SupportedExchanges
67 - proposeMsg.Ciphers = &SupportedCiphers
68 - proposeMsg.Hashes = &SupportedHashes
69 -
70 - encoded, err := proto.Marshal(proposeMsg)
71 - if err != nil {
72 - return err
73 - }
74 -
75 - // Send our Propose packet
76 - select {
77 - case s.insecure.Out <- encoded:
78 - case <-s.ctx.Done():
79 - return ErrClosed
80 - }
81 -
82 - // Parse their Propose packet and generate an Exchange packet.
83 - // Exchange = (EphemeralPubKey, Signature)
84 - var resp []byte
85 - select {
86 - case <-s.ctx.Done():
87 - return ErrClosed
88 - case resp = <-s.insecure.In:
89 - }
90 -
91 - // u.POut("received encoded handshake\n")
92 - proposeResp := new(pb.Propose)
93 - err = proto.Unmarshal(resp, proposeResp)
94 - if err != nil {
95 - return err
96 - }
97 -
98 - // get remote identity
99 - remotePubKey, err := ci.UnmarshalPublicKey(proposeResp.GetPubkey())
100 - if err != nil {
101 - return err
102 - }
103 -
104 - // get or construct peer
105 - s.remote, err = getOrConstructPeer(s.peers, remotePubKey)
106 - if err != nil {
107 - return err
108 - }
109 - log.Debugf("%s Remote Peer Identified as %s", s.local, s.remote)
110 -
111 - exchange, err := SelectBest(SupportedExchanges, proposeResp.GetExchanges())
112 - if err != nil {
113 - return err
114 - }
115 -
116 - cipherType, err := SelectBest(SupportedCiphers, proposeResp.GetCiphers())
117 - if err != nil {
118 - return err
119 - }
120 -
121 - hashType, err := SelectBest(SupportedHashes, proposeResp.GetHashes())
122 - if err != nil {
123 - return err
124 - }
125 -
126 - // u.POut("Selected %s %s %s\n", exchange, cipherType, hashType)
127 - epubkey, genSharedKey, err := ci.GenerateEKeyPair(exchange) // Generate EphemeralPubKey
128 -
129 - var handshake bytes.Buffer // Gather corpus to sign.
130 - handshake.Write(encoded)
131 - handshake.Write(resp)
132 - handshake.Write(epubkey)
133 -
134 - exPacket := new(pb.Exchange)
135 -
136 - exPacket.Epubkey = epubkey
137 - exPacket.Signature, err = s.local.PrivKey().Sign(handshake.Bytes())
138 - if err != nil {
139 - return err
140 - }
141 -
142 - exEncoded, err := proto.Marshal(exPacket)
143 -
144 - // send out Exchange packet
145 - select {
146 - case s.insecure.Out <- exEncoded:
147 - case <-s.ctx.Done():
148 - return ErrClosed
149 - }
150 -
151 - // Parse their Exchange packet and generate a Finish packet.
152 - // Finish = E('Finish')
153 - var resp1 []byte
154 - select {
155 - case <-s.ctx.Done():
156 - return ErrClosed
157 - case resp1 = <-s.insecure.In:
158 - }
159 -
160 - exchangeResp := new(pb.Exchange)
161 - err = proto.Unmarshal(resp1, exchangeResp)
162 - if err != nil {
163 - return err
164 - }
165 -
166 - var theirHandshake bytes.Buffer
167 - theirHandshake.Write(resp)
168 - theirHandshake.Write(encoded)
169 - theirHandshake.Write(exchangeResp.GetEpubkey())
170 -
171 - // u.POut("Remote Peer Identified as %s\n", s.remote)
172 - ok, err := s.remote.PubKey().Verify(theirHandshake.Bytes(), exchangeResp.GetSignature())
173 - if err != nil {
174 - return err
175 - }
176 -
177 - if !ok {
178 - return errors.New("Bad signature!")
179 - }
180 -
181 - secret, err := genSharedKey(exchangeResp.GetEpubkey())
182 - if err != nil {
183 - return err
184 - }
185 -
186 - k1, k2 := ci.KeyStretcher(cipherType, hashType, secret)
187 - cmp := bytes.Compare(myPubKey, proposeResp.GetPubkey())
188 - switch cmp {
189 - case 1:
190 - case -1:
191 - k1, k2 = k2, k1 // swap
192 - case 0: // really shouldnt kappen.
193 - copy(k2.IV, k1.IV)
194 - copy(k2.MacKey, k1.MacKey)
195 - copy(k2.CipherKey, k1.CipherKey)
196 - }
197 - go s.handleSecureIn(hashType, cipherType, k2.IV, k2.CipherKey, k2.MacKey)
198 - go s.handleSecureOut(hashType, cipherType, k1.IV, k1.CipherKey, k1.MacKey)
199 -
200 - finished := []byte("Finished")
201 -
202 - // send finished msg
203 - select {
204 - case <-s.ctx.Done():
205 - return ErrClosed
206 - case s.Out <- finished:
207 - }
208 -
209 - // recv finished msg
210 - var resp2 []byte
211 - select {
212 - case <-s.ctx.Done():
213 - return ErrClosed
214 - case resp2 = <-s.In:
215 - }
216 -
217 - if bytes.Compare(resp2, finished) != 0 {
218 - return fmt.Errorf("Negotiation failed, got: %s", resp2)
219 - }
220 -
221 - log.Debugf("%s handshake: Got node id: %s", s.local, s.remote)
222 - return nil
223 -}
224 -
225 -func makeMac(hashType string, key []byte) (hash.Hash, int) {
226 - switch hashType {
227 - case "SHA1":
228 - return hmac.New(sha1.New, key), sha1.Size
229 - case "SHA512":
230 - return hmac.New(sha512.New, key), sha512.Size
231 - default:
232 - return hmac.New(sha256.New, key), sha256.Size
233 - }
234 -}
235 -
236 -func makeCipher(cipherType string, CKey []byte) (cipher.Block, error) {
237 - switch cipherType {
238 - case "AES-128", "AES-256":
239 - return aes.NewCipher(CKey)
240 - case "Blowfish":
241 - return bfish.NewCipher(CKey)
242 - default:
243 - return nil, fmt.Errorf("Unrecognized cipher string: %s", cipherType)
244 - }
245 -}
246 -
247 -func (s *SecurePipe) handleSecureIn(hashType, cipherType string, tIV, tCKey, tMKey []byte) {
248 - theirBlock, err := makeCipher(cipherType, tCKey)
249 - if err != nil {
250 - log.Criticalf("Invalid Cipher: %s", err)
251 - s.cancel()
252 - return
253 - }
254 - theirCipher := cipher.NewCTR(theirBlock, tIV)
255 -
256 - theirMac, macSize := makeMac(hashType, tMKey)
257 -
258 - for {
259 - var data []byte
260 - ok := true
261 -
262 - select {
263 - case <-s.ctx.Done():
264 - ok = false // return out
265 - case data, ok = <-s.insecure.In:
266 - }
267 -
268 - if !ok {
269 - close(s.Duplex.In)
270 - return
271 - }
272 -
273 - // log.Debug("[peer %s] secure in [from = %s] %d", s.local, s.remote, len(data))
274 - if len(data) <= macSize {
275 - continue
276 - }
277 -
278 - mark := len(data) - macSize
279 -
280 - theirMac.Write(data[0:mark])
281 - expected := theirMac.Sum(nil)
282 - theirMac.Reset()
283 -
284 - hmacOk := hmac.Equal(data[mark:], expected)
285 - if !hmacOk {
286 - continue
287 - }
288 -
289 - theirCipher.XORKeyStream(data, data[0:mark])
290 -
291 - s.Duplex.In <- data[:mark]
292 - }
293 -}
294 -
295 -func (s *SecurePipe) handleSecureOut(hashType, cipherType string, mIV, mCKey, mMKey []byte) {
296 - myBlock, err := makeCipher(cipherType, mCKey)
297 - if err != nil {
298 - log.Criticalf("Invalid Cipher: %s", err)
299 - s.cancel()
300 - return
301 - }
302 - myCipher := cipher.NewCTR(myBlock, mIV)
303 -
304 - myMac, macSize := makeMac(hashType, mMKey)
305 -
306 - for {
307 - var data []byte
308 - ok := true
309 -
310 - select {
311 - case <-s.ctx.Done():
312 - ok = false // return out
313 - case data, ok = <-s.Out:
314 - }
315 -
316 - if !ok {
317 - close(s.insecure.Out)
318 - return
319 - }
320 -
321 - if len(data) == 0 {
322 - continue
323 - }
324 -
325 - buff := make([]byte, len(data)+macSize)
326 -
327 - myCipher.XORKeyStream(buff, data)
328 -
329 - myMac.Write(buff[0:len(data)])
330 - copy(buff[len(data):], myMac.Sum(nil))
331 - myMac.Reset()
332 -
333 - // log.Debug("[peer %s] secure out [to = %s] %d", s.local, s.remote, len(buff))
334 - s.insecure.Out <- buff
335 - }
336 -}
337 -
338 -// Determines which algorithm to use. Note: f(a, b) = f(b, a)
339 -func SelectBest(myPrefs, theirPrefs string) (string, error) {
340 - // Person with greatest hash gets first choice.
341 - myHash := u.Hash([]byte(myPrefs))
342 - theirHash := u.Hash([]byte(theirPrefs))
343 -
344 - cmp := bytes.Compare(myHash, theirHash)
345 - var firstChoiceArr, secChoiceArr []string
346 -
347 - if cmp == -1 {
348 - firstChoiceArr = strings.Split(theirPrefs, ",")
349 - secChoiceArr = strings.Split(myPrefs, ",")
350 - } else if cmp == 1 {
351 - firstChoiceArr = strings.Split(myPrefs, ",")
352 - secChoiceArr = strings.Split(theirPrefs, ",")
353 - } else { // Exact same preferences.
354 - myPrefsArr := strings.Split(myPrefs, ",")
355 - return myPrefsArr[0], nil
356 - }
357 -
358 - for _, secChoice := range secChoiceArr {
359 - for _, firstChoice := range firstChoiceArr {
360 - if firstChoice == secChoice {
361 - return firstChoice, nil
362 - }
363 - }
364 - }
365 -
366 - return "", errors.New("No algorithms in common!")
367 -}
368 -
369 -// getOrConstructPeer attempts to fetch a peer from a peerstore.
370 -// if succeeds, verify ID and PubKey match.
371 -// else, construct it.
372 -func getOrConstructPeer(peers peer.Peerstore, rpk ci.PubKey) (peer.Peer, error) {
373 -
374 - rid, err := peer.IDFromPubKey(rpk)
375 - if err != nil {
376 - return nil, err
377 - }
378 -
379 - npeer, err := peers.FindOrCreate(rid)
380 - if err != nil {
381 - return nil, err // unexpected error happened.
382 - }
383 -
384 - // public key verification happens in Peer.VerifyAndSetPubKey
385 - if err := npeer.VerifyAndSetPubKey(rpk); err != nil {
386 - return nil, err // pubkey mismatch or other problem
387 - }
388 - return npeer, nil
389 -}
crypto/spipe/pipe.go deleted
-78
@@ -1,78 +0,0 @@
1 -package spipe
2 -
3 -import (
4 - "errors"
5 -
6 - context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
7 - peer "github.com/jbenet/go-ipfs/peer"
8 -
9 - pipes "github.com/jbenet/go-ipfs/util/pipes"
10 -)
11 -
12 -// SecurePipe objects represent a bi-directional message channel.
13 -type SecurePipe struct {
14 - pipes.Duplex
15 - insecure pipes.Duplex
16 -
17 - local peer.Peer
18 - remote peer.Peer
19 - peers peer.Peerstore
20 -
21 - params params
22 -
23 - ctx context.Context
24 - cancel context.CancelFunc
25 -}
26 -
27 -// options in a secure pipe
28 -type params struct {
29 -}
30 -
31 -// NewSecurePipe constructs a pipe with channels of a given buffer size.
32 -func NewSecurePipe(ctx context.Context, bufsize int, local peer.Peer,
33 - peers peer.Peerstore, insecure pipes.Duplex) (*SecurePipe, error) {
34 -
35 - ctx, cancel := context.WithCancel(ctx)
36 -
37 - sp := &SecurePipe{
38 - Duplex: pipes.Duplex{
39 - In: make(chan []byte, bufsize),
40 - Out: make(chan []byte, bufsize),
41 - },
42 - local: local,
43 - peers: peers,
44 - insecure: insecure,
45 -
46 - ctx: ctx,
47 - cancel: cancel,
48 - }
49 -
50 - if err := sp.handshake(); err != nil {
51 - sp.Close()
52 - return nil, err
53 - }
54 -
55 - return sp, nil
56 -}
57 -
58 -// LocalPeer retrieves the local peer.
59 -func (s *SecurePipe) LocalPeer() peer.Peer {
60 - return s.local
61 -}
62 -
63 -// RemotePeer retrieves the local peer.
64 -func (s *SecurePipe) RemotePeer() peer.Peer {
65 - return s.remote
66 -}
67 -
68 -// Close closes the secure pipe
69 -func (s *SecurePipe) Close() error {
70 - select {
71 - case <-s.ctx.Done():
72 - return errors.New("already closed")
73 - default:
74 - }
75 -
76 - s.cancel()
77 - return nil
78 -}
crypto/spipe/spipe_test.go deleted
-161
@@ -1,161 +0,0 @@
1 -package spipe
2 -
3 -import (
4 - "testing"
5 -
6 - "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
7 -
8 - ci "github.com/jbenet/go-ipfs/crypto"
9 - "github.com/jbenet/go-ipfs/peer"
10 - "github.com/jbenet/go-ipfs/util"
11 - "github.com/jbenet/go-ipfs/util/pipes"
12 - testutil "github.com/jbenet/go-ipfs/util/testutil"
13 -)
14 -
15 -func getPeer(tb testing.TB) peer.Peer {
16 - privk, pubk, err := ci.GenerateKeyPair(ci.RSA, 1024)
17 - if err != nil {
18 - tb.Fatal(err)
19 - }
20 -
21 - p, err := testutil.NewPeerWithKeyPair(privk, pubk)
22 - if err != nil {
23 - tb.Fatal(err)
24 - }
25 -
26 - return p
27 -}
28 -
29 -func bindDuplexNoCopy(a, b pipes.Duplex) {
30 - go func() {
31 - for m := range b.Out {
32 - a.In <- m
33 - }
34 - }()
35 - for m := range a.Out {
36 - b.In <- m
37 - }
38 -}
39 -
40 -var globuf = make([]byte, 4*1024*1024)
41 -
42 -func bindDuplexWithCopy(a, b pipes.Duplex) {
43 - dup := func(byt []byte) []byte {
44 - n := globuf[:len(byt)]
45 - copy(n, byt)
46 - return n
47 - }
48 - go func() {
49 - for m := range b.Out {
50 - a.In <- dup(m)
51 - }
52 - }()
53 - for m := range a.Out {
54 - b.In <- dup(m)
55 - }
56 -}
57 -
58 -func BenchmarkDataEncryptDefault(b *testing.B) {
59 - SupportedExchanges = "P-256,P-224,P-384,P-521"
60 - SupportedCiphers = "AES-256,AES-128"
61 - SupportedHashes = "SHA256,SHA512,SHA1"
62 -
63 - runEncryptBenchmark(b)
64 -}
65 -
66 -func BenchmarkDataEncryptLite(b *testing.B) {
67 - SupportedExchanges = "P-256"
68 - SupportedCiphers = "AES-128"
69 - SupportedHashes = "SHA1"
70 -
71 - runEncryptBenchmark(b)
72 -}
73 -
74 -func BenchmarkDataEncryptBlowfish(b *testing.B) {
75 - SupportedExchanges = "P-256"
76 - SupportedCiphers = "Blowfish"
77 - SupportedHashes = "SHA1"
78 -
79 - runEncryptBenchmark(b)
80 -}
81 -
82 -func runEncryptBenchmark(b *testing.B) {
83 - pstore := peer.NewPeerstore()
84 - ctx := context.TODO()
85 - bufsize := 1024 * 1024
86 -
87 - pa := getPeer(b)
88 - pb := getPeer(b)
89 - duplexa := pipes.NewDuplex(16)
90 - duplexb := pipes.NewDuplex(16)
91 -
92 - go bindDuplexNoCopy(duplexa, duplexb)
93 -
94 - var spb *SecurePipe
95 - done := make(chan struct{})
96 - go func() {
97 - var err error
98 - spb, err = NewSecurePipe(ctx, bufsize, pb, pstore, duplexb)
99 - if err != nil {
100 - b.Fatal(err)
101 - }
102 - done <- struct{}{}
103 - }()
104 -
105 - spa, err := NewSecurePipe(ctx, bufsize, pa, pstore, duplexa)
106 - if err != nil {
107 - b.Fatal(err)
108 - }
109 -
110 - <-done
111 -
112 - go func() {
113 - for _ = range spa.In {
114 - // Throw it all away,
115 - // all of your hopes and dreams
116 - // piped out to /dev/null...
117 - done <- struct{}{}
118 - }
119 - }()
120 -
121 - data := make([]byte, 1024*512)
122 - util.NewTimeSeededRand().Read(data)
123 - // Begin actual benchmarking
124 - b.ResetTimer()
125 -
126 - for i := 0; i < b.N; i++ {
127 - b.SetBytes(int64(len(data)))
128 - spb.Out <- data
129 - <-done
130 - }
131 -
132 -}
133 -
134 -func BenchmarkDataTransfer(b *testing.B) {
135 - duplexa := pipes.NewDuplex(16)
136 - duplexb := pipes.NewDuplex(16)
137 -
138 - go bindDuplexWithCopy(duplexa, duplexb)
139 -
140 - done := make(chan struct{})
141 - go func() {
142 - for _ = range duplexa.In {
143 - // Throw it all away,
144 - // all of your hopes and dreams
145 - // piped out to /dev/null...
146 - done <- struct{}{}
147 - }
148 - }()
149 -
150 - data := make([]byte, 1024*512)
151 - util.NewTimeSeededRand().Read(data)
152 - // Begin actual benchmarking
153 - b.ResetTimer()
154 -
155 - for i := 0; i < b.N; i++ {
156 - b.SetBytes(int64(len(data)))
157 - duplexb.Out <- data
158 - <-done
159 - }
160 -
161 -}
diagnostics/diag.go
+12 -12
@@ -13,8 +13,8 @@ import (
13
14 "crypto/rand"
15
16 - ggio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/io"
16 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
17 + ggio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/io"
18 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
19
20 pb "github.com/jbenet/go-ipfs/diagnostics/internal/pb"
@@ -31,7 +31,7 @@ const ResponseTimeout = time.Second * 10
31 // requests
32 type Diagnostics struct {
33 network net.Network
34 - self peer.Peer
34 + self peer.ID
35
36 diagLock sync.Mutex
37 diagMap map[string]time.Time
@@ -39,7 +39,7 @@ type Diagnostics struct {
39 }
40
41 // NewDiagnostics instantiates a new diagnostics service running on the given network
42 -func NewDiagnostics(self peer.Peer, inet net.Network) *Diagnostics {
42 +func NewDiagnostics(self peer.ID, inet net.Network) *Diagnostics {
43 d := &Diagnostics{
44 network: inet,
45 self: self,
@@ -91,20 +91,20 @@ func (di *DiagInfo) Marshal() []byte {
91 return b
92 }
93
94 -func (d *Diagnostics) getPeers() []peer.Peer {
94 +func (d *Diagnostics) getPeers() []peer.ID {
95 return d.network.Peers()
96 }
97
98 func (d *Diagnostics) getDiagInfo() *DiagInfo {
99 di := new(DiagInfo)
100 di.CodeVersion = "github.com/jbenet/go-ipfs"
101 - di.ID = d.self.ID().Pretty()
101 + di.ID = d.self.Pretty()
102 di.LifeSpan = time.Since(d.birth)
103 di.Keys = nil // Currently no way to query datastore
104 di.BwIn, di.BwOut = d.network.BandwidthTotals()
105
106 for _, p := range d.getPeers() {
107 - d := connDiagInfo{p.GetLatency(), p.ID().Pretty()}
107 + d := connDiagInfo{d.network.Peerstore().LatencyEWMA(p), p.Pretty()}
108 di.Connections = append(di.Connections, d)
109 }
110 return di
@@ -142,7 +142,7 @@ func (d *Diagnostics) GetDiagnostic(timeout time.Duration) ([]*DiagInfo, error)
142 for _, p := range peers {
143 log.Debugf("Sending getDiagnostic to: %s", p)
144 sends++
145 - go func(p peer.Peer) {
145 + go func(p peer.ID) {
146 data, err := d.getDiagnosticFromPeer(ctx, p, pmes)
147 if err != nil {
148 log.Errorf("GetDiagnostic error: %v", err)
@@ -181,7 +181,7 @@ func appendDiagnostics(data []byte, cur []*DiagInfo) []*DiagInfo {
181 }
182
183 // TODO: this method no longer needed.
184 -func (d *Diagnostics) getDiagnosticFromPeer(ctx context.Context, p peer.Peer, mes *pb.Message) ([]byte, error) {
184 +func (d *Diagnostics) getDiagnosticFromPeer(ctx context.Context, p peer.ID, mes *pb.Message) ([]byte, error) {
185 rpmes, err := d.sendRequest(ctx, p, mes)
186 if err != nil {
187 return nil, err
@@ -195,7 +195,7 @@ func newMessage(diagID string) *pb.Message {
195 return pmes
196 }
197
198 -func (d *Diagnostics) sendRequest(ctx context.Context, p peer.Peer, pmes *pb.Message) (*pb.Message, error) {
198 +func (d *Diagnostics) sendRequest(ctx context.Context, p peer.ID, pmes *pb.Message) (*pb.Message, error) {
199
200 s, err := d.network.NewStream(net.ProtocolDiag, p)
201 if err != nil {
@@ -225,7 +225,7 @@ func (d *Diagnostics) sendRequest(ctx context.Context, p peer.Peer, pmes *pb.Mes
225 return rpmes, nil
226 }
227
228 -func (d *Diagnostics) handleDiagnostic(p peer.Peer, pmes *pb.Message) (*pb.Message, error) {
228 +func (d *Diagnostics) handleDiagnostic(p peer.ID, pmes *pb.Message) (*pb.Message, error) {
229 log.Debugf("HandleDiagnostic from %s for id = %s", p, pmes.GetDiagID())
230 resp := newMessage(pmes.GetDiagID())
231
@@ -250,7 +250,7 @@ func (d *Diagnostics) handleDiagnostic(p peer.Peer, pmes *pb.Message) (*pb.Messa
250 for _, p := range d.getPeers() {
251 log.Debugf("Sending diagnostic request to peer: %s", p)
252 sendcount++
253 - go func(p peer.Peer) {
253 + go func(p peer.ID) {
254 out, err := d.getDiagnosticFromPeer(ctx, p, pmes)
255 if err != nil {
256 log.Errorf("getDiagnostic error: %v", err)
@@ -288,7 +288,7 @@ func (d *Diagnostics) HandleMessage(ctx context.Context, s net.Stream) error {
288
289 // Print out diagnostic
290 log.Infof("[peer: %s] Got message from [%s]\n",
291 - d.self.ID().Pretty(), s.Conn().RemotePeer().ID().Pretty())
291 + d.self.Pretty(), s.Conn().RemotePeer())
292
293 // dispatch handler.
294 p := s.Conn().RemotePeer()
exchange/bitswap/bitswap.go
+15 -14
@@ -8,6 +8,7 @@ import (
8 "time"
9
10 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
11 +
12 blocks "github.com/jbenet/go-ipfs/blocks"
13 blockstore "github.com/jbenet/go-ipfs/blocks/blockstore"
14 exchange "github.com/jbenet/go-ipfs/exchange"
@@ -43,7 +44,7 @@ var (
44 // BitSwapNetwork. This function registers the returned instance as the network
45 // delegate.
46 // Runs until context is cancelled.
46 -func New(parent context.Context, p peer.Peer, network bsnet.BitSwapNetwork, routing bsnet.Routing,
47 +func New(parent context.Context, p peer.ID, network bsnet.BitSwapNetwork, routing bsnet.Routing,
48 bstore blockstore.Blockstore, nice bool) exchange.Interface {
49
50 ctx, cancelFunc := context.WithCancel(parent)
@@ -165,7 +166,7 @@ func (bs *bitswap) HasBlock(ctx context.Context, blk *blocks.Block) error {
166 return bs.routing.Provide(ctx, blk.Key())
167 }
168
168 -func (bs *bitswap) sendWantListTo(ctx context.Context, peers <-chan peer.Peer) error {
169 +func (bs *bitswap) sendWantListTo(ctx context.Context, peers <-chan peer.PeerInfo) error {
170 if peers == nil {
171 panic("Cant send wantlist to nil peerchan")
172 }
@@ -175,9 +176,9 @@ func (bs *bitswap) sendWantListTo(ctx context.Context, peers <-chan peer.Peer) e
176 }
177 wg := sync.WaitGroup{}
178 for peerToQuery := range peers {
178 - log.Event(ctx, "PeerToQuery", peerToQuery)
179 + log.Event(ctx, "PeerToQuery", peerToQuery.ID)
180 wg.Add(1)
180 - go func(p peer.Peer) {
181 + go func(p peer.ID) {
182 defer wg.Done()
183
184 log.Event(ctx, "DialPeer", p)
@@ -196,7 +197,7 @@ func (bs *bitswap) sendWantListTo(ctx context.Context, peers <-chan peer.Peer) e
197 // communication fails. May require slightly different API to
198 // get better guarantees. May need shared sequence numbers.
199 bs.engine.MessageSent(p, message)
199 - }(peerToQuery)
200 + }(peerToQuery.ID)
201 }
202 wg.Wait()
203 return nil
@@ -224,8 +225,8 @@ func (bs *bitswap) sendWantlistToProviders(ctx context.Context, wantlist *wantli
225 providers := bs.routing.FindProvidersAsync(child, k, maxProvidersPerRequest)
226
227 for prov := range providers {
227 - if ps.TryAdd(prov) { //Do once per peer
228 - bs.send(ctx, prov, message)
228 + if ps.TryAdd(prov.ID) { //Do once per peer
229 + bs.send(ctx, prov.ID, message)
230 }
231 }
232 }(e.Key)
@@ -287,19 +288,19 @@ func (bs *bitswap) clientWorker(parent context.Context) {
288 }
289
290 // TODO(brian): handle errors
290 -func (bs *bitswap) ReceiveMessage(ctx context.Context, p peer.Peer, incoming bsmsg.BitSwapMessage) (
291 - peer.Peer, bsmsg.BitSwapMessage) {
291 +func (bs *bitswap) ReceiveMessage(ctx context.Context, p peer.ID, incoming bsmsg.BitSwapMessage) (
292 + peer.ID, bsmsg.BitSwapMessage) {
293 log.Debugf("ReceiveMessage from %s", p)
294
294 - if p == nil {
295 + if p == "" {
296 log.Error("Received message from nil peer!")
297 // TODO propagate the error upward
297 - return nil, nil
298 + return "", nil
299 }
300 if incoming == nil {
301 log.Error("Got nil bitswap message!")
302 // TODO propagate the error upward
302 - return nil, nil
303 + return "", nil
304 }
305
306 // This call records changes to wantlists, blocks received,
@@ -321,7 +322,7 @@ func (bs *bitswap) ReceiveMessage(ctx context.Context, p peer.Peer, incoming bsm
322 bs.cancelBlocks(ctx, keys)
323
324 // TODO: consider changing this function to not return anything
324 - return nil, nil
325 + return "", nil
326 }
327
328 func (bs *bitswap) cancelBlocks(ctx context.Context, bkeys []u.Key) {
@@ -349,7 +350,7 @@ func (bs *bitswap) ReceiveError(err error) {
350
351 // send strives to ensure that accounting is always performed when a message is
352 // sent
352 -func (bs *bitswap) send(ctx context.Context, p peer.Peer, m bsmsg.BitSwapMessage) error {
353 +func (bs *bitswap) send(ctx context.Context, p peer.ID, m bsmsg.BitSwapMessage) error {
354 if err := bs.sender.SendMessage(ctx, p, m); err != nil {
355 return err
356 }
exchange/bitswap/bitswap_test.go
+5 -3
@@ -7,13 +7,14 @@ import (
7 "time"
8
9 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
10 +
11 blocks "github.com/jbenet/go-ipfs/blocks"
12 blocksutil "github.com/jbenet/go-ipfs/blocks/blocksutil"
13 tn "github.com/jbenet/go-ipfs/exchange/bitswap/testnet"
14 + peer "github.com/jbenet/go-ipfs/peer"
15 mockrouting "github.com/jbenet/go-ipfs/routing/mock"
16 u "github.com/jbenet/go-ipfs/util"
17 delay "github.com/jbenet/go-ipfs/util/delay"
16 - testutil "github.com/jbenet/go-ipfs/util/testutil"
18 )
19
20 // FIXME the tests are really sensitive to the network delay. fix them to work
@@ -62,7 +63,8 @@ func TestProviderForKeyButNetworkCannotFind(t *testing.T) {
63 defer g.Close()
64
65 block := blocks.NewBlock([]byte("block"))
65 - rs.Client(testutil.NewPeerWithIDString("testing")).Provide(context.Background(), block.Key()) // but not on network
66 + pinfo := peer.PeerInfo{ID: peer.ID("testing")}
67 + rs.Client(pinfo).Provide(context.Background(), block.Key()) // but not on network
68
69 solo := g.Next()
70 defer solo.Exchange.Close()
@@ -153,7 +155,7 @@ func PerformDistributionTest(t *testing.T, numInstances, numBlocks int) {
155 first.Blockstore().Put(b)
156 blkeys = append(blkeys, b.Key())
157 first.Exchange.HasBlock(context.Background(), b)
156 - rs.Client(first.Peer).Provide(context.Background(), b.Key())
158 + rs.Client(peer.PeerInfo{ID: first.Peer}).Provide(context.Background(), b.Key())
159 }
160
161 t.Log("Distribute!")
exchange/bitswap/decision/engine.go
+12 -12
@@ -50,7 +50,7 @@ const (
50 // Envelope contains a message for a Peer
51 type Envelope struct {
52 // Peer is the intended recipient
53 - Peer peer.Peer
53 + Peer peer.ID
54 // Message is the payload
55 Message bsmsg.BitSwapMessage
56 }
@@ -75,12 +75,12 @@ type Engine struct {
75
76 lock sync.RWMutex // protects the fields immediatly below
77 // ledgerMap lists Ledgers by their Partner key.
78 - ledgerMap map[u.Key]*ledger
78 + ledgerMap map[peer.ID]*ledger
79 }
80
81 func NewEngine(ctx context.Context, bs bstore.Blockstore) *Engine {
82 e := &Engine{
83 - ledgerMap: make(map[u.Key]*ledger),
83 + ledgerMap: make(map[peer.ID]*ledger),
84 bs: bs,
85 peerRequestQueue: newTaskQueue(),
86 outbox: make(chan Envelope, sizeOutboxChan),
@@ -126,11 +126,11 @@ func (e *Engine) Outbox() <-chan Envelope {
126 }
127
128 // Returns a slice of Peers with whom the local node has active sessions
129 -func (e *Engine) Peers() []peer.Peer {
129 +func (e *Engine) Peers() []peer.ID {
130 e.lock.RLock()
131 defer e.lock.RUnlock()
132
133 - response := make([]peer.Peer, 0)
133 + response := make([]peer.ID, 0)
134 for _, ledger := range e.ledgerMap {
135 response = append(response, ledger.Partner)
136 }
@@ -139,7 +139,7 @@ func (e *Engine) Peers() []peer.Peer {
139
140 // MessageReceived performs book-keeping. Returns error if passed invalid
141 // arguments.
142 -func (e *Engine) MessageReceived(p peer.Peer, m bsmsg.BitSwapMessage) error {
142 +func (e *Engine) MessageReceived(p peer.ID, m bsmsg.BitSwapMessage) error {
143 newWorkExists := false
144 defer func() {
145 if newWorkExists {
@@ -189,7 +189,7 @@ func (e *Engine) MessageReceived(p peer.Peer, m bsmsg.BitSwapMessage) error {
189 // inconsistent. Would need to ensure that Sends and acknowledgement of the
190 // send happen atomically
191
192 -func (e *Engine) MessageSent(p peer.Peer, m bsmsg.BitSwapMessage) error {
192 +func (e *Engine) MessageSent(p peer.ID, m bsmsg.BitSwapMessage) error {
193 e.lock.Lock()
194 defer e.lock.Unlock()
195
@@ -203,22 +203,22 @@ func (e *Engine) MessageSent(p peer.Peer, m bsmsg.BitSwapMessage) error {
203 return nil
204 }
205
206 -func (e *Engine) numBytesSentTo(p peer.Peer) uint64 {
206 +func (e *Engine) numBytesSentTo(p peer.ID) uint64 {
207 // NB not threadsafe
208 return e.findOrCreate(p).Accounting.BytesSent
209 }
210
211 -func (e *Engine) numBytesReceivedFrom(p peer.Peer) uint64 {
211 +func (e *Engine) numBytesReceivedFrom(p peer.ID) uint64 {
212 // NB not threadsafe
213 return e.findOrCreate(p).Accounting.BytesRecv
214 }
215
216 // ledger lazily instantiates a ledger
217 -func (e *Engine) findOrCreate(p peer.Peer) *ledger {
218 - l, ok := e.ledgerMap[p.Key()]
217 +func (e *Engine) findOrCreate(p peer.ID) *ledger {
218 + l, ok := e.ledgerMap[p]
219 if !ok {
220 l = newLedger(p)
221 - e.ledgerMap[p.Key()] = l
221 + e.ledgerMap[p] = l
222 }
223 return l
224 }
exchange/bitswap/decision/engine_test.go
+6 -6
@@ -7,21 +7,21 @@ import (
7 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
8 ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
9 sync "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync"
10 +
11 blocks "github.com/jbenet/go-ipfs/blocks"
12 blockstore "github.com/jbenet/go-ipfs/blocks/blockstore"
13 message "github.com/jbenet/go-ipfs/exchange/bitswap/message"
14 peer "github.com/jbenet/go-ipfs/peer"
14 - testutil "github.com/jbenet/go-ipfs/util/testutil"
15 )
16
17 type peerAndEngine struct {
18 - peer.Peer
18 + Peer peer.ID
19 Engine *Engine
20 }
21
22 func newPeerAndLedgermanager(idStr string) peerAndEngine {
23 return peerAndEngine{
24 - Peer: testutil.NewPeerWithIDString(idStr),
24 + Peer: peer.ID(idStr),
25 //Strategy: New(true),
26 Engine: NewEngine(context.TODO(),
27 blockstore.NewBlockstore(sync.MutexWrap(ds.NewMapDatastore()))),
@@ -70,7 +70,7 @@ func TestPeerIsAddedToPeersWhenMessageReceivedOrSent(t *testing.T) {
70 sanfrancisco.Engine.MessageSent(seattle.Peer, m)
71 seattle.Engine.MessageReceived(sanfrancisco.Peer, m)
72
73 - if seattle.Peer.Key() == sanfrancisco.Peer.Key() {
73 + if seattle.Peer == sanfrancisco.Peer {
74 t.Fatal("Sanity Check: Peers have same Key!")
75 }
76
@@ -83,9 +83,9 @@ func TestPeerIsAddedToPeersWhenMessageReceivedOrSent(t *testing.T) {
83 }
84 }
85
86 -func peerIsPartner(p peer.Peer, e *Engine) bool {
86 +func peerIsPartner(p peer.ID, e *Engine) bool {
87 for _, partner := range e.Peers() {
88 - if partner.Key() == p.Key() {
88 + if partner == p {
89 return true
90 }
91 }
exchange/bitswap/decision/ledger.go
+2 -2
@@ -12,7 +12,7 @@ import (
12 // access/lookups.
13 type keySet map[u.Key]struct{}
14
15 -func newLedger(p peer.Peer) *ledger {
15 +func newLedger(p peer.ID) *ledger {
16 return &ledger{
17 wantList: wl.New(),
18 Partner: p,
@@ -24,7 +24,7 @@ func newLedger(p peer.Peer) *ledger {
24 // NOT threadsafe
25 type ledger struct {
26 // Partner is the remote Peer.
27 - Partner peer.Peer
27 + Partner peer.ID
28
29 // Accounting tracks bytes sent and recieved.
30 Accounting debtRatio
exchange/bitswap/decision/taskqueue.go
+5 -5
@@ -26,12 +26,12 @@ func newTaskQueue() *taskQueue {
26
27 type task struct {
28 Entry wantlist.Entry
29 - Target peer.Peer
29 + Target peer.ID
30 Trash bool
31 }
32
33 // Push currently adds a new task to the end of the list
34 -func (tl *taskQueue) Push(entry wantlist.Entry, to peer.Peer) {
34 +func (tl *taskQueue) Push(entry wantlist.Entry, to peer.ID) {
35 tl.lock.Lock()
36 defer tl.lock.Unlock()
37 if task, ok := tl.taskmap[taskKey(to, entry.Key)]; ok {
@@ -69,7 +69,7 @@ func (tl *taskQueue) Pop() *task {
69 }
70
71 // Remove lazily removes a task from the queue
72 -func (tl *taskQueue) Remove(k u.Key, p peer.Peer) {
72 +func (tl *taskQueue) Remove(k u.Key, p peer.ID) {
73 tl.lock.Lock()
74 t, ok := tl.taskmap[taskKey(p, k)]
75 if ok {
@@ -79,6 +79,6 @@ func (tl *taskQueue) Remove(k u.Key, p peer.Peer) {
79 }
80
81 // taskKey returns a key that uniquely identifies a task.
82 -func taskKey(p peer.Peer, k u.Key) string {
83 - return string(p.Key() + k)
82 +func taskKey(p peer.ID, k u.Key) string {
83 + return string(p) + string(k)
84 }
exchange/bitswap/network/interface.go
+6 -6
@@ -12,18 +12,18 @@ import (
12 type BitSwapNetwork interface {
13
14 // DialPeer ensures there is a connection to peer.
15 - DialPeer(context.Context, peer.Peer) error
15 + DialPeer(context.Context, peer.ID) error
16
17 // SendMessage sends a BitSwap message to a peer.
18 SendMessage(
19 context.Context,
20 - peer.Peer,
20 + peer.ID,
21 bsmsg.BitSwapMessage) error
22
23 // SendRequest sends a BitSwap message to a peer and waits for a response.
24 SendRequest(
25 context.Context,
26 - peer.Peer,
26 + peer.ID,
27 bsmsg.BitSwapMessage) (incoming bsmsg.BitSwapMessage, err error)
28
29 // SetDelegate registers the Reciver to handle messages received from the
@@ -34,15 +34,15 @@ type BitSwapNetwork interface {
34 // Implement Receiver to receive messages from the BitSwapNetwork
35 type Receiver interface {
36 ReceiveMessage(
37 - ctx context.Context, sender peer.Peer, incoming bsmsg.BitSwapMessage) (
38 - destination peer.Peer, outgoing bsmsg.BitSwapMessage)
37 + ctx context.Context, sender peer.ID, incoming bsmsg.BitSwapMessage) (
38 + destination peer.ID, outgoing bsmsg.BitSwapMessage)
39
40 ReceiveError(error)
41 }
42
43 type Routing interface {
44 // FindProvidersAsync returns a channel of providers for the given key
45 - FindProvidersAsync(context.Context, u.Key, int) <-chan peer.Peer
45 + FindProvidersAsync(context.Context, u.Key, int) <-chan peer.PeerInfo
46
47 // Provide provides the key to the network
48 Provide(context.Context, u.Key) error
exchange/bitswap/network/ipfs_impl.go
+3 -3
@@ -53,13 +53,13 @@ func (bsnet *impl) handleNewStream(s inet.Stream) {
53
54 }
55
56 -func (bsnet *impl) DialPeer(ctx context.Context, p peer.Peer) error {
56 +func (bsnet *impl) DialPeer(ctx context.Context, p peer.ID) error {
57 return bsnet.network.DialPeer(ctx, p)
58 }
59
60 func (bsnet *impl) SendMessage(
61 ctx context.Context,
62 - p peer.Peer,
62 + p peer.ID,
63 outgoing bsmsg.BitSwapMessage) error {
64
65 s, err := bsnet.network.NewStream(inet.ProtocolBitswap, p)
@@ -73,7 +73,7 @@ func (bsnet *impl) SendMessage(
73
74 func (bsnet *impl) SendRequest(
75 ctx context.Context,
76 - p peer.Peer,
76 + p peer.ID,
77 outgoing bsmsg.BitSwapMessage) (bsmsg.BitSwapMessage, error) {
78
79 s, err := bsnet.network.NewStream(inet.ProtocolBitswap, p)
exchange/bitswap/testnet/network.go
+32 -33
@@ -1,33 +1,32 @@
1 package bitswap
2
3 import (
4 - "bytes"
4 "errors"
5 "fmt"
6
7 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
8 +
9 bsmsg "github.com/jbenet/go-ipfs/exchange/bitswap/message"
10 bsnet "github.com/jbenet/go-ipfs/exchange/bitswap/network"
11 peer "github.com/jbenet/go-ipfs/peer"
12 - "github.com/jbenet/go-ipfs/util"
12 delay "github.com/jbenet/go-ipfs/util/delay"
13 )
14
15 type Network interface {
17 - Adapter(peer.Peer) bsnet.BitSwapNetwork
16 + Adapter(peer.ID) bsnet.BitSwapNetwork
17
19 - HasPeer(peer.Peer) bool
18 + HasPeer(peer.ID) bool
19
20 SendMessage(
21 ctx context.Context,
23 - from peer.Peer,
24 - to peer.Peer,
22 + from peer.ID,
23 + to peer.ID,
24 message bsmsg.BitSwapMessage) error
25
26 SendRequest(
27 ctx context.Context,
29 - from peer.Peer,
30 - to peer.Peer,
28 + from peer.ID,
29 + to peer.ID,
30 message bsmsg.BitSwapMessage) (
31 incoming bsmsg.BitSwapMessage, err error)
32 }
@@ -36,27 +35,27 @@ type Network interface {
35
36 func VirtualNetwork(d delay.D) Network {
37 return &network{
39 - clients: make(map[util.Key]bsnet.Receiver),
38 + clients: make(map[peer.ID]bsnet.Receiver),
39 delay: d,
40 }
41 }
42
43 type network struct {
45 - clients map[util.Key]bsnet.Receiver
44 + clients map[peer.ID]bsnet.Receiver
45 delay delay.D
46 }
47
49 -func (n *network) Adapter(p peer.Peer) bsnet.BitSwapNetwork {
48 +func (n *network) Adapter(p peer.ID) bsnet.BitSwapNetwork {
49 client := &networkClient{
50 local: p,
51 network: n,
52 }
54 - n.clients[p.Key()] = client
53 + n.clients[p] = client
54 return client
55 }
56
58 -func (n *network) HasPeer(p peer.Peer) bool {
59 - _, found := n.clients[p.Key()]
57 +func (n *network) HasPeer(p peer.ID) bool {
58 + _, found := n.clients[p]
59 return found
60 }
61
@@ -64,11 +63,11 @@ func (n *network) HasPeer(p peer.Peer) bool {
63 // TODO what does the network layer do with errors received from services?
64 func (n *network) SendMessage(
65 ctx context.Context,
67 - from peer.Peer,
68 - to peer.Peer,
66 + from peer.ID,
67 + to peer.ID,
68 message bsmsg.BitSwapMessage) error {
69
71 - receiver, ok := n.clients[to.Key()]
70 + receiver, ok := n.clients[to]
71 if !ok {
72 return errors.New("Cannot locate peer on network")
73 }
@@ -82,8 +81,8 @@ func (n *network) SendMessage(
81 }
82
83 func (n *network) deliver(
85 - r bsnet.Receiver, from peer.Peer, message bsmsg.BitSwapMessage) error {
86 - if message == nil || from == nil {
84 + r bsnet.Receiver, from peer.ID, message bsmsg.BitSwapMessage) error {
85 + if message == nil || from == "" {
86 return errors.New("Invalid input")
87 }
88
@@ -91,15 +90,15 @@ func (n *network) deliver(
90
91 nextPeer, nextMsg := r.ReceiveMessage(context.TODO(), from, message)
92
94 - if (nextPeer == nil && nextMsg != nil) || (nextMsg == nil && nextPeer != nil) {
93 + if (nextPeer == "" && nextMsg != nil) || (nextMsg == nil && nextPeer != "") {
94 return errors.New("Malformed client request")
95 }
96
98 - if nextPeer == nil && nextMsg == nil { // no response to send
97 + if nextPeer == "" && nextMsg == nil { // no response to send
98 return nil
99 }
100
102 - nextReceiver, ok := n.clients[nextPeer.Key()]
101 + nextReceiver, ok := n.clients[nextPeer]
102 if !ok {
103 return errors.New("Cannot locate peer on network")
104 }
@@ -110,32 +109,32 @@ func (n *network) deliver(
109 // TODO
110 func (n *network) SendRequest(
111 ctx context.Context,
113 - from peer.Peer,
114 - to peer.Peer,
112 + from peer.ID,
113 + to peer.ID,
114 message bsmsg.BitSwapMessage) (
115 incoming bsmsg.BitSwapMessage, err error) {
116
118 - r, ok := n.clients[to.Key()]
117 + r, ok := n.clients[to]
118 if !ok {
119 return nil, errors.New("Cannot locate peer on network")
120 }
121 nextPeer, nextMsg := r.ReceiveMessage(context.TODO(), from, message)
122
123 // TODO dedupe code
125 - if (nextPeer == nil && nextMsg != nil) || (nextMsg == nil && nextPeer != nil) {
124 + if (nextPeer == "" && nextMsg != nil) || (nextMsg == nil && nextPeer != "") {
125 r.ReceiveError(errors.New("Malformed client request"))
126 return nil, nil
127 }
128
129 // TODO dedupe code
131 - if nextPeer == nil && nextMsg == nil {
130 + if nextPeer == "" && nextMsg == nil {
131 return nil, nil
132 }
133
134 // TODO test when receiver doesn't immediately respond to the initiator of the request
136 - if !bytes.Equal(nextPeer.ID(), from.ID()) {
135 + if nextPeer != from {
136 go func() {
138 - nextReceiver, ok := n.clients[nextPeer.Key()]
137 + nextReceiver, ok := n.clients[nextPeer]
138 if !ok {
139 // TODO log the error?
140 }
@@ -147,26 +146,26 @@ func (n *network) SendRequest(
146 }
147
148 type networkClient struct {
150 - local peer.Peer
149 + local peer.ID
150 bsnet.Receiver
151 network Network
152 }
153
154 func (nc *networkClient) SendMessage(
155 ctx context.Context,
157 - to peer.Peer,
156 + to peer.ID,
157 message bsmsg.BitSwapMessage) error {
158 return nc.network.SendMessage(ctx, nc.local, to, message)
159 }
160
161 func (nc *networkClient) SendRequest(
162 ctx context.Context,
164 - to peer.Peer,
163 + to peer.ID,
164 message bsmsg.BitSwapMessage) (incoming bsmsg.BitSwapMessage, err error) {
165 return nc.network.SendRequest(ctx, nc.local, to, message)
166 }
167
169 -func (nc *networkClient) DialPeer(ctx context.Context, p peer.Peer) error {
168 +func (nc *networkClient) DialPeer(ctx context.Context, p peer.ID) error {
169 // no need to do anything because dialing isn't a thing in this test net.
170 if !nc.network.HasPeer(p) {
171 return fmt.Errorf("Peer not in network: %s", p)
exchange/bitswap/testnet/network_test.go
+26 -22
@@ -5,30 +5,30 @@ import (
5 "testing"
6
7 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
8 +
9 blocks "github.com/jbenet/go-ipfs/blocks"
10 bsmsg "github.com/jbenet/go-ipfs/exchange/bitswap/message"
11 bsnet "github.com/jbenet/go-ipfs/exchange/bitswap/network"
12 peer "github.com/jbenet/go-ipfs/peer"
13 delay "github.com/jbenet/go-ipfs/util/delay"
13 - testutil "github.com/jbenet/go-ipfs/util/testutil"
14 )
15
16 func TestSendRequestToCooperativePeer(t *testing.T) {
17 net := VirtualNetwork(delay.Fixed(0))
18
19 - idOfRecipient := []byte("recipient")
19 + idOfRecipient := peer.ID("recipient")
20
21 t.Log("Get two network adapters")
22
23 - initiator := net.Adapter(testutil.NewPeerWithIDString("initiator"))
24 - recipient := net.Adapter(testutil.NewPeerWithID(idOfRecipient))
23 + initiator := net.Adapter(peer.ID("initiator"))
24 + recipient := net.Adapter(idOfRecipient)
25
26 expectedStr := "response from recipient"
27 recipient.SetDelegate(lambda(func(
28 ctx context.Context,
29 - from peer.Peer,
29 + from peer.ID,
30 incoming bsmsg.BitSwapMessage) (
31 - peer.Peer, bsmsg.BitSwapMessage) {
31 + peer.ID, bsmsg.BitSwapMessage) {
32
33 t.Log("Recipient received a message from the network")
34
@@ -45,13 +45,17 @@ func TestSendRequestToCooperativePeer(t *testing.T) {
45 message := bsmsg.New()
46 message.AddBlock(blocks.NewBlock([]byte("data")))
47 response, err := initiator.SendRequest(
48 - context.Background(), testutil.NewPeerWithID(idOfRecipient), message)
48 + context.Background(), idOfRecipient, message)
49 if err != nil {
50 t.Fatal(err)
51 }
52
53 t.Log("Check the contents of the response from recipient")
54
55 + if response == nil {
56 + t.Fatal("Should have received a response")
57 + }
58 +
59 for _, blockFromRecipient := range response.Blocks() {
60 if string(blockFromRecipient.Data) == expectedStr {
61 return
@@ -62,9 +66,9 @@ func TestSendRequestToCooperativePeer(t *testing.T) {
66
67 func TestSendMessageAsyncButWaitForResponse(t *testing.T) {
68 net := VirtualNetwork(delay.Fixed(0))
65 - idOfResponder := []byte("responder")
66 - waiter := net.Adapter(testutil.NewPeerWithIDString("waiter"))
67 - responder := net.Adapter(testutil.NewPeerWithID(idOfResponder))
69 + idOfResponder := peer.ID("responder")
70 + waiter := net.Adapter(peer.ID("waiter"))
71 + responder := net.Adapter(idOfResponder)
72
73 var wg sync.WaitGroup
74
@@ -74,9 +78,9 @@ func TestSendMessageAsyncButWaitForResponse(t *testing.T) {
78
79 responder.SetDelegate(lambda(func(
80 ctx context.Context,
77 - fromWaiter peer.Peer,
81 + fromWaiter peer.ID,
82 msgFromWaiter bsmsg.BitSwapMessage) (
79 - peer.Peer, bsmsg.BitSwapMessage) {
83 + peer.ID, bsmsg.BitSwapMessage) {
84
85 msgToWaiter := bsmsg.New()
86 msgToWaiter.AddBlock(blocks.NewBlock([]byte(expectedStr)))
@@ -86,9 +90,9 @@ func TestSendMessageAsyncButWaitForResponse(t *testing.T) {
90
91 waiter.SetDelegate(lambda(func(
92 ctx context.Context,
89 - fromResponder peer.Peer,
93 + fromResponder peer.ID,
94 msgFromResponder bsmsg.BitSwapMessage) (
91 - peer.Peer, bsmsg.BitSwapMessage) {
95 + peer.ID, bsmsg.BitSwapMessage) {
96
97 // TODO assert that this came from the correct peer and that the message contents are as expected
98 ok := false
@@ -103,13 +107,13 @@ func TestSendMessageAsyncButWaitForResponse(t *testing.T) {
107 t.Fatal("Message not received from the responder")
108
109 }
106 - return nil, nil
110 + return "", nil
111 }))
112
113 messageSentAsync := bsmsg.New()
114 messageSentAsync.AddBlock(blocks.NewBlock([]byte("data")))
115 errSending := waiter.SendMessage(
112 - context.Background(), testutil.NewPeerWithID(idOfResponder), messageSentAsync)
116 + context.Background(), idOfResponder, messageSentAsync)
117 if errSending != nil {
118 t.Fatal(errSending)
119 }
@@ -117,8 +121,8 @@ func TestSendMessageAsyncButWaitForResponse(t *testing.T) {
121 wg.Wait() // until waiter delegate function is executed
122 }
123
120 -type receiverFunc func(ctx context.Context, p peer.Peer,
121 - incoming bsmsg.BitSwapMessage) (peer.Peer, bsmsg.BitSwapMessage)
124 +type receiverFunc func(ctx context.Context, p peer.ID,
125 + incoming bsmsg.BitSwapMessage) (peer.ID, bsmsg.BitSwapMessage)
126
127 // lambda returns a Receiver instance given a receiver function
128 func lambda(f receiverFunc) bsnet.Receiver {
@@ -128,13 +132,13 @@ func lambda(f receiverFunc) bsnet.Receiver {
132 }
133
134 type lambdaImpl struct {
131 - f func(ctx context.Context, p peer.Peer, incoming bsmsg.BitSwapMessage) (
132 - peer.Peer, bsmsg.BitSwapMessage)
135 + f func(ctx context.Context, p peer.ID, incoming bsmsg.BitSwapMessage) (
136 + peer.ID, bsmsg.BitSwapMessage)
137 }
138
139 func (lam *lambdaImpl) ReceiveMessage(ctx context.Context,
136 - p peer.Peer, incoming bsmsg.BitSwapMessage) (
137 - peer.Peer, bsmsg.BitSwapMessage) {
140 + p peer.ID, incoming bsmsg.BitSwapMessage) (
141 + peer.ID, bsmsg.BitSwapMessage) {
142 return lam.f(ctx, p, incoming)
143 }
144
exchange/bitswap/testutils.go
+4 -5
@@ -44,7 +44,7 @@ func (g *SessionGenerator) Close() error {
44
45 func (g *SessionGenerator) Next() Instance {
46 g.seq++
47 - return session(g.ctx, g.net, g.rs, g.ps, []byte(string(g.seq)))
47 + return session(g.ctx, g.net, g.rs, g.ps, peer.ID(g.seq))
48 }
49
50 func (g *SessionGenerator) Instances(n int) []Instance {
@@ -57,7 +57,7 @@ func (g *SessionGenerator) Instances(n int) []Instance {
57 }
58
59 type Instance struct {
60 - Peer peer.Peer
60 + Peer peer.ID
61 Exchange exchange.Interface
62 blockstore blockstore.Blockstore
63
@@ -77,11 +77,10 @@ func (i *Instance) SetBlockstoreLatency(t time.Duration) time.Duration {
77 // NB: It's easy make mistakes by providing the same peer ID to two different
78 // sessions. To safeguard, use the SessionGenerator to generate sessions. It's
79 // just a much better idea.
80 -func session(ctx context.Context, net tn.Network, rs mockrouting.Server, ps peer.Peerstore, id peer.ID) Instance {
81 - p := ps.WithID(id)
80 +func session(ctx context.Context, net tn.Network, rs mockrouting.Server, ps peer.Peerstore, p peer.ID) Instance {
81
82 adapter := net.Adapter(p)
84 - htc := rs.Client(p)
83 + htc := rs.Client(peer.PeerInfo{ID: p})
84
85 bsdelay := delay.Fixed(0)
86 const kWriteCacheElems = 100
fuse/ipns/ipns_test.go
+2 -2
@@ -69,7 +69,7 @@ func setupIpnsTest(t *testing.T, node *core.IpfsNode) (*core.IpfsNode, *fstest.M
69 }
70 }
71
72 - fs, err := NewIpns(node, "")
72 + fs, err := NewIpns(node, node.PrivateKey, "")
73 if err != nil {
74 t.Fatal(err)
75 }
@@ -226,7 +226,7 @@ func TestFastRepublish(t *testing.T) {
226
227 node, mnt := setupIpnsTest(t, nil)
228
229 - h, err := node.Identity.PrivKey().GetPublic().Hash()
229 + h, err := node.PrivateKey.GetPublic().Hash()
230 if err != nil {
231 t.Fatal(err)
232 }
fuse/ipns/ipns_unix.go
+2 -2
@@ -37,8 +37,8 @@ type FileSystem struct {
37 }
38
39 // NewFileSystem constructs new fs using given core.IpfsNode instance.
40 -func NewIpns(ipfs *core.IpfsNode, ipfspath string) (*FileSystem, error) {
41 - root, err := CreateRoot(ipfs, []ci.PrivKey{ipfs.Identity.PrivKey()}, ipfspath)
40 +func NewIpns(ipfs *core.IpfsNode, sk ci.PrivKey, ipfspath string) (*FileSystem, error) {
41 + root, err := CreateRoot(ipfs, []ci.PrivKey{sk}, ipfspath)
42 if err != nil {
43 return nil, err
44 }
fuse/ipns/mount_unix.go
+1 -1
@@ -48,7 +48,7 @@ func internalMount(ipfs *core.IpfsNode, fpath string, ipfspath string) error {
48 }
49 defer c.Close()
50
51 - fsys, err := NewIpns(ipfs, ipfspath)
51 + fsys, err := NewIpns(ipfs, ipfs.PrivateKey, ipfspath)
52 if err != nil {
53 return err
54 }
namesys/resolve_test.go
+6 -2
@@ -4,14 +4,18 @@ import (
4 "testing"
5
6 ci "github.com/jbenet/go-ipfs/crypto"
7 + peer "github.com/jbenet/go-ipfs/peer"
8 mockrouting "github.com/jbenet/go-ipfs/routing/mock"
9 u "github.com/jbenet/go-ipfs/util"
10 testutil "github.com/jbenet/go-ipfs/util/testutil"
11 )
12
13 func TestRoutingResolve(t *testing.T) {
13 - local := testutil.NewPeerWithIDString("testID")
14 - d := mockrouting.NewServer().Client(local)
14 + local, err := testutil.RandPeerID()
15 + if err != nil {
16 + t.Fatal(err)
17 + }
18 + d := mockrouting.NewServer().Client(peer.PeerInfo{ID: local})
19
20 resolver := NewRoutingResolver(d)
21 publisher := NewRoutingPublisher(d)
net/backpressure/backpressure_test.go
+20 -13
@@ -17,15 +17,19 @@ import (
17
18 var log = eventlog.Logger("backpressure")
19
20 -func GenNetwork(ctx context.Context) (inet.Network, error) {
21 - p, err := testutil.PeerWithKeysAndAddress(testutil.RandLocalTCPAddress())
22 - if err != nil {
23 - return nil, err
24 - }
25 -
26 - listen := p.Addresses()
20 +func GenNetwork(t *testing.T, ctx context.Context) (inet.Network, error) {
21 + p := testutil.RandPeerNetParams(t)
22 ps := peer.NewPeerstore()
28 - return inet.NewNetwork(ctx, listen, p, ps)
23 + ps.AddAddress(p.ID, p.Addr)
24 + ps.AddPubKey(p.ID, p.PubKey)
25 + ps.AddPrivKey(p.ID, p.PrivKey)
26 + return inet.NewNetwork(ctx, ps.Addresses(p.ID), p.ID, ps)
27 +}
28 +
29 +func divulgeAddresses(a, b inet.Network) {
30 + id := a.LocalPeer()
31 + addrs := a.Peerstore().Addresses(id)
32 + b.Peerstore().AddAddresses(id, addrs)
33 }
34
35 // TestBackpressureStreamHandler tests whether mux handler
@@ -83,7 +87,7 @@ a problem.
87 }
88
89 // the sender opens streams as fast as possible
86 - sender := func(net inet.Network, remote peer.Peer) {
90 + sender := func(net inet.Network, remote peer.ID) {
91 var s inet.Stream
92 var err error
93 defer func() {
@@ -145,11 +149,11 @@ a problem.
149 // ok that's enough setup. let's do it!
150
151 ctx := context.Background()
148 - n1, err := GenNetwork(ctx)
152 + n1, err := GenNetwork(t, ctx)
153 if err != nil {
154 t.Fatal(err)
155 }
152 - n2, err := GenNetwork(ctx)
156 + n2, err := GenNetwork(t, ctx)
157 if err != nil {
158 t.Fatal(err)
159 }
@@ -287,15 +291,18 @@ func TestStBackpressureStreamWrite(t *testing.T) {
291
292 // setup the networks
293 ctx := context.Background()
290 - n1, err := GenNetwork(ctx)
294 + n1, err := GenNetwork(t, ctx)
295 if err != nil {
296 t.Fatal(err)
297 }
294 - n2, err := GenNetwork(ctx)
298 + n2, err := GenNetwork(t, ctx)
299 if err != nil {
300 t.Fatal(err)
301 }
302
303 + divulgeAddresses(n1, n2)
304 + divulgeAddresses(n2, n1)
305 +
306 // setup sender handler on 1
307 n1.SetHandler(inet.ProtocolTesting, sender)
308
net/conn/conn.go
+16 -7
@@ -11,6 +11,7 @@ import (
11 ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
12 manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
13
14 + ic "github.com/jbenet/go-ipfs/crypto"
15 peer "github.com/jbenet/go-ipfs/peer"
16 u "github.com/jbenet/go-ipfs/util"
17 eventlog "github.com/jbenet/go-ipfs/util/eventlog"
@@ -32,14 +33,14 @@ func ReleaseBuffer(b []byte) {
33
34 // singleConn represents a single connection to another Peer (IPFS Node).
35 type singleConn struct {
35 - local peer.Peer
36 - remote peer.Peer
36 + local peer.ID
37 + remote peer.ID
38 maconn manet.Conn
39 msgrw msgio.ReadWriteCloser
40 }
41
42 // newConn constructs a new connection
42 -func newSingleConn(ctx context.Context, local, remote peer.Peer, maconn manet.Conn) (Conn, error) {
43 +func newSingleConn(ctx context.Context, local, remote peer.ID, maconn manet.Conn) (Conn, error) {
44
45 conn := &singleConn{
46 local: local,
@@ -83,6 +84,14 @@ func (c *singleConn) RemoteAddr() net.Addr {
84 return c.maconn.RemoteAddr()
85 }
86
87 +func (c *singleConn) LocalPrivateKey() ic.PrivKey {
88 + return nil
89 +}
90 +
91 +func (c *singleConn) RemotePublicKey() ic.PubKey {
92 + return nil
93 +}
94 +
95 func (c *singleConn) SetDeadline(t time.Time) error {
96 return c.maconn.SetDeadline(t)
97 }
@@ -105,12 +114,12 @@ func (c *singleConn) RemoteMultiaddr() ma.Multiaddr {
114 }
115
116 // LocalPeer is the Peer on this side
108 -func (c *singleConn) LocalPeer() peer.Peer {
117 +func (c *singleConn) LocalPeer() peer.ID {
118 return c.local
119 }
120
121 // RemotePeer is the Peer on the remote side
113 -func (c *singleConn) RemotePeer() peer.Peer {
122 +func (c *singleConn) RemotePeer() peer.ID {
123 return c.remote
124 }
125
@@ -145,8 +154,8 @@ func (c *singleConn) ReleaseMsg(m []byte) {
154
155 // ID returns the ID of a given Conn.
156 func ID(c Conn) string {
148 - l := fmt.Sprintf("%s/%s", c.LocalMultiaddr(), c.LocalPeer().ID())
149 - r := fmt.Sprintf("%s/%s", c.RemoteMultiaddr(), c.RemotePeer().ID())
157 + l := fmt.Sprintf("%s/%s", c.LocalMultiaddr(), c.LocalPeer().Pretty())
158 + r := fmt.Sprintf("%s/%s", c.RemoteMultiaddr(), c.RemotePeer().Pretty())
159 lh := u.Hash([]byte(l))
160 rh := u.Hash([]byte(r))
161 ch := u.XOR(lh, rh)
net/conn/conn_test.go
+12 -12
@@ -5,7 +5,6 @@ import (
5 "fmt"
6 "os"
7 "runtime"
8 - "strconv"
8 "sync"
9 "testing"
10 "time"
@@ -14,6 +13,7 @@ import (
13 )
14
15 func testOneSendRecv(t *testing.T, c1, c2 Conn) {
16 + log.Debugf("testOneSendRecv from %s to %s", c1.LocalPeer(), c2.LocalPeer())
17 m1 := []byte("hello")
18 if err := c1.WriteMsg(m1); err != nil {
19 t.Fatal(err)
@@ -41,8 +41,9 @@ func testNotOneSendRecv(t *testing.T, c1, c2 Conn) {
41 func TestClose(t *testing.T) {
42 // t.Skip("Skipping in favor of another test")
43
44 - ctx := context.Background()
45 - c1, c2 := setupSingleConn(t, ctx, "/ip4/127.0.0.1/tcp/5534", "/ip4/127.0.0.1/tcp/5545")
44 + ctx, cancel := context.WithCancel(context.Background())
45 + defer cancel()
46 + c1, c2, _, _ := setupSingleConn(t, ctx)
47
48 testOneSendRecv(t, c1, c2)
49 testOneSendRecv(t, c2, c1)
@@ -56,6 +57,7 @@ func TestClose(t *testing.T) {
57 }
58
59 func TestCloseLeak(t *testing.T) {
60 + // t.Skip("Skipping in favor of another test")
61 if testing.Short() {
62 t.SkipNow()
63 }
@@ -66,11 +68,9 @@ func TestCloseLeak(t *testing.T) {
68
69 var wg sync.WaitGroup
70
69 - runPair := func(p1, p2, num int) {
70 - a1 := strconv.Itoa(p1)
71 - a2 := strconv.Itoa(p2)
71 + runPair := func(num int) {
72 ctx, cancel := context.WithCancel(context.Background())
73 - c1, c2 := setupSingleConn(t, ctx, "/ip4/127.0.0.1/tcp/"+a1, "/ip4/127.0.0.1/tcp/"+a2)
73 + c1, c2, _, _ := setupSingleConn(t, ctx)
74
75 for i := 0; i < num; i++ {
76 b1 := []byte(fmt.Sprintf("beep%d", i))
@@ -102,15 +102,15 @@ func TestCloseLeak(t *testing.T) {
102 wg.Done()
103 }
104
105 - var cons = 1
106 - var msgs = 100
107 - fmt.Printf("Running %d connections * %d msgs.\n", cons, msgs)
105 + var cons = 5
106 + var msgs = 50
107 + log.Debugf("Running %d connections * %d msgs.\n", cons, msgs)
108 for i := 0; i < cons; i++ {
109 wg.Add(1)
110 - go runPair(2000+i, 2001+i, msgs)
110 + go runPair(msgs)
111 }
112
113 - fmt.Printf("Waiting...\n")
113 + log.Debugf("Waiting...\n")
114 wg.Wait()
115 // done!
116
net/conn/dial.go
+58 -33
@@ -1,6 +1,7 @@
1 package conn
2
3 import (
4 + "fmt"
5 "strings"
6
7 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
@@ -11,49 +12,32 @@ import (
12 debugerror "github.com/jbenet/go-ipfs/util/debugerror"
13 )
14
14 -// Dial connects to a particular peer, over a given network
15 -// Example: d.Dial(ctx, "udp", peer)
16 -func (d *Dialer) Dial(ctx context.Context, network string, remote peer.Peer) (Conn, error) {
17 - raddr := remote.NetAddress(network)
18 - if raddr == nil {
19 - return nil, debugerror.Errorf("No remote address for network %s", network)
20 - }
21 - return d.DialAddr(ctx, raddr, remote)
15 +// String returns the string rep of d.
16 +func (d *Dialer) String() string {
17 + return fmt.Sprintf("<Dialer %s %s ...>", d.LocalPeer, d.LocalAddrs[0])
18 }
19
24 -// DialAddr connects to a peer over a particular address
20 +// Dial connects to a peer over a particular address
21 // Ensures raddr is part of peer.Addresses()
22 // Example: d.DialAddr(ctx, peer.Addresses()[0], peer)
27 -func (d *Dialer) DialAddr(ctx context.Context, raddr ma.Multiaddr, remote peer.Peer) (Conn, error) {
28 -
29 - found := false
30 - for _, addr := range remote.Addresses() {
31 - if addr.Equal(raddr) {
32 - found = true
33 - }
34 - }
35 - if !found {
36 - return nil, debugerror.Errorf("address %s is not in peer %s", raddr, remote)
37 - }
23 +func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (Conn, error) {
24
25 network, _, err := manet.DialArgs(raddr)
26 if err != nil {
27 return nil, err
28 }
29
44 - laddr := d.LocalPeer.NetAddress(network)
45 - if laddr == nil {
46 - return nil, debugerror.Errorf("No local address for network %s", network)
47 - }
48 -
30 if strings.HasPrefix(raddr.String(), "/ip4/0.0.0.0") {
31 return nil, debugerror.Errorf("Attempted to connect to zero address: %s", raddr)
32 }
33
53 - remote.SetType(peer.Remote)
54 - remote, err = d.Peerstore.Add(remote)
55 - if err != nil {
56 - log.Errorf("Error putting peer into peerstore: %s", remote)
34 + var laddr ma.Multiaddr
35 + if len(d.LocalAddrs) > 0 {
36 + // laddr := MultiaddrNetMatch(raddr, d.LocalAddrs)
37 + laddr = NetAddress(network, d.LocalAddrs)
38 + if laddr == nil {
39 + return nil, debugerror.Errorf("No local address for network %s", network)
40 + }
41 }
42
43 // TODO: try to get reusing addr/ports to work.
@@ -69,7 +53,7 @@ func (d *Dialer) DialAddr(ctx context.Context, raddr ma.Multiaddr, remote peer.P
53 select {
54 case <-ctx.Done():
55 maconn.Close()
72 - return nil, err
56 + return nil, ctx.Err()
57 default:
58 }
59
@@ -78,17 +62,58 @@ func (d *Dialer) DialAddr(ctx context.Context, raddr ma.Multiaddr, remote peer.P
62 return nil, err
63 }
64
81 - if d.WithoutSecureTransport {
65 + if d.PrivateKey == nil {
66 + log.Warning("dialer %s dialing INSECURELY %s at %s!", d, remote, raddr)
67 return c, nil
68 }
69
70 select {
71 case <-ctx.Done():
72 c.Close()
88 - return nil, err
73 + return nil, ctx.Err()
74 default:
75 }
76
77 // return c, nil
93 - return newSecureConn(ctx, c, d.Peerstore)
78 + return newSecureConn(ctx, d.PrivateKey, c)
79 +}
80 +
81 +// MultiaddrProtocolsMatch returns whether two multiaddrs match in protocol stacks.
82 +func MultiaddrProtocolsMatch(a, b ma.Multiaddr) bool {
83 + ap := a.Protocols()
84 + bp := b.Protocols()
85 +
86 + if len(ap) != len(bp) {
87 + return false
88 + }
89 +
90 + for i, api := range ap {
91 + if api != bp[i] {
92 + return false
93 + }
94 + }
95 +
96 + return true
97 +}
98 +
99 +// MultiaddrNetMatch returns the first Multiaddr found to match network.
100 +func MultiaddrNetMatch(tgt ma.Multiaddr, srcs []ma.Multiaddr) ma.Multiaddr {
101 + for _, a := range srcs {
102 + if MultiaddrProtocolsMatch(tgt, a) {
103 + return a
104 + }
105 + }
106 + return nil
107 +}
108 +
109 +// NetAddress returns the first Multiaddr found for a given network.
110 +func NetAddress(n string, addrs []ma.Multiaddr) ma.Multiaddr {
111 + for _, a := range addrs {
112 + for _, p := range a.Protocols() {
113 + if p.Name == n {
114 + return a
115 + }
116 + }
117 + }
118 + return nil
119 }
net/conn/dial_test.go
+61 -158
@@ -2,45 +2,35 @@ package conn
2
3 import (
4 "io"
5 + "net"
6 "testing"
7 + "time"
8
7 - ci "github.com/jbenet/go-ipfs/crypto"
8 - peer "github.com/jbenet/go-ipfs/peer"
9 - testutil "github.com/jbenet/go-ipfs/util/testutil"
9 + tu "github.com/jbenet/go-ipfs/util/testutil"
10
11 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
12 - ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
12 )
13
15 -func setupPeer(addr string) (peer.Peer, error) {
16 - tcp, err := ma.NewMultiaddr(addr)
17 - if err != nil {
18 - return nil, err
19 - }
20 -
21 - sk, pk, err := ci.GenerateKeyPair(ci.RSA, 512)
22 - if err != nil {
23 - return nil, err
24 - }
25 -
26 - p, err := testutil.NewPeerWithKeyPair(sk, pk)
27 - if err != nil {
28 - return nil, err
29 - }
30 - p.AddAddress(tcp)
31 - return p, nil
32 -}
33 -
14 func echoListen(ctx context.Context, listener Listener) {
15 for {
16 c, err := listener.Accept()
17 if err != nil {
18 +
19 select {
20 case <-ctx.Done():
21 return
22 default:
23 }
24 +
25 + if ne, ok := err.(net.Error); ok && ne.Temporary() {
26 + <-time.After(time.Microsecond * 10)
27 + continue
28 + }
29 +
30 + log.Debugf("echoListen: listener appears to be closing")
31 + return
32 }
33 +
34 go echo(c.(Conn))
35 }
36 }
@@ -49,106 +39,86 @@ func echo(c Conn) {
39 io.Copy(c, c)
40 }
41
52 -func setupSecureConn(t *testing.T, ctx context.Context, a1, a2 string) (a, b Conn) {
53 - return setupConn(t, ctx, a1, a2, true)
42 +func setupSecureConn(t *testing.T, ctx context.Context) (a, b Conn, p1, p2 tu.PeerNetParams) {
43 + return setupConn(t, ctx, true)
44 }
45
56 -func setupSingleConn(t *testing.T, ctx context.Context, a1, a2 string) (a, b Conn) {
57 - return setupConn(t, ctx, a1, a2, false)
46 +func setupSingleConn(t *testing.T, ctx context.Context) (a, b Conn, p1, p2 tu.PeerNetParams) {
47 + return setupConn(t, ctx, false)
48 }
49
60 -func setupConn(t *testing.T, ctx context.Context, a1, a2 string, secure bool) (a, b Conn) {
50 +func setupConn(t *testing.T, ctx context.Context, secure bool) (a, b Conn, p1, p2 tu.PeerNetParams) {
51
62 - p1, err := setupPeer(a1)
63 - if err != nil {
64 - t.Fatal("error setting up peer", err)
65 - }
52 + p1 = tu.RandPeerNetParams(t)
53 + p2 = tu.RandPeerNetParams(t)
54 + laddr := p1.Addr
55
67 - p2, err := setupPeer(a2)
68 - if err != nil {
69 - t.Fatal("error setting up peer", err)
70 - }
71 -
72 - laddr := p1.NetAddress("tcp")
73 - if laddr == nil {
74 - t.Fatal("Listen address is nil.")
56 + key1 := p1.PrivKey
57 + key2 := p2.PrivKey
58 + if !secure {
59 + key1 = nil
60 + key2 = nil
61 }
76 -
77 - ps1 := peer.NewPeerstore()
78 - ps2 := peer.NewPeerstore()
79 - ps1.Add(p1)
80 - ps2.Add(p2)
81 -
82 - l1, err := Listen(ctx, laddr, p1, ps1)
83 - l1.SetWithoutSecureTransport(!secure)
62 + l1, err := Listen(ctx, laddr, p1.ID, key1)
63 if err != nil {
64 t.Fatal(err)
65 }
66
67 d2 := &Dialer{
89 - Peerstore: ps2,
90 - LocalPeer: p2,
91 - WithoutSecureTransport: !secure,
68 + LocalPeer: p2.ID,
69 + PrivateKey: key2,
70 }
71
72 var c2 Conn
73
96 - done := make(chan struct{})
74 + done := make(chan error)
75 go func() {
98 - c2, err = d2.Dial(ctx, "tcp", p1)
76 + var err error
77 + c2, err = d2.Dial(ctx, p1.Addr, p1.ID)
78 if err != nil {
100 - t.Fatal("error dialing peer", err)
79 + done <- err
80 }
102 - done <- struct{}{}
81 + close(done)
82 }()
83
84 c1, err := l1.Accept()
85 if err != nil {
107 - t.Fatal("failed to accept")
86 + t.Fatal("failed to accept", err)
87 + }
88 + if err := <-done; err != nil {
89 + t.Fatal(err)
90 }
109 - <-done
91
111 - return c1.(Conn), c2
92 + return c1.(Conn), c2, p1, p2
93 }
94
114 -func TestDialer(t *testing.T) {
95 +func testDialer(t *testing.T, secure bool) {
96 // t.Skip("Skipping in favor of another test")
97
117 - p1, err := setupPeer("/ip4/127.0.0.1/tcp/4234")
118 - if err != nil {
119 - t.Fatal("error setting up peer", err)
120 - }
98 + p1 := tu.RandPeerNetParams(t)
99 + p2 := tu.RandPeerNetParams(t)
100
122 - p2, err := setupPeer("/ip4/127.0.0.1/tcp/4235")
123 - if err != nil {
124 - t.Fatal("error setting up peer", err)
101 + key1 := p1.PrivKey
102 + key2 := p2.PrivKey
103 + if !secure {
104 + key1 = nil
105 + key2 = nil
106 }
107
108 ctx, cancel := context.WithCancel(context.Background())
128 -
129 - laddr := p1.NetAddress("tcp")
130 - if laddr == nil {
131 - t.Fatal("Listen address is nil.")
132 - }
133 -
134 - ps1 := peer.NewPeerstore()
135 - ps2 := peer.NewPeerstore()
136 - ps1.Add(p1)
137 - ps2.Add(p2)
138 -
139 - l, err := Listen(ctx, laddr, p1, ps1)
109 + l1, err := Listen(ctx, p1.Addr, p1.ID, key1)
110 if err != nil {
111 t.Fatal(err)
112 }
113
144 - go echoListen(ctx, l)
145 -
146 - d := &Dialer{
147 - Peerstore: ps2,
148 - LocalPeer: p2,
114 + d2 := &Dialer{
115 + LocalPeer: p2.ID,
116 + PrivateKey: key2,
117 }
118
151 - c, err := d.Dial(ctx, "tcp", p1)
119 + go echoListen(ctx, l1)
120 +
121 + c, err := d2.Dial(ctx, p1.Addr, p1.ID)
122 if err != nil {
123 t.Fatal("error dialing peer", err)
124 }
@@ -180,83 +150,16 @@ func TestDialer(t *testing.T) {
150
151 // fmt.Println("closing")
152 c.Close()
183 - l.Close()
153 + l1.Close()
154 cancel()
155 }
156
187 -func TestDialAddr(t *testing.T) {
157 +func TestDialerInsecure(t *testing.T) {
158 // t.Skip("Skipping in favor of another test")
159 + testDialer(t, false)
160 +}
161
190 - p1, err := setupPeer("/ip4/127.0.0.1/tcp/4334")
191 - if err != nil {
192 - t.Fatal("error setting up peer", err)
193 - }
194 -
195 - p2, err := setupPeer("/ip4/127.0.0.1/tcp/4335")
196 - if err != nil {
197 - t.Fatal("error setting up peer", err)
198 - }
199 -
200 - ctx, cancel := context.WithCancel(context.Background())
201 -
202 - laddr := p1.NetAddress("tcp")
203 - if laddr == nil {
204 - t.Fatal("Listen address is nil.")
205 - }
206 -
207 - ps1 := peer.NewPeerstore()
208 - ps2 := peer.NewPeerstore()
209 - ps1.Add(p1)
210 - ps2.Add(p2)
211 -
212 - l, err := Listen(ctx, laddr, p1, ps1)
213 - if err != nil {
214 - t.Fatal(err)
215 - }
216 -
217 - go echoListen(ctx, l)
218 -
219 - d := &Dialer{
220 - Peerstore: ps2,
221 - LocalPeer: p2,
222 - }
223 -
224 - raddr := p1.NetAddress("tcp")
225 - if raddr == nil {
226 - t.Fatal("Dial address is nil.")
227 - }
228 -
229 - c, err := d.DialAddr(ctx, raddr, p1)
230 - if err != nil {
231 - t.Fatal("error dialing peer", err)
232 - }
233 -
234 - // fmt.Println("sending")
235 - c.WriteMsg([]byte("beep"))
236 - c.WriteMsg([]byte("boop"))
237 -
238 - out, err := c.ReadMsg()
239 - if err != nil {
240 - t.Fatal(err)
241 - }
242 - // fmt.Println("recving", string(out))
243 - data := string(out)
244 - if data != "beep" {
245 - t.Error("unexpected conn output", data)
246 - }
247 -
248 - out, err = c.ReadMsg()
249 - if err != nil {
250 - t.Fatal(err)
251 - }
252 -
253 - data = string(out)
254 - if string(out) != "boop" {
255 - t.Error("unexpected conn output", data)
256 - }
257 -
258 - // fmt.Println("closing")
259 - c.Close()
260 - l.Close()
261 - cancel()
162 +func TestDialerSecure(t *testing.T) {
163 + // t.Skip("Skipping in favor of another test")
164 + testDialer(t, true)
165 }
net/conn/handshake.go
+1 -37
@@ -2,13 +2,12 @@ package conn
2
3 import (
4 "fmt"
5 - "io"
5
6 handshake "github.com/jbenet/go-ipfs/net/handshake"
7 hspb "github.com/jbenet/go-ipfs/net/handshake/pb"
8
10 - ggprotoio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/io"
9 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
10 + ggprotoio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/io"
11 )
12
13 // Handshake1 exchanges local and remote versions and compares them
@@ -51,38 +50,3 @@ func Handshake1(ctx context.Context, c Conn) error {
50 log.Debugf("%s version handshake compatible %s", lpeer, rpeer)
51 return nil
52 }
54 -
55 -// Handshake3 exchanges local and remote service information
56 -func Handshake3(ctx context.Context, stream io.ReadWriter, c Conn) (*handshake.Handshake3Result, error) {
57 - rpeer := c.RemotePeer()
58 - lpeer := c.LocalPeer()
59 -
60 - // setup up protobuf io
61 - maxSize := 4096
62 - r := ggprotoio.NewDelimitedReader(stream, maxSize)
63 - w := ggprotoio.NewDelimitedWriter(stream)
64 - localH := handshake.Handshake3Msg(lpeer, c.RemoteMultiaddr())
65 - remoteH := new(hspb.Handshake3)
66 -
67 - // setup + send the message to remote
68 - if err := w.WriteMsg(localH); err != nil {
69 - return nil, err
70 - }
71 - log.Debugf("Handshake3: sent to %s", rpeer)
72 - log.Event(ctx, "handshake3Sent", lpeer, rpeer)
73 -
74 - // wait + listen for response
75 - if err := r.ReadMsg(remoteH); err != nil {
76 - return nil, fmt.Errorf("Handshake3 could not receive remote msg: %q", err)
77 - }
78 - log.Debugf("Handshake3: received from %s", rpeer)
79 - log.Event(ctx, "handshake3Received", lpeer, rpeer)
80 -
81 - // actually update our state based on the new knowledge
82 - res, err := handshake.Handshake3Update(lpeer, rpeer, remoteH)
83 - if err != nil {
84 - log.Errorf("Handshake3 failed to update %s", rpeer)
85 - }
86 - res.RemoteObservedAddress = c.RemoteMultiaddr()
87 - return res, nil
88 -}
net/conn/interface.go
+14 -27
@@ -5,6 +5,7 @@ import (
5 "net"
6 "time"
7
8 + ic "github.com/jbenet/go-ipfs/crypto"
9 peer "github.com/jbenet/go-ipfs/peer"
10 u "github.com/jbenet/go-ipfs/util"
11
@@ -16,17 +17,15 @@ import (
17 type Map map[u.Key]Conn
18
19 type PeerConn interface {
19 - // LocalMultiaddr is the Multiaddr on this side
20 + // LocalPeer (this side) ID, PrivateKey, and Address
21 + LocalPeer() peer.ID
22 + LocalPrivateKey() ic.PrivKey
23 LocalMultiaddr() ma.Multiaddr
24
22 - // LocalPeer is the Peer on our side of the connection
23 - LocalPeer() peer.Peer
24 -
25 - // RemoteMultiaddr is the Multiaddr on the remote side
25 + // RemotePeer ID, PublicKey, and Address
26 + RemotePeer() peer.ID
27 + RemotePublicKey() ic.PubKey
28 RemoteMultiaddr() ma.Multiaddr
27 -
28 - // RemotePeer is the Peer on the remote side
29 - RemotePeer() peer.Peer
29 }
30
31 // Conn is a generic message-based Peer-to-Peer connection.
@@ -54,16 +53,14 @@ type Conn interface {
53 type Dialer struct {
54
55 // LocalPeer is the identity of the local Peer.
57 - LocalPeer peer.Peer
56 + LocalPeer peer.ID
57
59 - // Peerstore is the set of peers we know about locally. The Dialer needs it
60 - // because when an incoming connection is identified, we should reuse the
61 - // same peer objects (otherwise things get inconsistent).
62 - Peerstore peer.Peerstore
58 + // LocalAddrs is a set of local addresses to use.
59 + LocalAddrs []ma.Multiaddr
60
64 - // WithoutSecureTransport determines whether to initialize an insecure connection.
65 - // Phrased negatively so default is Secure, and verbosely to be very clear.
66 - WithoutSecureTransport bool
61 + // PrivateKey used to initialize a secure connection.
62 + // Warning: if PrivateKey is nil, connection will not be secured.
63 + PrivateKey ic.PrivKey
64 }
65
66 // Listener is an object that can accept connections. It matches net.Listener
@@ -72,11 +69,6 @@ type Listener interface {
69 // Accept waits for and returns the next connection to the listener.
70 Accept() (net.Conn, error)
71
75 - // {Set}WithoutSecureTransport decides whether to start insecure connections.
76 - // Phrased negatively so default is Secure, and verbosely to be very clear.
77 - WithoutSecureTransport() bool
78 - SetWithoutSecureTransport(bool)
79 -
72 // Addr is the local address
73 Addr() net.Addr
74
@@ -84,12 +76,7 @@ type Listener interface {
76 Multiaddr() ma.Multiaddr
77
78 // LocalPeer is the identity of the local Peer.
87 - LocalPeer() peer.Peer
88 -
89 - // Peerstore is the set of peers we know about locally. The Listener needs it
90 - // because when an incoming connection is identified, we should reuse the
91 - // same peer objects (otherwise things get inconsistent).
92 - Peerstore() peer.Peerstore
79 + LocalPeer() peer.ID
80
81 // Close closes the listener.
82 // Any blocked Accept operations will be unblocked and return errors.
net/conn/listen.go
+28 -35
@@ -5,31 +5,37 @@ import (
5 "net"
6
7 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
8 + ctxgroup "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-ctxgroup"
9 ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
10 manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
11
12 + ic "github.com/jbenet/go-ipfs/crypto"
13 peer "github.com/jbenet/go-ipfs/peer"
14 )
15
16 // listener is an object that can accept connections. It implements Listener
17 type listener struct {
16 - withoutSecureTransport bool
17 -
18 manet.Listener
19
20 - // Local multiaddr to listen on
21 - maddr ma.Multiaddr
20 + maddr ma.Multiaddr // Local multiaddr to listen on
21 + local peer.ID // LocalPeer is the identity of the local Peer
22 + privk ic.PrivKey // private key to use to initialize secure conns
23
23 - // LocalPeer is the identity of the local Peer.
24 - local peer.Peer
24 + cg ctxgroup.ContextGroup
25 +}
26
26 - // Peerstore is the set of peers we know about locally
27 - peers peer.Peerstore
27 +func (l *listener) teardown() error {
28 + defer log.Debugf("listener closed: %s %s", l.local, l.maddr)
29 + return l.Listener.Close()
30 }
31
32 func (l *listener) Close() error {
31 - log.Infof("listener closing: %s %s", l.local, l.maddr)
32 - return l.Listener.Close()
33 + log.Debugf("listener closing: %s %s", l.local, l.maddr)
34 + return l.cg.Close()
35 +}
36 +
37 +func (l *listener) String() string {
38 + return fmt.Sprintf("<Listener %s %s>", l.local, l.maddr)
39 }
40
41 // Accept waits for and returns the next connection to the listener.
@@ -46,29 +52,22 @@ func (l *listener) Accept() (net.Conn, error) {
52 return nil, err
53 }
54
49 - c, err := newSingleConn(ctx, l.local, nil, maconn)
55 + c, err := newSingleConn(ctx, l.local, "", maconn)
56 if err != nil {
57 return nil, fmt.Errorf("Error accepting connection: %v", err)
58 }
59
54 - if l.withoutSecureTransport {
60 + if l.privk == nil {
61 + log.Warning("listener %s listening INSECURELY!", l)
62 return c, nil
63 }
57 - sc, err := newSecureConn(ctx, c, l.peers)
64 + sc, err := newSecureConn(ctx, l.privk, c)
65 if err != nil {
66 return nil, fmt.Errorf("Error securing connection: %v", err)
67 }
68 return sc, nil
69 }
70
64 -func (l *listener) WithoutSecureTransport() bool {
65 - return l.withoutSecureTransport
66 -}
67 -
68 -func (l *listener) SetWithoutSecureTransport(b bool) {
69 - l.withoutSecureTransport = b
70 -}
71 -
71 func (l *listener) Addr() net.Addr {
72 return l.Listener.Addr()
73 }
@@ -79,29 +78,22 @@ func (l *listener) Multiaddr() ma.Multiaddr {
78 }
79
80 // LocalPeer is the identity of the local Peer.
82 -func (l *listener) LocalPeer() peer.Peer {
81 +func (l *listener) LocalPeer() peer.ID {
82 return l.local
83 }
84
86 -// Peerstore is the set of peers we know about locally. The Listener needs it
87 -// because when an incoming connection is identified, we should reuse the
88 -// same peer objects (otherwise things get inconsistent).
89 -func (l *listener) Peerstore() peer.Peerstore {
90 - return l.peers
91 -}
92 -
85 func (l *listener) Loggable() map[string]interface{} {
86 return map[string]interface{}{
87 "listener": map[string]interface{}{
96 - "peer": l.LocalPeer(),
97 - "address": l.Multiaddr(),
98 - "withoutSecureTransport": l.withoutSecureTransport,
88 + "peer": l.LocalPeer(),
89 + "address": l.Multiaddr(),
90 + "secure": (l.privk != nil),
91 },
92 }
93 }
94
95 // Listen listens on the particular multiaddr, with given peer and peerstore.
104 -func Listen(ctx context.Context, addr ma.Multiaddr, local peer.Peer, peers peer.Peerstore) (Listener, error) {
96 +func Listen(ctx context.Context, addr ma.Multiaddr, local peer.ID, sk ic.PrivKey) (Listener, error) {
97
98 ml, err := manet.Listen(addr)
99 if err != nil {
@@ -111,10 +103,11 @@ func Listen(ctx context.Context, addr ma.Multiaddr, local peer.Peer, peers peer.
103 l := &listener{
104 Listener: ml,
105 maddr: addr,
114 - peers: peers,
106 local: local,
116 - withoutSecureTransport: false,
107 + privk: sk,
108 + cg: ctxgroup.WithContext(ctx),
109 }
110 + l.cg.SetTeardown(l.teardown)
111
112 log.Infof("swarm listening on %s\n", l.Multiaddr())
113 log.Event(ctx, "swarmListen", l)
net/conn/secure_conn.go
+27 -4
@@ -8,8 +8,10 @@ import (
8 msgio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio"
9 ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
10
11 + ic "github.com/jbenet/go-ipfs/crypto"
12 secio "github.com/jbenet/go-ipfs/crypto/secio"
13 peer "github.com/jbenet/go-ipfs/peer"
14 + errors "github.com/jbenet/go-ipfs/util/debugerror"
15 )
16
17 // secureConn wraps another Conn object with an encrypted channel.
@@ -26,10 +28,21 @@ type secureConn struct {
28 }
29
30 // newConn constructs a new connection
29 -func newSecureConn(ctx context.Context, insecure Conn, peers peer.Peerstore) (Conn, error) {
31 +func newSecureConn(ctx context.Context, sk ic.PrivKey, insecure Conn) (Conn, error) {
32 +
33 + if insecure == nil {
34 + return nil, errors.New("insecure is nil")
35 + }
36 + if insecure.LocalPeer() == "" {
37 + return nil, errors.New("insecure.LocalPeer() is nil")
38 + }
39 + if sk == nil {
40 + panic("way")
41 + return nil, errors.New("private key is nil")
42 + }
43
44 // NewSession performs the secure handshake, which takes multiple RTT
32 - sessgen := secio.SessionGenerator{Local: insecure.LocalPeer(), Peerstore: peers}
45 + sessgen := secio.SessionGenerator{LocalID: insecure.LocalPeer(), PrivateKey: sk}
46 session, err := sessgen.NewSession(ctx, insecure)
47 if err != nil {
48 return nil, err
@@ -92,15 +105,25 @@ func (c *secureConn) RemoteMultiaddr() ma.Multiaddr {
105 }
106
107 // LocalPeer is the Peer on this side
95 -func (c *secureConn) LocalPeer() peer.Peer {
108 +func (c *secureConn) LocalPeer() peer.ID {
109 return c.session.LocalPeer()
110 }
111
112 // RemotePeer is the Peer on the remote side
100 -func (c *secureConn) RemotePeer() peer.Peer {
113 +func (c *secureConn) RemotePeer() peer.ID {
114 return c.session.RemotePeer()
115 }
116
117 +// LocalPrivateKey is the public key of the peer on this side
118 +func (c *secureConn) LocalPrivateKey() ic.PrivKey {
119 + return c.session.LocalPrivateKey()
120 +}
121 +
122 +// RemotePubKey is the public key of the peer on the remote side
123 +func (c *secureConn) RemotePublicKey() ic.PubKey {
124 + return c.session.RemotePublicKey()
125 +}
126 +
127 // Read reads data, net.Conn style
128 func (c *secureConn) Read(buf []byte) (int, error) {
129 return c.secure.Read(buf)
net/conn/secure_conn_test.go
+84 -32
@@ -2,50 +2,78 @@ package conn
2
3 import (
4 "bytes"
5 - "fmt"
5 "os"
6 "runtime"
8 - "strconv"
7 "sync"
8 "testing"
9 "time"
10
13 - peer "github.com/jbenet/go-ipfs/peer"
11 + ic "github.com/jbenet/go-ipfs/crypto"
12
13 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
14 )
15
18 -func upgradeToSecureConn(t *testing.T, ctx context.Context, c Conn) (Conn, error) {
16 +func upgradeToSecureConn(t *testing.T, ctx context.Context, sk ic.PrivKey, c Conn) (Conn, error) {
17 if c, ok := c.(*secureConn); ok {
18 return c, nil
19 }
20
21 // shouldn't happen, because dial + listen already return secure conns.
24 - s, err := newSecureConn(ctx, c, peer.NewPeerstore())
22 + s, err := newSecureConn(ctx, sk, c)
23 if err != nil {
24 return nil, err
25 }
26 return s, nil
27 }
28
31 -func secureHandshake(t *testing.T, ctx context.Context, c Conn, done chan error) {
32 - _, err := upgradeToSecureConn(t, ctx, c)
29 +func secureHandshake(t *testing.T, ctx context.Context, sk ic.PrivKey, c Conn, done chan error) {
30 + _, err := upgradeToSecureConn(t, ctx, sk, c)
31 done <- err
32 }
33
34 +func TestSecureSimple(t *testing.T) {
35 + // t.Skip("Skipping in favor of another test")
36 +
37 + numMsgs := 100
38 + if testing.Short() {
39 + numMsgs = 10
40 + }
41 +
42 + ctx := context.Background()
43 + c1, c2, p1, p2 := setupSingleConn(t, ctx)
44 +
45 + done := make(chan error)
46 + go secureHandshake(t, ctx, p1.PrivKey, c1, done)
47 + go secureHandshake(t, ctx, p2.PrivKey, c2, done)
48 +
49 + for i := 0; i < 2; i++ {
50 + if err := <-done; err != nil {
51 + t.Fatal(err)
52 + }
53 + }
54 +
55 + for i := 0; i < numMsgs; i++ {
56 + testOneSendRecv(t, c1, c2)
57 + testOneSendRecv(t, c2, c1)
58 + }
59 +
60 + c1.Close()
61 + c2.Close()
62 +}
63 +
64 func TestSecureClose(t *testing.T) {
65 // t.Skip("Skipping in favor of another test")
66
67 ctx := context.Background()
40 - c1, c2 := setupSingleConn(t, ctx, "/ip4/127.0.0.1/tcp/6634", "/ip4/127.0.0.1/tcp/6645")
68 + c1, c2, p1, p2 := setupSingleConn(t, ctx)
69
70 done := make(chan error)
43 - go secureHandshake(t, ctx, c1, done)
44 - go secureHandshake(t, ctx, c2, done)
71 + go secureHandshake(t, ctx, p1.PrivKey, c1, done)
72 + go secureHandshake(t, ctx, p2.PrivKey, c2, done)
73
74 for i := 0; i < 2; i++ {
75 if err := <-done; err != nil {
48 - t.Error(err)
76 + t.Fatal(err)
77 }
78 }
79
@@ -64,13 +92,13 @@ func TestSecureCancelHandshake(t *testing.T) {
92 // t.Skip("Skipping in favor of another test")
93
94 ctx, cancel := context.WithCancel(context.Background())
67 - c1, c2 := setupSingleConn(t, ctx, "/ip4/127.0.0.1/tcp/6634", "/ip4/127.0.0.1/tcp/6645")
95 + c1, c2, p1, p2 := setupSingleConn(t, ctx)
96
97 done := make(chan error)
70 - go secureHandshake(t, ctx, c1, done)
71 - <-time.After(50 * time.Millisecond)
98 + go secureHandshake(t, ctx, p1.PrivKey, c1, done)
99 + <-time.After(time.Millisecond)
100 cancel() // cancel ctx
73 - go secureHandshake(t, ctx, c2, done)
101 + go secureHandshake(t, ctx, p2.PrivKey, c2, done)
102
103 for i := 0; i < 2; i++ {
104 if err := <-done; err == nil {
@@ -79,6 +107,24 @@ func TestSecureCancelHandshake(t *testing.T) {
107 }
108 }
109
110 +func TestSecureHandshakeFailsWithWrongKeys(t *testing.T) {
111 + // t.Skip("Skipping in favor of another test")
112 +
113 + ctx, cancel := context.WithCancel(context.Background())
114 + defer cancel()
115 + c1, c2, p1, p2 := setupSingleConn(t, ctx)
116 +
117 + done := make(chan error)
118 + go secureHandshake(t, ctx, p2.PrivKey, c1, done)
119 + go secureHandshake(t, ctx, p1.PrivKey, c2, done)
120 +
121 + for i := 0; i < 2; i++ {
122 + if err := <-done; err == nil {
123 + t.Fatal("wrong keys should've errored out.")
124 + }
125 + }
126 +}
127 +
128 func TestSecureCloseLeak(t *testing.T) {
129 // t.Skip("Skipping in favor of another test")
130
@@ -89,15 +135,11 @@ func TestSecureCloseLeak(t *testing.T) {
135 t.Skip("this doesn't work well on travis")
136 }
137
92 - var wg sync.WaitGroup
93 -
94 - runPair := func(p1, p2, num int) {
95 - a1 := strconv.Itoa(p1)
96 - a2 := strconv.Itoa(p2)
97 - ctx, cancel := context.WithCancel(context.Background())
98 - c1, c2 := setupSecureConn(t, ctx, "/ip4/127.0.0.1/tcp/"+a1, "/ip4/127.0.0.1/tcp/"+a2)
138 + runPair := func(c1, c2 Conn, num int) {
139 + log.Debugf("runPair %d", num)
140
141 for i := 0; i < num; i++ {
142 + log.Debugf("runPair iteration %d", i)
143 b1 := []byte("beep")
144 c1.WriteMsg(b1)
145 b2, err := c2.ReadMsg()
@@ -120,22 +162,32 @@ func TestSecureCloseLeak(t *testing.T) {
162
163 <-time.After(time.Microsecond * 5)
164 }
123 -
124 - c1.Close()
125 - c2.Close()
126 - cancel() // close the listener
127 - wg.Done()
165 }
166
130 - var cons = 20
131 - var msgs = 100
132 - fmt.Printf("Running %d connections * %d msgs.\n", cons, msgs)
167 + var cons = 5
168 + var msgs = 50
169 + log.Debugf("Running %d connections * %d msgs.\n", cons, msgs)
170 +
171 + var wg sync.WaitGroup
172 for i := 0; i < cons; i++ {
173 wg.Add(1)
135 - go runPair(2000+i, 2001+i, msgs)
174 +
175 + ctx, cancel := context.WithCancel(context.Background())
176 + c1, c2, _, _ := setupSecureConn(t, ctx)
177 + go func(c1, c2 Conn) {
178 +
179 + defer func() {
180 + c1.Close()
181 + c2.Close()
182 + cancel()
183 + wg.Done()
184 + }()
185 +
186 + runPair(c1, c2, msgs)
187 + }(c1, c2)
188 }
189
138 - fmt.Printf("Waiting...\n")
190 + log.Debugf("Waiting...\n")
191 wg.Wait()
192 // done!
193
net/handshake/handshake1.go
+10
@@ -6,10 +6,13 @@ import (
6
7 config "github.com/jbenet/go-ipfs/config"
8 pb "github.com/jbenet/go-ipfs/net/handshake/pb"
9 + u "github.com/jbenet/go-ipfs/util"
10
11 semver "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/coreos/go-semver/semver"
12 )
13
14 +var log = u.Logger("handshake")
15 +
16 // IpfsVersion holds the current protocol version for a client running this code
17 var IpfsVersion *semver.Version
18 var ClientVersion = "go-ipfs/" + config.CurrentVersionNumber
@@ -51,6 +54,13 @@ func Handshake1Compatible(handshakeA, handshakeB *pb.Handshake1) error {
54
55 // NewHandshake1 creates a new Handshake1 from the two strings
56 func NewHandshake1(protoVer, agentVer string) *pb.Handshake1 {
57 + if protoVer == "" {
58 + protoVer = IpfsVersion.String()
59 + }
60 + if agentVer == "" {
61 + agentVer = ClientVersion
62 + }
63 +
64 return &pb.Handshake1{
65 ProtocolVersion: &protoVer,
66 AgentVersion: &agentVer,
net/handshake/handshake3.go deleted
-82
@@ -1,82 +0,0 @@
1 -package handshake
2 -
3 -import (
4 - "fmt"
5 -
6 - pb "github.com/jbenet/go-ipfs/net/handshake/pb"
7 - peer "github.com/jbenet/go-ipfs/peer"
8 - u "github.com/jbenet/go-ipfs/util"
9 -
10 - ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
11 -)
12 -
13 -var log = u.Logger("handshake")
14 -
15 -// Handshake3Msg constructs a Handshake3 msg.
16 -func Handshake3Msg(localPeer peer.Peer, remoteAddr ma.Multiaddr) *pb.Handshake3 {
17 - var msg pb.Handshake3
18 - // don't need publicKey after secure channel.
19 - // msg.PublicKey = localPeer.PubKey().Bytes()
20 -
21 - // local listen addresses
22 - addrs := localPeer.Addresses()
23 - msg.ListenAddrs = make([][]byte, len(addrs))
24 - for i, a := range addrs {
25 - msg.ListenAddrs[i] = a.Bytes()
26 - }
27 -
28 - // observed remote address
29 - msg.ObservedAddr = remoteAddr.Bytes()
30 -
31 - // services
32 - // srv := localPeer.Services()
33 - // msg.Services = make([]mux.ProtocolID, len(srv))
34 - // for i, pid := range srv {
35 - // msg.Services[i] = pid
36 - // }
37 -
38 - return &msg
39 -}
40 -
41 -// Handshake3Update updates local knowledge with the information in the
42 -// handshake3 msg we received from remote client.
43 -func Handshake3Update(lpeer, rpeer peer.Peer, msg *pb.Handshake3) (*Handshake3Result, error) {
44 - res := &Handshake3Result{}
45 -
46 - // our observed address
47 - observedAddr, err := ma.NewMultiaddrBytes(msg.GetObservedAddr())
48 - if err != nil {
49 - return res, err
50 - }
51 - if lpeer.AddAddress(observedAddr) {
52 - log.Debugf("(nat) added new local, remote-observed address: %s", observedAddr)
53 - }
54 - res.LocalObservedAddress = observedAddr
55 -
56 - // remote's reported addresses
57 - for _, a := range msg.GetListenAddrs() {
58 - addr, err := ma.NewMultiaddrBytes(a)
59 - if err != nil {
60 - err = fmt.Errorf("remote peer address not a multiaddr: %s", err)
61 - log.Errorf("Handshake3 error %s", err)
62 - return res, err
63 - }
64 - rpeer.AddAddress(addr)
65 - res.RemoteListenAddresses = append(res.RemoteListenAddresses, addr)
66 - }
67 -
68 - return res, nil
69 -}
70 -
71 -// Handshake3Result collects the knowledge gained in Handshake3.
72 -type Handshake3Result struct {
73 -
74 - // The addresses reported by the remote client
75 - RemoteListenAddresses []ma.Multiaddr
76 -
77 - // The address of the remote client we observed in this connection
78 - RemoteObservedAddress ma.Multiaddr
79 -
80 - // The address the remote client observed from this connection
81 - LocalObservedAddress ma.Multiaddr
82 -}
net/handshake/pb/handshake.pb.go
+29
@@ -53,8 +53,16 @@ func (m *Handshake1) GetAgentVersion() string {
53
54 // Handshake3 is delivered _after_ the secure channel is initialized
55 type Handshake3 struct {
56 + // can include all the values in handshake1, for protocol version, etc.
57 + H1 *Handshake1 `protobuf:"bytes,5,opt,name=h1" json:"h1,omitempty"`
58 + // publicKey is this node's public key (which also gives its node.ID)
59 + // - may not need to be sent, as secure channel implies it has been sent.
60 + // - then again, if we change / disable secure channel, may still want it.
61 + PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey" json:"publicKey,omitempty"`
62 // listenAddrs are the multiaddrs the sender node listens for open connections on
63 ListenAddrs [][]byte `protobuf:"bytes,2,rep,name=listenAddrs" json:"listenAddrs,omitempty"`
64 + // protocols are the services this node is running
65 + Protocols []string `protobuf:"bytes,3,rep,name=protocols" json:"protocols,omitempty"`
66 // oservedAddr is the multiaddr of the remote endpoint that the sender node perceives
67 // this is useful information to convey to the other side, as it helps the remote endpoint
68 // determine whether its connection to the local peer goes through NAT.
@@ -66,6 +74,20 @@ func (m *Handshake3) Reset() { *m = Handshake3{} }
74 func (m *Handshake3) String() string { return proto.CompactTextString(m) }
75 func (*Handshake3) ProtoMessage() {}
76
77 +func (m *Handshake3) GetH1() *Handshake1 {
78 + if m != nil {
79 + return m.H1
80 + }
81 + return nil
82 +}
83 +
84 +func (m *Handshake3) GetPublicKey() []byte {
85 + if m != nil {
86 + return m.PublicKey
87 + }
88 + return nil
89 +}
90 +
91 func (m *Handshake3) GetListenAddrs() [][]byte {
92 if m != nil {
93 return m.ListenAddrs
@@ -73,6 +95,13 @@ func (m *Handshake3) GetListenAddrs() [][]byte {
95 return nil
96 }
97
98 +func (m *Handshake3) GetProtocols() []string {
99 + if m != nil {
100 + return m.Protocols
101 + }
102 + return nil
103 +}
104 +
105 func (m *Handshake3) GetObservedAddr() []byte {
106 if m != nil {
107 return m.ObservedAddr
net/handshake/pb/handshake.proto
+6 -6
@@ -17,19 +17,19 @@ message Handshake1 {
17 // Handshake3 is delivered _after_ the secure channel is initialized
18 message Handshake3 {
19
20 + // can include all the values in handshake1, for protocol version, etc.
21 + optional Handshake1 h1 = 5;
22 +
23 // publicKey is this node's public key (which also gives its node.ID)
24 // - may not need to be sent, as secure channel implies it has been sent.
25 // - then again, if we change / disable secure channel, may still want it.
23 - // optional bytes publicKey = 1;
26 + optional bytes publicKey = 1;
27
28 // listenAddrs are the multiaddrs the sender node listens for open connections on
29 repeated bytes listenAddrs = 2;
30
28 - // TODO
29 - // services list the services this node is running
30 - // repeated mux.ProtocolID services = 3;
31 -
32 - // we'll have more fields here later.
31 + // protocols are the services this node is running
32 + repeated string protocols = 3;
33
34 // oservedAddr is the multiaddr of the remote endpoint that the sender node perceives
35 // this is useful information to convey to the other side, as it helps the remote endpoint
net/id.go new
+110
@@ -0,0 +1,110 @@
1 +package net
2 +
3 +import (
4 + handshake "github.com/jbenet/go-ipfs/net/handshake"
5 + pb "github.com/jbenet/go-ipfs/net/handshake/pb"
6 +
7 + ggio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/io"
8 + ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
9 +)
10 +
11 +// IDService is a structure that implements ProtocolIdentify.
12 +// It is a trivial service that gives the other peer some
13 +// useful information about the local peer. A sort of hello.
14 +//
15 +// The IDService sends:
16 +// * Our IPFS Protocol Version
17 +// * Our IPFS Agent Version
18 +// * Our public Listen Addresses
19 +type IDService struct {
20 + Network Network
21 +}
22 +
23 +func NewIDService(n Network) *IDService {
24 + s := &IDService{Network: n}
25 + n.SetHandler(ProtocolIdentify, s.RequestHandler)
26 + return s
27 +}
28 +
29 +func (ids *IDService) RequestHandler(s Stream) {
30 + defer s.Close()
31 + c := s.Conn()
32 +
33 + w := ggio.NewDelimitedWriter(s)
34 + mes := pb.Handshake3{}
35 + ids.populateMessage(&mes, s.Conn())
36 + w.WriteMsg(&mes)
37 +
38 + log.Debugf("%s sent message to %s %s", ProtocolIdentify,
39 + c.RemotePeer(), c.RemoteMultiaddr())
40 +}
41 +
42 +func (ids *IDService) ResponseHandler(s Stream) {
43 + defer s.Close()
44 + c := s.Conn()
45 +
46 + r := ggio.NewDelimitedReader(s, 2048)
47 + mes := pb.Handshake3{}
48 + if err := r.ReadMsg(&mes); err != nil {
49 + log.Errorf("%s error receiving message from %s %s", ProtocolIdentify,
50 + c.RemotePeer(), c.RemoteMultiaddr())
51 + return
52 + }
53 + ids.consumeMessage(&mes, c)
54 +
55 + log.Debugf("%s received message from %s %s", ProtocolIdentify,
56 + c.RemotePeer(), c.RemoteMultiaddr())
57 +}
58 +
59 +func (ids *IDService) populateMessage(mes *pb.Handshake3, c Conn) {
60 +
61 + // set protocols this node is currently handling
62 + protos := ids.Network.Protocols()
63 + mes.Protocols = make([]string, len(protos))
64 + for i, p := range protos {
65 + mes.Protocols[i] = string(p)
66 + }
67 +
68 + // observed address so other side is informed of their
69 + // "public" address, at least in relation to us.
70 + mes.ObservedAddr = c.RemoteMultiaddr().Bytes()
71 +
72 + // set listen addrs
73 + laddrs := ids.Network.ListenAddresses()
74 + mes.ListenAddrs = make([][]byte, len(laddrs))
75 + for i, addr := range laddrs {
76 + mes.ListenAddrs[i] = addr.Bytes()
77 + }
78 +
79 + // set protocol versions
80 + mes.H1 = handshake.NewHandshake1("", "")
81 +}
82 +
83 +func (ids *IDService) consumeMessage(mes *pb.Handshake3, c Conn) {
84 + p := c.RemotePeer()
85 +
86 + // mes.Protocols
87 + // mes.ObservedAddr
88 +
89 + // mes.ListenAddrs
90 + laddrs := mes.GetListenAddrs()
91 + lmaddrs := make([]ma.Multiaddr, 0, len(laddrs))
92 + for _, addr := range laddrs {
93 + maddr, err := ma.NewMultiaddrBytes(addr)
94 + if err != nil {
95 + log.Errorf("%s failed to parse multiaddr from %s %s", ProtocolIdentify, p,
96 + c.RemoteMultiaddr())
97 + continue
98 + }
99 + lmaddrs = append(lmaddrs, maddr)
100 + }
101 +
102 + // update our peerstore with the addresses.
103 + ids.Network.Peerstore().AddAddresses(p, lmaddrs)
104 +
105 + // get protocol versions
106 + pv := *mes.H1.ProtocolVersion
107 + av := *mes.H1.AgentVersion
108 + ids.Network.Peerstore().Put(p, "ProtocolVersion", pv)
109 + ids.Network.Peerstore().Put(p, "AgentVersion", av)
110 +}
net/id_test.go new
+98
@@ -0,0 +1,98 @@
1 +package net_test
2 +
3 +import (
4 + "testing"
5 + "time"
6 +
7 + inet "github.com/jbenet/go-ipfs/net"
8 + handshake "github.com/jbenet/go-ipfs/net/handshake"
9 + peer "github.com/jbenet/go-ipfs/peer"
10 + testutil "github.com/jbenet/go-ipfs/util/testutil"
11 +
12 + context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
13 + ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
14 +)
15 +
16 +func GenNetwork(t *testing.T, ctx context.Context) inet.Network {
17 + p := testutil.RandPeerNetParams(t)
18 + ps := peer.NewPeerstore()
19 + ps.AddAddress(p.ID, p.Addr)
20 + ps.AddPubKey(p.ID, p.PubKey)
21 + ps.AddPrivKey(p.ID, p.PrivKey)
22 + n, err := inet.NewNetwork(ctx, ps.Addresses(p.ID), p.ID, ps)
23 + if err != nil {
24 + t.Fatal(err)
25 + }
26 + return n
27 +}
28 +
29 +func DivulgeAddresses(a, b inet.Network) {
30 + id := a.LocalPeer()
31 + addrs := a.Peerstore().Addresses(id)
32 + b.Peerstore().AddAddresses(id, addrs)
33 +}
34 +
35 +func TestIDService(t *testing.T) {
36 +
37 + // the generated networks should have the id service wired in.
38 + ctx := context.Background()
39 + n1 := GenNetwork(t, ctx)
40 + n2 := GenNetwork(t, ctx)
41 +
42 + testKnowsAddrs := func(n inet.Network, p peer.ID, expected []ma.Multiaddr) {
43 + actual := n.Peerstore().Addresses(p)
44 +
45 + if len(actual) != len(expected) {
46 + t.Error("dont have the same addresses")
47 + }
48 +
49 + have := map[string]struct{}{}
50 + for _, addr := range actual {
51 + have[addr.String()] = struct{}{}
52 + }
53 + for _, addr := range expected {
54 + if _, found := have[addr.String()]; !found {
55 + t.Errorf("%s did not have addr for %s: %s", n.LocalPeer(), p, addr)
56 + panic("ahhhhhhh")
57 + }
58 + }
59 + }
60 +
61 + testHasProtocolVersions := func(n inet.Network, p peer.ID) {
62 + v, err := n.Peerstore().Get(p, "ProtocolVersion")
63 + if v.(string) != handshake.IpfsVersion.String() {
64 + t.Fatal("protocol mismatch", err)
65 + }
66 + v, err = n.Peerstore().Get(p, "AgentVersion")
67 + if v.(string) != handshake.ClientVersion {
68 + t.Fatal("agent version mismatch", err)
69 + }
70 + }
71 +
72 + n1p := n1.LocalPeer()
73 + n2p := n2.LocalPeer()
74 +
75 + testKnowsAddrs(n1, n2p, []ma.Multiaddr{}) // nothing
76 + testKnowsAddrs(n2, n1p, []ma.Multiaddr{}) // nothing
77 +
78 + // have n2 tell n1, so we can dial...
79 + DivulgeAddresses(n2, n1)
80 +
81 + testKnowsAddrs(n1, n2p, n2.Peerstore().Addresses(n2p)) // has them
82 + testKnowsAddrs(n2, n1p, []ma.Multiaddr{}) // nothing
83 +
84 + if err := n1.DialPeer(ctx, n2p); err != nil {
85 + t.Fatalf("Failed to dial:", err)
86 + }
87 +
88 + <-time.After(100 * time.Millisecond)
89 +
90 + // the IDService should be opened automatically, by the network.
91 + // what we should see now is that both peers know about each others listen addresses.
92 + testKnowsAddrs(n1, n2p, n2.Peerstore().Addresses(n2p)) // has them
93 + testKnowsAddrs(n2, n1p, n1.Peerstore().Addresses(n1p)) // has them
94 +
95 + // and the protocol versions.
96 + testHasProtocolVersions(n1, n2p)
97 + testHasProtocolVersions(n2, n1p)
98 +}
net/interface.go
+23 -12
@@ -18,10 +18,11 @@ type ProtocolID string
18 // These are the ProtocolIDs of the protocols running. It is useful
19 // to keep them in one place.
20 const (
21 - ProtocolTesting ProtocolID = "/ipfs/testing"
22 - ProtocolBitswap ProtocolID = "/ipfs/bitswap"
23 - ProtocolDHT ProtocolID = "/ipfs/dht"
24 - ProtocolDiag ProtocolID = "/ipfs/diagnostics"
21 + ProtocolTesting ProtocolID = "/ipfs/testing"
22 + ProtocolBitswap ProtocolID = "/ipfs/bitswap"
23 + ProtocolDHT ProtocolID = "/ipfs/dht"
24 + ProtocolIdentify ProtocolID = "/ipfs/id"
25 + ProtocolDiag ProtocolID = "/ipfs/diagnostics"
26 )
27
28 // MessageSizeMax is a soft (recommended) maximum for network messages.
@@ -56,8 +57,8 @@ type StreamHandlerMap map[ProtocolID]StreamHandler
57 type Conn interface {
58 conn.PeerConn
59
59 - // NewStreamWithProtocol constructs a new Stream directly connected to p.
60 - NewStreamWithProtocol(pr ProtocolID, p peer.Peer) (Stream, error)
60 + // NewStreamWithProtocol constructs a new Stream over this conn.
61 + NewStreamWithProtocol(pr ProtocolID) (Stream, error)
62 }
63
64 // Network is the interface IPFS uses for connecting to the world.
@@ -72,13 +73,17 @@ type Network interface {
73 // This operation is threadsafe.
74 SetHandler(ProtocolID, StreamHandler)
75
76 + // Protocols returns the list of protocols this network currently
77 + // has registered handlers for.
78 + Protocols() []ProtocolID
79 +
80 // NewStream returns a new stream to given peer p.
81 // If there is no connection to p, attempts to create one.
82 // If ProtocolID is "", writes no header.
78 - NewStream(ProtocolID, peer.Peer) (Stream, error)
83 + NewStream(ProtocolID, peer.ID) (Stream, error)
84
85 // Peers returns the peers connected
81 - Peers() []peer.Peer
86 + Peers() []peer.ID
87
88 // Conns returns the connections in this Netowrk
89 Conns() []Conn
@@ -103,17 +108,23 @@ type Network interface {
108 // (this is usually just a Network, but other services may not need the whole
109 // stack, and thus it becomes easier to mock)
110 type Dialer interface {
111 +
112 + // Peerstore returns the internal peerstore
113 + // This is useful to tell the dialer about a new address for a peer.
114 + // Or use one of the public keys found out over the network.
115 + Peerstore() peer.Peerstore
116 +
117 // LocalPeer returns the local peer associated with this network
107 - LocalPeer() peer.Peer
118 + LocalPeer() peer.ID
119
120 // DialPeer attempts to establish a connection to a given peer
110 - DialPeer(context.Context, peer.Peer) error
121 + DialPeer(context.Context, peer.ID) error
122
123 // ClosePeer closes the connection to a given peer
113 - ClosePeer(peer.Peer) error
124 + ClosePeer(peer.ID) error
125
126 // Connectedness returns a state signaling connection capabilities
116 - Connectedness(peer.Peer) Connectedness
127 + Connectedness(peer.ID) Connectedness
128 }
129
130 // Connectedness signals the capacity for a connection with a given node.
net/mock/interface.go
+16 -9
@@ -10,21 +10,28 @@ import (
10 "io"
11 "time"
12
13 + ic "github.com/jbenet/go-ipfs/crypto"
14 inet "github.com/jbenet/go-ipfs/net"
15 peer "github.com/jbenet/go-ipfs/peer"
16 +
17 + ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
18 )
19
20 type Mocknet interface {
21 +
22 + // GenPeer generates a peer and its inet.Network in the Mocknet
23 GenPeer() (inet.Network, error)
19 - AddPeer(peer.ID) (inet.Network, error)
24 +
25 + // AddPeer adds an existing peer. we need both a privkey and addr.
26 + // ID is derived from PrivKey
27 + AddPeer(ic.PrivKey, ma.Multiaddr) (inet.Network, error)
28
29 // retrieve things
22 - Peer(peer.ID) peer.Peer
23 - Peers() []peer.Peer
30 + Peers() []peer.ID
31 Net(peer.ID) inet.Network
32 Nets() []inet.Network
33 Links() LinkMap
27 - LinksBetweenPeers(a, b peer.Peer) []Link
34 + LinksBetweenPeers(a, b peer.ID) []Link
35 LinksBetweenNets(a, b inet.Network) []Link
36
37 // Links are the **ability to connect**.
@@ -32,10 +39,10 @@ type Mocknet interface {
39 // For p1 and p2 to connect, a link must exist between them.
40 // (this makes it possible to test dial failures, and
41 // things like relaying traffic)
35 - LinkPeers(peer.Peer, peer.Peer) (Link, error)
42 + LinkPeers(peer.ID, peer.ID) (Link, error)
43 LinkNets(inet.Network, inet.Network) (Link, error)
44 Unlink(Link) error
38 - UnlinkPeers(peer.Peer, peer.Peer) error
45 + UnlinkPeers(peer.ID, peer.ID) error
46 UnlinkNets(inet.Network, inet.Network) error
47
48 // LinkDefaults are the default options that govern links
@@ -45,9 +52,9 @@ type Mocknet interface {
52
53 // Connections are the usual. Connecting means Dialing.
54 // **to succeed, peers must be linked beforehand**
48 - ConnectPeers(peer.Peer, peer.Peer) error
55 + ConnectPeers(peer.ID, peer.ID) error
56 ConnectNets(inet.Network, inet.Network) error
50 - DisconnectPeers(peer.Peer, peer.Peer) error
57 + DisconnectPeers(peer.ID, peer.ID) error
58 DisconnectNets(inet.Network, inet.Network) error
59 }
60
@@ -66,7 +73,7 @@ type LinkOptions struct {
73 // nodes cannot talk to each other directly. :)
74 type Link interface {
75 Networks() []inet.Network
69 - Peers() []peer.Peer
76 + Peers() []peer.ID
77
78 SetOptions(LinkOptions)
79 Options() LinkOptions
net/mock/mock_conn.go
+26 -8
@@ -4,6 +4,7 @@ import (
4 "container/list"
5 "sync"
6
7 + ic "github.com/jbenet/go-ipfs/crypto"
8 inet "github.com/jbenet/go-ipfs/net"
9 peer "github.com/jbenet/go-ipfs/peer"
10
@@ -14,8 +15,15 @@ import (
15 // live connection between two peers.
16 // it goes over a particular link.
17 type conn struct {
17 - local peer.Peer
18 - remote peer.Peer
18 + local peer.ID
19 + remote peer.ID
20 +
21 + localAddr ma.Multiaddr
22 + remoteAddr ma.Multiaddr
23 +
24 + localPrivKey ic.PrivKey
25 + remotePubKey ic.PubKey
26 +
27 net *peernet
28 link *link
29 rconn *conn // counterpart
@@ -74,8 +82,8 @@ func (c *conn) openStream() *stream {
82 return sl
83 }
84
77 -func (c *conn) NewStreamWithProtocol(pr inet.ProtocolID, p peer.Peer) (inet.Stream, error) {
78 - log.Debugf("Conn.NewStreamWithProtocol: %s --> %s", c.local, p)
85 +func (c *conn) NewStreamWithProtocol(pr inet.ProtocolID) (inet.Stream, error) {
86 + log.Debugf("Conn.NewStreamWithProtocol: %s --> %s", c.local, c.remote)
87
88 s := c.openStream()
89 if err := inet.WriteProtocolHeader(pr, s); err != nil {
@@ -87,20 +95,30 @@ func (c *conn) NewStreamWithProtocol(pr inet.ProtocolID, p peer.Peer) (inet.Stre
95
96 // LocalMultiaddr is the Multiaddr on this side
97 func (c *conn) LocalMultiaddr() ma.Multiaddr {
90 - return nil
98 + return c.localAddr
99 }
100
101 // LocalPeer is the Peer on our side of the connection
94 -func (c *conn) LocalPeer() peer.Peer {
102 +func (c *conn) LocalPeer() peer.ID {
103 return c.local
104 }
105
106 +// LocalPrivateKey is the private key of the peer on our side.
107 +func (c *conn) LocalPrivateKey() ic.PrivKey {
108 + return c.localPrivKey
109 +}
110 +
111 // RemoteMultiaddr is the Multiaddr on the remote side
112 func (c *conn) RemoteMultiaddr() ma.Multiaddr {
100 - return nil
113 + return c.remoteAddr
114 }
115
116 // RemotePeer is the Peer on the remote side
104 -func (c *conn) RemotePeer() peer.Peer {
117 +func (c *conn) RemotePeer() peer.ID {
118 return c.remote
119 }
120 +
121 +// RemotePublicKey is the private key of the peer on our side.
122 +func (c *conn) RemotePublicKey() ic.PubKey {
123 + return c.remotePubKey
124 +}
net/mock/mock_link.go
+16 -13
@@ -1,7 +1,6 @@
1 package mocknet
2
3 import (
4 - "fmt"
4 "io"
5 "sync"
6
@@ -16,6 +15,8 @@ type link struct {
15 nets []*peernet
16 opts LinkOptions
17
18 + // this could have addresses on both sides.
19 +
20 sync.RWMutex
21 }
22
@@ -27,20 +28,22 @@ func (l *link) newConnPair(dialer *peernet) (*conn, *conn) {
28 l.RLock()
29 defer l.RUnlock()
30
30 - mkconn := func(n *peernet, rid peer.ID) *conn {
31 - c := &conn{net: n, link: l}
32 - c.local = n.peer
31 + mkconn := func(ln, rn *peernet) *conn {
32 + c := &conn{net: ln, link: l}
33 + c.local = ln.peer
34 + c.remote = rn.peer
35 +
36 + c.localAddr = ln.ps.Addresses(ln.peer)[0]
37 + c.remoteAddr = rn.ps.Addresses(rn.peer)[0]
38 +
39 + c.localPrivKey = ln.ps.PrivKey(ln.peer)
40 + c.remotePubKey = rn.ps.PubKey(rn.peer)
41
34 - r, err := n.ps.FindOrCreate(rid)
35 - if err != nil {
36 - panic(fmt.Errorf("error creating peer: %s", err))
37 - }
38 - c.remote = r
42 return c
43 }
44
42 - c1 := mkconn(l.nets[0], l.nets[1].peer.ID())
43 - c2 := mkconn(l.nets[1], l.nets[0].peer.ID())
45 + c1 := mkconn(l.nets[0], l.nets[1])
46 + c2 := mkconn(l.nets[1], l.nets[0])
47 c1.rconn = c2
48 c2.rconn = c1
49
@@ -70,11 +73,11 @@ func (l *link) Networks() []inet.Network {
73 return cp
74 }
75
73 -func (l *link) Peers() []peer.Peer {
76 +func (l *link) Peers() []peer.ID {
77 l.RLock()
78 defer l.RUnlock()
79
77 - cp := make([]peer.Peer, len(l.nets))
80 + cp := make([]peer.ID, len(l.nets))
81 for i, n := range l.nets {
82 cp[i] = n.peer
83 }
net/mock/mock_net.go
+34 -49
@@ -4,27 +4,27 @@ import (
4 "fmt"
5 "sync"
6
7 + ic "github.com/jbenet/go-ipfs/crypto"
8 inet "github.com/jbenet/go-ipfs/net"
9 peer "github.com/jbenet/go-ipfs/peer"
10 testutil "github.com/jbenet/go-ipfs/util/testutil"
11
12 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
13 ctxgroup "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-ctxgroup"
14 + ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
15 )
16
15 -type peerID string
16 -
17 // mocknet implements mocknet.Mocknet
18 type mocknet struct {
19 - // must map on peer.ID (instead of peer.Peer) because
19 + // must map on peer.ID (instead of peer.ID) because
20 // each inet.Network has different peerstore
21 - nets map[peerID]*peernet
21 + nets map[peer.ID]*peernet
22
23 // links make it possible to connect two peers.
24 // think of links as the physical medium.
25 // usually only one, but there could be multiple
26 // **links are shared between peers**
27 - links map[peerID]map[peerID]map[*link]struct{}
27 + links map[peer.ID]map[peer.ID]map[*link]struct{}
28
29 linkDefaults LinkOptions
30
@@ -34,33 +34,30 @@ type mocknet struct {
34
35 func New(ctx context.Context) Mocknet {
36 return &mocknet{
37 - nets: map[peerID]*peernet{},
38 - links: map[peerID]map[peerID]map[*link]struct{}{},
37 + nets: map[peer.ID]*peernet{},
38 + links: map[peer.ID]map[peer.ID]map[*link]struct{}{},
39 cg: ctxgroup.WithContext(ctx),
40 }
41 }
42
43 func (mn *mocknet) GenPeer() (inet.Network, error) {
44 - p, err := testutil.PeerWithNewKeys()
44 + sk, _, err := testutil.RandKeyPair(512)
45 if err != nil {
46 return nil, err
47 }
48
49 - n, err := mn.AddPeer(p.ID())
50 - if err != nil {
51 - return nil, err
52 - }
49 + a := testutil.RandLocalTCPAddress()
50
54 - // copy over keys
55 - if err := n.LocalPeer().Update(p); err != nil {
51 + n, err := mn.AddPeer(sk, a)
52 + if err != nil {
53 return nil, err
54 }
55
56 return n, nil
57 }
58
62 -func (mn *mocknet) AddPeer(p peer.ID) (inet.Network, error) {
63 - n, err := newPeernet(mn.cg.Context(), mn, p)
59 +func (mn *mocknet) AddPeer(k ic.PrivKey, a ma.Multiaddr) (inet.Network, error) {
60 + n, err := newPeernet(mn.cg.Context(), mn, k, a)
61 if err != nil {
62 return nil, err
63 }
@@ -68,28 +65,16 @@ func (mn *mocknet) AddPeer(p peer.ID) (inet.Network, error) {
65 mn.cg.AddChildGroup(n.cg)
66
67 mn.Lock()
71 - mn.nets[pid(n.peer)] = n
68 + mn.nets[n.peer] = n
69 mn.Unlock()
70 return n, nil
71 }
72
76 -func (mn *mocknet) Peer(pid peer.ID) peer.Peer {
77 - mn.RLock()
78 - defer mn.RUnlock()
79 -
80 - for _, n := range mn.nets {
81 - if n.peer.ID().Equal(pid) {
82 - return n.peer
83 - }
84 - }
85 - return nil
86 -}
87 -
88 -func (mn *mocknet) Peers() []peer.Peer {
73 +func (mn *mocknet) Peers() []peer.ID {
74 mn.RLock()
75 defer mn.RUnlock()
76
92 - cp := make([]peer.Peer, 0, len(mn.nets))
77 + cp := make([]peer.ID, 0, len(mn.nets))
78 for _, n := range mn.nets {
79 cp = append(cp, n.peer)
80 }
@@ -101,7 +86,7 @@ func (mn *mocknet) Net(pid peer.ID) inet.Network {
86 defer mn.RUnlock()
87
88 for _, n := range mn.nets {
104 - if n.peer.ID().Equal(pid) {
89 + if n.peer == pid {
90 return n
91 }
92 }
@@ -152,10 +137,10 @@ func (mn *mocknet) LinkAll() error {
137 return nil
138 }
139
155 -func (mn *mocknet) LinkPeers(p1, p2 peer.Peer) (Link, error) {
140 +func (mn *mocknet) LinkPeers(p1, p2 peer.ID) (Link, error) {
141 mn.RLock()
157 - n1 := mn.nets[pid(p1)]
158 - n2 := mn.nets[pid(p2)]
142 + n1 := mn.nets[p1]
143 + n2 := mn.nets[p2]
144 mn.RUnlock()
145
146 if n1 == nil {
@@ -177,7 +162,7 @@ func (mn *mocknet) validate(n inet.Network) (*peernet, error) {
162 return nil, fmt.Errorf("Network not supported (use mock package nets only)")
163 }
164
180 - if _, found := mn.nets[pid(nr.peer)]; !found {
165 + if _, found := mn.nets[nr.peer]; !found {
166 return nil, fmt.Errorf("Network not on mocknet. is it from another mocknet?")
167 }
168
@@ -215,7 +200,7 @@ func (mn *mocknet) Unlink(l2 Link) error {
200 return nil
201 }
202
218 -func (mn *mocknet) UnlinkPeers(p1, p2 peer.Peer) error {
203 +func (mn *mocknet) UnlinkPeers(p1, p2 peer.ID) error {
204 ls := mn.LinksBetweenPeers(p1, p2)
205 if ls == nil {
206 return fmt.Errorf("no link between p1 and p2")
@@ -234,19 +219,19 @@ func (mn *mocknet) UnlinkNets(n1, n2 inet.Network) error {
219 }
220
221 // get from the links map. and lazily contruct.
237 -func (mn *mocknet) linksMapGet(p1, p2 peer.Peer) *map[*link]struct{} {
222 +func (mn *mocknet) linksMapGet(p1, p2 peer.ID) *map[*link]struct{} {
223
239 - l1, found := mn.links[pid(p1)]
224 + l1, found := mn.links[p1]
225 if !found {
241 - mn.links[pid(p1)] = map[peerID]map[*link]struct{}{}
242 - l1 = mn.links[pid(p1)] // so we make sure it's there.
226 + mn.links[p1] = map[peer.ID]map[*link]struct{}{}
227 + l1 = mn.links[p1] // so we make sure it's there.
228 }
229
245 - l2, found := l1[pid(p2)]
230 + l2, found := l1[p2]
231 if !found {
232 m := map[*link]struct{}{}
248 - l1[pid(p2)] = m
249 - l2 = l1[pid(p2)]
233 + l1[p2] = m
234 + l2 = l1[p2]
235 }
236
237 return &l2
@@ -286,23 +271,23 @@ func (mn *mocknet) ConnectAll() error {
271 return nil
272 }
273
289 -func (mn *mocknet) ConnectPeers(a, b peer.Peer) error {
290 - return mn.Net(a.ID()).DialPeer(mn.cg.Context(), b)
274 +func (mn *mocknet) ConnectPeers(a, b peer.ID) error {
275 + return mn.Net(a).DialPeer(mn.cg.Context(), b)
276 }
277
278 func (mn *mocknet) ConnectNets(a, b inet.Network) error {
279 return a.DialPeer(mn.cg.Context(), b.LocalPeer())
280 }
281
297 -func (mn *mocknet) DisconnectPeers(p1, p2 peer.Peer) error {
298 - return mn.Net(p1.ID()).ClosePeer(p2)
282 +func (mn *mocknet) DisconnectPeers(p1, p2 peer.ID) error {
283 + return mn.Net(p1).ClosePeer(p2)
284 }
285
286 func (mn *mocknet) DisconnectNets(n1, n2 inet.Network) error {
287 return n1.ClosePeer(n2.LocalPeer())
288 }
289
305 -func (mn *mocknet) LinksBetweenPeers(p1, p2 peer.Peer) []Link {
290 +func (mn *mocknet) LinksBetweenPeers(p1, p2 peer.ID) []Link {
291 mn.RLock()
292 defer mn.RUnlock()
293
net/mock/mock_peernet.go
+41 -39
@@ -5,6 +5,7 @@ import (
5 "math/rand"
6 "sync"
7
8 + ic "github.com/jbenet/go-ipfs/crypto"
9 inet "github.com/jbenet/go-ipfs/net"
10 peer "github.com/jbenet/go-ipfs/peer"
11
@@ -17,13 +18,13 @@ import (
18 type peernet struct {
19 mocknet *mocknet // parent
20
20 - peer peer.Peer
21 + peer peer.ID
22 ps peer.Peerstore
23
24 // conns are actual live connections between peers.
25 // many conns could run over each link.
26 // **conns are NOT shared between peers**
26 - connsByPeer map[peerID]map[*conn]struct{}
27 + connsByPeer map[peer.ID]map[*conn]struct{}
28 connsByLink map[*link]map[*conn]struct{}
29
30 // needed to implement inet.Network
@@ -34,16 +35,20 @@ type peernet struct {
35 }
36
37 // newPeernet constructs a new peernet
37 -func newPeernet(ctx context.Context, m *mocknet, id peer.ID) (*peernet, error) {
38 +func newPeernet(ctx context.Context, m *mocknet, k ic.PrivKey,
39 + a ma.Multiaddr) (*peernet, error) {
40
39 - // create our own entirely, so that peers dont get shuffled across
40 - // network divides. dont share peers.
41 - ps := peer.NewPeerstore()
42 - p, err := ps.FindOrCreate(id)
41 + p, err := peer.IDFromPublicKey(k.GetPublic())
42 if err != nil {
43 return nil, err
44 }
45
46 + // create our own entirely, so that peers knowledge doesn't get shared
47 + ps := peer.NewPeerstore()
48 + ps.AddAddress(p, a)
49 + ps.AddPrivKey(p, k)
50 + ps.AddPubKey(p, k.GetPublic())
51 +
52 n := &peernet{
53 mocknet: m,
54 peer: p,
@@ -51,7 +56,7 @@ func newPeernet(ctx context.Context, m *mocknet, id peer.ID) (*peernet, error) {
56 mux: inet.Mux{Handlers: inet.StreamHandlerMap{}},
57 cg: ctxgroup.WithContext(ctx),
58
54 - connsByPeer: map[peerID]map[*conn]struct{}{},
59 + connsByPeer: map[peer.ID]map[*conn]struct{}{},
60 connsByLink: map[*link]map[*conn]struct{}{},
61 }
62
@@ -86,6 +91,14 @@ func (pn *peernet) Close() error {
91 return pn.cg.Close()
92 }
93
94 +func (pn *peernet) Protocols() []inet.ProtocolID {
95 + return pn.mux.Protocols()
96 +}
97 +
98 +func (pn *peernet) Peerstore() peer.Peerstore {
99 + return pn.ps
100 +}
101 +
102 func (pn *peernet) String() string {
103 return fmt.Sprintf("<mock.peernet %s - %d conns>", pn.peer, len(pn.allConns()))
104 }
@@ -97,23 +110,16 @@ func (pn *peernet) handleNewStream(s inet.Stream) {
110
111 // DialPeer attempts to establish a connection to a given peer.
112 // Respects the context.
100 -func (pn *peernet) DialPeer(ctx context.Context, p peer.Peer) error {
113 +func (pn *peernet) DialPeer(ctx context.Context, p peer.ID) error {
114 return pn.connect(p)
115 }
116
104 -func (pn *peernet) connect(p peer.Peer) error {
117 +func (pn *peernet) connect(p peer.ID) error {
118 log.Debugf("%s dialing %s", pn.peer, p)
119
107 - // cannot trust the peer we get. typical for tests to give us
108 - // a peer from some other peerstore...
109 - p, err := pn.ps.Add(p)
110 - if err != nil {
111 - return err
112 - }
113 -
120 // first, check if we already have live connections
121 pn.RLock()
116 - cs, found := pn.connsByPeer[pid(p)]
122 + cs, found := pn.connsByPeer[p]
123 pn.RUnlock()
124 if found && len(cs) > 0 {
125 return nil
@@ -136,7 +142,7 @@ func (pn *peernet) connect(p peer.Peer) error {
142 return nil
143 }
144
139 -func (pn *peernet) openConn(r peer.Peer, l *link) *conn {
145 +func (pn *peernet) openConn(r peer.ID, l *link) *conn {
146 lc, rc := l.newConnPair(pn)
147 log.Debugf("%s opening connection to %s", pn.LocalPeer(), lc.RemotePeer())
148 pn.addConn(lc)
@@ -153,12 +159,12 @@ func (pn *peernet) remoteOpenedConn(c *conn) {
159 // to given remote peer over given link
160 func (pn *peernet) addConn(c *conn) {
161 pn.Lock()
156 - cs, found := pn.connsByPeer[pid(c.RemotePeer())]
162 + cs, found := pn.connsByPeer[c.RemotePeer()]
163 if !found {
164 cs = map[*conn]struct{}{}
159 - pn.connsByPeer[pid(c.RemotePeer())] = cs
165 + pn.connsByPeer[c.RemotePeer()] = cs
166 }
161 - pn.connsByPeer[pid(c.RemotePeer())][c] = struct{}{}
167 + pn.connsByPeer[c.RemotePeer()][c] = struct{}{}
168
169 cs, found = pn.connsByLink[c.link]
170 if !found {
@@ -180,7 +186,7 @@ func (pn *peernet) removeConn(c *conn) {
186 }
187 delete(cs, c)
188
183 - cs, found = pn.connsByPeer[pid(c.remote)]
189 + cs, found = pn.connsByPeer[c.remote]
190 if !found {
191 panic("attempting to remove a conn that doesnt exist")
192 }
@@ -193,16 +199,16 @@ func (pn *peernet) CtxGroup() ctxgroup.ContextGroup {
199 }
200
201 // LocalPeer the network's LocalPeer
196 -func (pn *peernet) LocalPeer() peer.Peer {
202 +func (pn *peernet) LocalPeer() peer.ID {
203 return pn.peer
204 }
205
206 // Peers returns the connected peers
201 -func (pn *peernet) Peers() []peer.Peer {
207 +func (pn *peernet) Peers() []peer.ID {
208 pn.RLock()
209 defer pn.RUnlock()
210
205 - peers := make([]peer.Peer, 0, len(pn.connsByPeer))
211 + peers := make([]peer.ID, 0, len(pn.connsByPeer))
212 for _, cs := range pn.connsByPeer {
213 for c := range cs {
214 peers = append(peers, c.remote)
@@ -226,11 +232,11 @@ func (pn *peernet) Conns() []inet.Conn {
232 return out
233 }
234
229 -func (pn *peernet) ConnsToPeer(p peer.Peer) []inet.Conn {
235 +func (pn *peernet) ConnsToPeer(p peer.ID) []inet.Conn {
236 pn.RLock()
237 defer pn.RUnlock()
238
233 - cs, found := pn.connsByPeer[pid(p)]
239 + cs, found := pn.connsByPeer[p]
240 if !found || len(cs) == 0 {
241 return nil
242 }
@@ -243,9 +249,9 @@ func (pn *peernet) ConnsToPeer(p peer.Peer) []inet.Conn {
249 }
250
251 // ClosePeer connections to peer
246 -func (pn *peernet) ClosePeer(p peer.Peer) error {
252 +func (pn *peernet) ClosePeer(p peer.ID) error {
253 pn.RLock()
248 - cs, found := pn.connsByPeer[pid(p)]
254 + cs, found := pn.connsByPeer[p]
255 pn.RUnlock()
256 if !found {
257 return nil
@@ -278,11 +284,11 @@ func (pn *peernet) InterfaceListenAddresses() ([]ma.Multiaddr, error) {
284
285 // Connectedness returns a state signaling connection capabilities
286 // For now only returns Connecter || NotConnected. Expand into more later.
281 -func (pn *peernet) Connectedness(p peer.Peer) inet.Connectedness {
287 +func (pn *peernet) Connectedness(p peer.ID) inet.Connectedness {
288 pn.Lock()
289 defer pn.Unlock()
290
285 - cs, found := pn.connsByPeer[pid(p)]
291 + cs, found := pn.connsByPeer[p]
292 if found && len(cs) > 0 {
293 return inet.Connected
294 }
@@ -292,11 +298,11 @@ func (pn *peernet) Connectedness(p peer.Peer) inet.Connectedness {
298 // NewStream returns a new stream to given peer p.
299 // If there is no connection to p, attempts to create one.
300 // If ProtocolID is "", writes no header.
295 -func (pn *peernet) NewStream(pr inet.ProtocolID, p peer.Peer) (inet.Stream, error) {
301 +func (pn *peernet) NewStream(pr inet.ProtocolID, p peer.ID) (inet.Stream, error) {
302 pn.Lock()
303 defer pn.Unlock()
304
299 - cs, found := pn.connsByPeer[pid(p)]
305 + cs, found := pn.connsByPeer[p]
306 if !found || len(cs) < 1 {
307 return nil, fmt.Errorf("no connection to peer")
308 }
@@ -313,7 +319,7 @@ func (pn *peernet) NewStream(pr inet.ProtocolID, p peer.Peer) (inet.Stream, erro
319 n--
320 }
321
316 - return c.NewStreamWithProtocol(pr, p)
322 + return c.NewStreamWithProtocol(pr)
323 }
324
325 // SetHandler sets the protocol handler on the Network's Muxer.
@@ -321,7 +327,3 @@ func (pn *peernet) NewStream(pr inet.ProtocolID, p peer.Peer) (inet.Stream, erro
327 func (pn *peernet) SetHandler(p inet.ProtocolID, h inet.StreamHandler) {
328 pn.mux.SetHandler(p, h)
329 }
324 -
325 -func pid(p peer.Peer) peerID {
326 - return peerID(p.ID())
327 -}
net/mock/mock_test.go
+54 -33
@@ -14,51 +14,64 @@ import (
14 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
15 )
16
17 +func randPeer(t *testing.T) peer.ID {
18 + p, err := testutil.RandPeerID()
19 + if err != nil {
20 + t.Fatal(err)
21 + }
22 + return p
23 +}
24 +
25 func TestNetworkSetup(t *testing.T) {
26
27 ctx := context.Background()
20 - p1 := testutil.RandPeer()
21 - p2 := testutil.RandPeer()
22 - p3 := testutil.RandPeer()
28 + sk1, _, err := testutil.RandKeyPair(512)
29 + if err != nil {
30 + t.Fatal(t)
31 + }
32 + sk2, _, err := testutil.RandKeyPair(512)
33 + if err != nil {
34 + t.Fatal(t)
35 + }
36 + sk3, _, err := testutil.RandKeyPair(512)
37 + if err != nil {
38 + t.Fatal(t)
39 + }
40 mn := New(ctx)
24 - // peers := []peer.Peer{p1, p2, p3}
41 + // peers := []peer.ID{p1, p2, p3}
42
43 // add peers to mock net
44
28 - n1, err := mn.AddPeer(p1.ID())
45 + a1 := testutil.RandLocalTCPAddress()
46 + a2 := testutil.RandLocalTCPAddress()
47 + a3 := testutil.RandLocalTCPAddress()
48 +
49 + n1, err := mn.AddPeer(sk1, a1)
50 if err != nil {
51 t.Fatal(err)
52 }
53 + p1 := n1.LocalPeer()
54
33 - n2, err := mn.AddPeer(p2.ID())
55 + n2, err := mn.AddPeer(sk2, a2)
56 if err != nil {
57 t.Fatal(err)
58 }
59 + p2 := n2.LocalPeer()
60
38 - n3, err := mn.AddPeer(p3.ID())
61 + n3, err := mn.AddPeer(sk3, a3)
62 if err != nil {
63 t.Fatal(err)
64 }
65 + p3 := n3.LocalPeer()
66
67 // check peers and net
44 -
45 - if !mn.Peer(p1.ID()).ID().Equal(p1.ID()) {
46 - t.Error("peer for p1.ID != p1.ID")
47 - }
48 - if !mn.Peer(p2.ID()).ID().Equal(p2.ID()) {
49 - t.Error("peer for p2.ID != p2.ID")
50 - }
51 - if !mn.Peer(p3.ID()).ID().Equal(p3.ID()) {
52 - t.Error("peer for p3.ID != p3.ID")
53 - }
54 -
55 - if mn.Net(p1.ID()) != n1 {
68 + if mn.Net(p1) != n1 {
69 t.Error("net for p1.ID != n1")
70 }
58 - if mn.Net(p2.ID()) != n2 {
71 + if mn.Net(p2) != n2 {
72 t.Error("net for p2.ID != n1")
73 }
61 - if mn.Net(p3.ID()) != n3 {
74 + if mn.Net(p3) != n3 {
75 t.Error("net for p3.ID != n1")
76 }
77
@@ -373,24 +386,32 @@ func TestStreamsStress(t *testing.T) {
386 }(i)
387 }
388
376 - wg.Done()
389 + wg.Wait()
390 }
391
392 func TestAdding(t *testing.T) {
393
394 mn := New(context.Background())
395
383 - p1 := testutil.RandPeer()
384 - p2 := testutil.RandPeer()
385 - p3 := testutil.RandPeer()
386 - peers := []peer.Peer{p1, p2, p3}
396 + peers := []peer.ID{}
397 + for i := 0; i < 3; i++ {
398 + sk, _, err := testutil.RandKeyPair(512)
399 + if err != nil {
400 + t.Fatal(err)
401 + }
402
388 - for _, p := range peers {
389 - if _, err := mn.AddPeer(p.ID()); err != nil {
390 - t.Error(err)
403 + a := testutil.RandLocalTCPAddress()
404 + n, err := mn.AddPeer(sk, a)
405 + if err != nil {
406 + t.Fatal(err)
407 }
408 +
409 + peers = append(peers, n.LocalPeer())
410 }
411
412 + p1 := peers[0]
413 + p2 := peers[1]
414 +
415 // link them
416 for _, p1 := range peers {
417 for _, p2 := range peers {
@@ -401,9 +422,9 @@ func TestAdding(t *testing.T) {
422 }
423
424 // set the new stream handler on p2
404 - n2 := mn.Net(p2.ID())
425 + n2 := mn.Net(p2)
426 if n2 == nil {
406 - t.Fatalf("no network for %s", p2.ID())
427 + t.Fatalf("no network for %s", p2)
428 }
429 n2.SetHandler(inet.ProtocolBitswap, func(s inet.Stream) {
430 go func() {
@@ -429,9 +450,9 @@ func TestAdding(t *testing.T) {
450 }
451
452 // talk to p2
432 - n1 := mn.Net(p1.ID())
453 + n1 := mn.Net(p1)
454 if n1 == nil {
434 - t.Fatalf("no network for %s", p1.ID())
455 + t.Fatalf("no network for %s", p1)
456 }
457
458 s, err := n1.NewStream(inet.ProtocolBitswap, p2)
net/mux.go
+11
@@ -37,6 +37,17 @@ type Mux struct {
37 sync.RWMutex
38 }
39
40 +// Protocols returns the list of protocols this muxer has handlers for
41 +func (m *Mux) Protocols() []ProtocolID {
42 + m.RLock()
43 + l := make([]ProtocolID, 0, len(m.Handlers))
44 + for p := range m.Handlers {
45 + l = append(l, p)
46 + }
47 + m.RUnlock()
48 + return l
49 +}
50 +
51 // ReadProtocolHeader reads the stream and returns the next Handler function
52 // according to the muxer encoding.
53 func (m *Mux) ReadProtocolHeader(s io.Reader) (string, StreamHandler, error) {
net/net.go
+55 -20
@@ -2,6 +2,7 @@
2 package net
3
4 import (
5 + ic "github.com/jbenet/go-ipfs/crypto"
6 swarm "github.com/jbenet/go-ipfs/net/swarm"
7 peer "github.com/jbenet/go-ipfs/peer"
8
@@ -43,7 +44,7 @@ func (c *conn_) SwarmConn() *swarm.Conn {
44 return (*swarm.Conn)(c)
45 }
46
46 -func (c *conn_) NewStreamWithProtocol(pr ProtocolID, p peer.Peer) (Stream, error) {
47 +func (c *conn_) NewStreamWithProtocol(pr ProtocolID) (Stream, error) {
48 s, err := (*swarm.Conn)(c).NewStream()
49 if err != nil {
50 return nil, err
@@ -59,37 +60,43 @@ func (c *conn_) NewStreamWithProtocol(pr ProtocolID, p peer.Peer) (Stream, error
60 return ss, nil
61 }
62
62 -// LocalMultiaddr is the Multiaddr on this side
63 func (c *conn_) LocalMultiaddr() ma.Multiaddr {
64 return c.SwarmConn().LocalMultiaddr()
65 }
66
67 -// LocalPeer is the Peer on our side of the connection
68 -func (c *conn_) LocalPeer() peer.Peer {
69 - return c.SwarmConn().LocalPeer()
70 -}
71 -
72 -// RemoteMultiaddr is the Multiaddr on the remote side
67 func (c *conn_) RemoteMultiaddr() ma.Multiaddr {
68 return c.SwarmConn().RemoteMultiaddr()
69 }
70
77 -// RemotePeer is the Peer on the remote side
78 -func (c *conn_) RemotePeer() peer.Peer {
71 +func (c *conn_) LocalPeer() peer.ID {
72 + return c.SwarmConn().LocalPeer()
73 +}
74 +
75 +func (c *conn_) RemotePeer() peer.ID {
76 return c.SwarmConn().RemotePeer()
77 }
78
79 +func (c *conn_) LocalPrivateKey() ic.PrivKey {
80 + return c.SwarmConn().LocalPrivateKey()
81 +}
82 +
83 +func (c *conn_) RemotePublicKey() ic.PubKey {
84 + return c.SwarmConn().RemotePublicKey()
85 +}
86 +
87 // network implements the Network interface,
88 type network struct {
84 - local peer.Peer // local peer
89 + local peer.ID // local peer
90 mux Mux // protocol multiplexing
91 swarm *swarm.Swarm // peer connection multiplexing
92 + ps peer.Peerstore
93 + ids *IDService
94
95 cg ctxgroup.ContextGroup // for Context closing
96 }
97
98 // NewNetwork constructs a new network and starts listening on given addresses.
92 -func NewNetwork(ctx context.Context, listen []ma.Multiaddr, local peer.Peer,
99 +func NewNetwork(ctx context.Context, listen []ma.Multiaddr, local peer.ID,
100 peers peer.Peerstore) (Network, error) {
101
102 s, err := swarm.NewSwarm(ctx, listen, local, peers)
@@ -102,24 +109,47 @@ func NewNetwork(ctx context.Context, listen []ma.Multiaddr, local peer.Peer,
109 swarm: s,
110 mux: Mux{Handlers: StreamHandlerMap{}},
111 cg: ctxgroup.WithContext(ctx),
112 + ps: peers,
113 }
114
115 + n.cg.SetTeardown(n.close)
116 + n.cg.AddChildGroup(s.CtxGroup())
117 +
118 s.SetStreamHandler(func(s *swarm.Stream) {
119 n.mux.Handle((*stream)(s))
120 })
121
111 - n.cg.SetTeardown(n.close)
112 - n.cg.AddChildGroup(s.CtxGroup())
122 + // setup a conn handler that immediately "asks the other side about them"
123 + // this is ProtocolIdentify.
124 + n.ids = NewIDService(n)
125 + s.SetConnHandler(n.newConnHandler)
126 +
127 return n, nil
128 }
129
130 +func (n *network) newConnHandler(c *swarm.Conn) {
131 + cc := (*conn_)(c)
132 + s, err := cc.NewStreamWithProtocol(ProtocolIdentify)
133 + if err != nil {
134 + log.Error("network: unable to open initial stream for %s", ProtocolIdentify)
135 + log.Event(n.CtxGroup().Context(), "IdentifyOpenFailed", c.RemotePeer())
136 + }
137 +
138 + // ok give the response to our handler.
139 + n.ids.ResponseHandler(s)
140 +}
141 +
142 // DialPeer attempts to establish a connection to a given peer.
143 // Respects the context.
118 -func (n *network) DialPeer(ctx context.Context, p peer.Peer) error {
144 +func (n *network) DialPeer(ctx context.Context, p peer.ID) error {
145 _, err := n.swarm.Dial(ctx, p)
146 return err
147 }
148
149 +func (n *network) Protocols() []ProtocolID {
150 + return n.mux.Protocols()
151 +}
152 +
153 // CtxGroup returns the network's ContextGroup
154 func (n *network) CtxGroup() ctxgroup.ContextGroup {
155 return n.cg
@@ -131,15 +161,20 @@ func (n *network) Swarm() *swarm.Swarm {
161 }
162
163 // LocalPeer the network's LocalPeer
134 -func (n *network) LocalPeer() peer.Peer {
164 +func (n *network) LocalPeer() peer.ID {
165 return n.swarm.LocalPeer()
166 }
167
168 // Peers returns the connected peers
139 -func (n *network) Peers() []peer.Peer {
169 +func (n *network) Peers() []peer.ID {
170 return n.swarm.Peers()
171 }
172
173 +// Peers returns the connected peers
174 +func (n *network) Peerstore() peer.Peerstore {
175 + return n.ps
176 +}
177 +
178 // Conns returns the connected peers
179 func (n *network) Conns() []Conn {
180 conns1 := n.swarm.Connections()
@@ -151,7 +186,7 @@ func (n *network) Conns() []Conn {
186 }
187
188 // ClosePeer connection to peer
154 -func (n *network) ClosePeer(p peer.Peer) error {
189 +func (n *network) ClosePeer(p peer.ID) error {
190 return n.swarm.CloseConnection(p)
191 }
192
@@ -186,7 +221,7 @@ func (n *network) InterfaceListenAddresses() ([]ma.Multiaddr, error) {
221
222 // Connectedness returns a state signaling connection capabilities
223 // For now only returns Connected || NotConnected. Expand into more later.
189 -func (n *network) Connectedness(p peer.Peer) Connectedness {
224 +func (n *network) Connectedness(p peer.ID) Connectedness {
225 c := n.swarm.ConnectionsToPeer(p)
226 if c != nil && len(c) < 1 {
227 return Connected
@@ -197,7 +232,7 @@ func (n *network) Connectedness(p peer.Peer) Connectedness {
232 // NewStream returns a new stream to given peer p.
233 // If there is no connection to p, attempts to create one.
234 // If ProtocolID is "", writes no header.
200 -func (c *network) NewStream(pr ProtocolID, p peer.Peer) (Stream, error) {
235 +func (c *network) NewStream(pr ProtocolID, p peer.ID) (Stream, error) {
236 s, err := c.swarm.NewStreamWithPeer(p)
237 if err != nil {
238 return nil, err
net/swarm/simul_test.go
+16 -30
@@ -1,36 +1,29 @@
1 package swarm
2
3 import (
4 - "fmt"
4 "sync"
5 "testing"
6 + "time"
7
8 peer "github.com/jbenet/go-ipfs/peer"
9 - "github.com/jbenet/go-ipfs/util/testutil"
9
10 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
11 + ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
12 )
13
14 func TestSimultOpen(t *testing.T) {
15 // t.Skip("skipping for another test")
16
17 - addrs := []string{
18 - "/ip4/127.0.0.1/tcp/1244",
19 - "/ip4/127.0.0.1/tcp/1245",
20 - }
21 -
17 ctx := context.Background()
23 - swarms, _ := makeSwarms(ctx, t, addrs)
18 + swarms, peers := makeSwarms(ctx, t, 2)
19
20 // connect everyone
21 {
22 var wg sync.WaitGroup
28 - connect := func(s *Swarm, dst peer.Peer) {
23 + connect := func(s *Swarm, dst peer.ID, addr ma.Multiaddr) {
24 // copy for other peer
30 - cp := testutil.NewPeerWithID(dst.ID())
31 - cp.AddAddress(dst.Addresses()[0])
32 -
33 - if _, err := s.Dial(ctx, cp); err != nil {
25 + s.peers.AddAddress(dst, addr)
26 + if _, err := s.Dial(ctx, dst); err != nil {
27 t.Fatal("error swarm dialing to peer", err)
28 }
29 wg.Done()
@@ -38,8 +31,8 @@ func TestSimultOpen(t *testing.T) {
31
32 log.Info("Connecting swarms simultaneously.")
33 wg.Add(2)
41 - go connect(swarms[0], swarms[1].local)
42 - go connect(swarms[1], swarms[0].local)
34 + go connect(swarms[0], swarms[1].local, peers[1].Addr)
35 + go connect(swarms[1], swarms[0].local, peers[0].Addr)
36 wg.Wait()
37 }
38
@@ -51,13 +44,7 @@ func TestSimultOpen(t *testing.T) {
44 func TestSimultOpenMany(t *testing.T) {
45 // t.Skip("very very slow")
46
54 - many := 10
55 - addrs := []string{}
56 - for i := 2200; i < (2200 + many); i++ {
57 - s := fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", i)
58 - addrs = append(addrs, s)
59 - }
60 -
47 + addrs := 20
48 SubtestSwarm(t, addrs, 10)
49 }
50
@@ -67,14 +54,13 @@ func TestSimultOpenFewStress(t *testing.T) {
54 }
55 // t.Skip("skipping for another test")
56
70 - num := 10
71 - // num := 100
72 - for i := 0; i < num; i++ {
73 - addrs := []string{
74 - fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 1900+i),
75 - fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 2900+i),
76 - }
57 + msgs := 40
58 + swarms := 2
59 + rounds := 10
60 + // rounds := 100
61
78 - SubtestSwarm(t, addrs, 10)
62 + for i := 0; i < rounds; i++ {
63 + SubtestSwarm(t, swarms, msgs)
64 + <-time.After(10 * time.Millisecond)
65 }
66 }
net/swarm/swarm.go
+33 -38
@@ -22,21 +22,16 @@ var log = eventlog.Logger("swarm2")
22 // Uses peerstream.Swarm
23 type Swarm struct {
24 swarm *ps.Swarm
25 - local peer.Peer
25 + local peer.ID
26 peers peer.Peerstore
27 + connh ConnHandler
28
29 cg ctxgroup.ContextGroup
30 }
31
32 // NewSwarm constructs a Swarm, with a Chan.
33 func NewSwarm(ctx context.Context, listenAddrs []ma.Multiaddr,
33 - local peer.Peer, peers peer.Peerstore) (*Swarm, error) {
34 -
35 - // make sure our own peer is in our peerstore...
36 - local, err := peers.Add(local)
37 - if err != nil {
38 - return nil, err
39 - }
34 + local peer.ID, peers peer.Peerstore) (*Swarm, error) {
35
36 s := &Swarm{
37 swarm: ps.NewSwarm(),
@@ -47,7 +42,7 @@ func NewSwarm(ctx context.Context, listenAddrs []ma.Multiaddr,
42
43 // configure Swarm
44 s.cg.SetTeardown(s.teardown)
50 - s.swarm.SetConnHandler(s.connHandler)
45 + s.SetConnHandler(nil) // make sure to setup our own conn handler.
46
47 return s, s.listen(listenAddrs)
48 }
@@ -71,6 +66,27 @@ func (s *Swarm) StreamSwarm() *ps.Swarm {
66 return s.swarm
67 }
68
69 +// SetConnHandler assigns the handler for new connections.
70 +// See peerstream. You will rarely use this. See SetStreamHandler
71 +func (s *Swarm) SetConnHandler(handler ConnHandler) {
72 +
73 + // handler is nil if user wants to clear the old handler.
74 + if handler == nil {
75 + s.swarm.SetConnHandler(func(psconn *ps.Conn) {
76 + s.connHandler(psconn)
77 + })
78 + return
79 + }
80 +
81 + s.swarm.SetConnHandler(func(psconn *ps.Conn) {
82 + // sc is nil if closed in our handler.
83 + if sc := s.connHandler(psconn); sc != nil {
84 + // call the user's handler. in a goroutine for sync safety.
85 + go handler(sc)
86 + }
87 + })
88 +}
89 +
90 // SetStreamHandler assigns the handler for new streams.
91 // See peerstream.
92 func (s *Swarm) SetStreamHandler(handler StreamHandler) {
@@ -80,13 +96,7 @@ func (s *Swarm) SetStreamHandler(handler StreamHandler) {
96 }
97
98 // NewStreamWithPeer creates a new stream on any available connection to p
83 -func (s *Swarm) NewStreamWithPeer(p peer.Peer) (*Stream, error) {
84 - // make sure we use OUR peers. (the tests mess with you...)
85 - p, err := s.peers.Add(p)
86 - if err != nil {
87 - return nil, err
88 - }
89 -
99 +func (s *Swarm) NewStreamWithPeer(p peer.ID) (*Stream, error) {
100 // if we have no connections, try connecting.
101 if len(s.ConnectionsToPeer(p)) == 0 {
102 log.Debug("Swarm: NewStreamWithPeer no connections. Attempting to connect...")
@@ -101,21 +111,12 @@ func (s *Swarm) NewStreamWithPeer(p peer.Peer) (*Stream, error) {
111 }
112
113 // StreamsWithPeer returns all the live Streams to p
104 -func (s *Swarm) StreamsWithPeer(p peer.Peer) []*Stream {
105 - // make sure we use OUR peers. (the tests mess with you...)
106 - if p2, err := s.peers.Add(p); err == nil {
107 - p = p2
108 - }
109 -
114 +func (s *Swarm) StreamsWithPeer(p peer.ID) []*Stream {
115 return wrapStreams(ps.StreamsWithGroup(p, s.swarm.Streams()))
116 }
117
118 // ConnectionsToPeer returns all the live connections to p
114 -func (s *Swarm) ConnectionsToPeer(p peer.Peer) []*Conn {
115 - // make sure we use OUR peers. (the tests mess with you...)
116 - if p2, err := s.peers.Add(p); err == nil {
117 - p = p2
118 - }
119 +func (s *Swarm) ConnectionsToPeer(p peer.ID) []*Conn {
120 return wrapConns(ps.ConnsWithGroup(p, s.swarm.Conns()))
121 }
122
@@ -125,13 +126,7 @@ func (s *Swarm) Connections() []*Conn {
126 }
127
128 // CloseConnection removes a given peer from swarm + closes the connection
128 -func (s *Swarm) CloseConnection(p peer.Peer) error {
129 - // make sure we use OUR peers. (the tests mess with you...)
130 - p, err := s.peers.Add(p)
131 - if err != nil {
132 - return err
133 - }
134 -
129 +func (s *Swarm) CloseConnection(p peer.ID) error {
130 conns := s.swarm.ConnsWithGroup(p) // boom.
131 for _, c := range conns {
132 c.Close()
@@ -140,11 +135,11 @@ func (s *Swarm) CloseConnection(p peer.Peer) error {
135 }
136
137 // Peers returns a copy of the set of peers swarm is connected to.
143 -func (s *Swarm) Peers() []peer.Peer {
138 +func (s *Swarm) Peers() []peer.ID {
139 conns := s.Connections()
140
146 - seen := make(map[peer.Peer]struct{})
147 - peers := make([]peer.Peer, 0, len(conns))
141 + seen := make(map[peer.ID]struct{})
142 + peers := make([]peer.ID, 0, len(conns))
143 for _, c := range conns {
144 p := c.RemotePeer()
145 if _, found := seen[p]; found {
@@ -157,6 +152,6 @@ func (s *Swarm) Peers() []peer.Peer {
152 }
153
154 // LocalPeer returns the local peer swarm is associated to.
160 -func (s *Swarm) LocalPeer() peer.Peer {
155 +func (s *Swarm) LocalPeer() peer.ID {
156 return s.local
157 }
net/swarm/swarm_conn.go
+23 -34
@@ -3,6 +3,7 @@ package swarm
3 import (
4 "fmt"
5
6 + ic "github.com/jbenet/go-ipfs/crypto"
7 conn "github.com/jbenet/go-ipfs/net/conn"
8 peer "github.com/jbenet/go-ipfs/peer"
9
@@ -23,6 +24,10 @@ import (
24 // layers do build up pieces of functionality. and they're all just io.RW :) )
25 type Conn ps.Conn
26
27 +// ConnHandler is called when new conns are opened from remote peers.
28 +// See peerstream.ConnHandler
29 +type ConnHandler func(*Conn)
30 +
31 func (c *Conn) StreamConn() *ps.Conn {
32 return (*ps.Conn)(c)
33 }
@@ -41,7 +46,7 @@ func (c *Conn) LocalMultiaddr() ma.Multiaddr {
46 }
47
48 // LocalPeer is the Peer on our side of the connection
44 -func (c *Conn) LocalPeer() peer.Peer {
49 +func (c *Conn) LocalPeer() peer.ID {
50 return c.RawConn().LocalPeer()
51 }
52
@@ -51,10 +56,20 @@ func (c *Conn) RemoteMultiaddr() ma.Multiaddr {
56 }
57
58 // RemotePeer is the Peer on the remote side
54 -func (c *Conn) RemotePeer() peer.Peer {
59 +func (c *Conn) RemotePeer() peer.ID {
60 return c.RawConn().RemotePeer()
61 }
62
63 +// LocalPrivateKey is the public key of the peer on this side
64 +func (c *Conn) LocalPrivateKey() ic.PrivKey {
65 + return c.RawConn().LocalPrivateKey()
66 +}
67 +
68 +// RemotePublicKey is the public key of the peer on the remote side
69 +func (c *Conn) RemotePublicKey() ic.PubKey {
70 + return c.RawConn().RemotePublicKey()
71 +}
72 +
73 // NewStream returns a new Stream from this connection
74 func (c *Conn) NewStream() (*Stream, error) {
75 s, err := c.StreamConn().NewStream()
@@ -96,12 +111,12 @@ func (s *Swarm) newConnSetup(ctx context.Context, psConn *ps.Conn) (*Conn, error
111 return nil, err
112 }
113
99 - // removing this for now, as it has to change. we can put this in a different
100 - // sub-protocol anyway.
101 - // // run Handshake3
102 - // if err := runHandshake3(ctx, s, sc); err != nil {
103 - // return nil, err
104 - // }
114 + // if we have a public key, make sure we add it to our peerstore!
115 + // This is an important detail. Otherwise we must fetch the public
116 + // key from the DHT or some other system.
117 + if pk := sc.RemotePublicKey(); pk != nil {
118 + s.peers.AddPubKey(sc.RemotePeer(), pk)
119 + }
120
121 // ok great! we can use it. add it to our group.
122
@@ -113,29 +128,3 @@ func (s *Swarm) newConnSetup(ctx context.Context, psConn *ps.Conn) (*Conn, error
128
129 return sc, nil
130 }
116 -
117 -// func runHandshake3(ctx context.Context, s *Swarm, c *Conn) error {
118 -// log.Event(ctx, "newConnection", c.LocalPeer(), c.RemotePeer())
119 -
120 -// stream, err := c.NewStream()
121 -// if err != nil {
122 -// return err
123 -// }
124 -
125 -// // handshake3 (this whole thing is ugly. maybe lets get rid of it...)
126 -// h3result, err := conn.Handshake3(ctx, stream, c.RawConn())
127 -// if err != nil {
128 -// return fmt.Errorf("Handshake3 failed: %s", err)
129 -// }
130 -
131 -// // check for nats. you know, just in case.
132 -// if h3result.LocalObservedAddress != nil {
133 -// checkNATWarning(s, h3result.LocalObservedAddress, c.LocalMultiaddr())
134 -// } else {
135 -// log.Warningf("Received nil observed address from %s", c.RemotePeer())
136 -// }
137 -
138 -// stream.Close()
139 -// log.Event(ctx, "handshake3Succeeded", c.LocalPeer(), c.RemotePeer())
140 -// return nil
141 -// }
net/swarm/swarm_dial.go
+21 -14
@@ -17,9 +17,9 @@ import (
17 // the connection will happen over. Swarm can use whichever it choses.
18 // This allows us to use various transport protocols, do NAT traversal/relay,
19 // etc. to achive connection.
20 -func (s *Swarm) Dial(ctx context.Context, p peer.Peer) (*Conn, error) {
20 +func (s *Swarm) Dial(ctx context.Context, p peer.ID) (*Conn, error) {
21
22 - if p.ID().Equal(s.local.ID()) {
22 + if p == s.local {
23 return nil, errors.New("Attempted connection to self!")
24 }
25
@@ -31,28 +31,35 @@ func (s *Swarm) Dial(ctx context.Context, p peer.Peer) (*Conn, error) {
31 }
32 }
33
34 - // check if we don't have the peer in Peerstore
35 - p, err := s.peers.Add(p)
36 - if err != nil {
37 - return nil, err
34 + sk := s.peers.PrivKey(s.local)
35 + if sk == nil {
36 + // may be fine for sk to be nil, just log a warning.
37 + log.Warning("Dial not given PrivateKey, so WILL NOT SECURE conn.")
38 }
39
40 - // open connection to peer
41 - d := &conn.Dialer{
42 - LocalPeer: s.local,
43 - Peerstore: s.peers,
40 + remoteAddrs := s.peers.Addresses(p)
41 + if len(remoteAddrs) == 0 {
42 + return nil, errors.New("peer has no addresses")
43 + }
44 + localAddrs := s.peers.Addresses(s.local)
45 + if len(localAddrs) == 0 {
46 + log.Debug("Dialing out with no local addresses.")
47 }
48
46 - if len(p.Addresses()) == 0 {
47 - return nil, errors.New("peer has no addresses")
49 + // open connection to peer
50 + d := &conn.Dialer{
51 + LocalPeer: s.local,
52 + LocalAddrs: localAddrs,
53 + PrivateKey: sk,
54 }
55
56 // try to connect to one of the peer's known addresses.
57 // for simplicity, we do this sequentially.
58 // A future commit will do this asynchronously.
59 var connC conn.Conn
54 - for _, addr := range p.Addresses() {
55 - connC, err = d.DialAddr(ctx, addr, p)
60 + var err error
61 + for _, addr := range remoteAddrs {
62 + connC, err = d.Dial(ctx, addr, p)
63 if err == nil {
64 break
65 }
net/swarm/swarm_listen.go
+33 -27
@@ -6,8 +6,8 @@ import (
6
7 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
8 ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
9 - multierr "github.com/jbenet/go-ipfs/util/multierr"
9 ps "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream"
10 + multierr "github.com/jbenet/go-ipfs/util/multierr"
11 )
12
13 // Open listeners for each network the swarm should listen on
@@ -35,21 +35,26 @@ func (s *Swarm) listen(addrs []ma.Multiaddr) error {
35 // Listen for new connections on the given multiaddr
36 func (s *Swarm) setupListener(maddr ma.Multiaddr) error {
37
38 - resolved, err := resolveUnspecifiedAddresses([]ma.Multiaddr{maddr})
39 - if err != nil {
40 - return err
41 - }
38 + // TODO rethink how this has to work. (jbenet)
39 + //
40 + // resolved, err := resolveUnspecifiedAddresses([]ma.Multiaddr{maddr})
41 + // if err != nil {
42 + // return err
43 + // }
44 + // for _, a := range resolved {
45 + // s.peers.AddAddress(s.local, a)
46 + // }
47
43 - list, err := conn.Listen(s.cg.Context(), maddr, s.local, s.peers)
48 + sk := s.peers.PrivKey(s.local)
49 + if sk == nil {
50 + // may be fine for sk to be nil, just log a warning.
51 + log.Warning("Listener not given PrivateKey, so WILL NOT SECURE conns.")
52 + }
53 + list, err := conn.Listen(s.cg.Context(), maddr, s.local, sk)
54 if err != nil {
55 return err
56 }
57
48 - // add resolved local addresses to peer
49 - for _, addr := range resolved {
50 - s.local.AddAddress(addr)
51 - }
52 -
58 // AddListener to the peerstream Listener. this will begin accepting connections
59 // and streams!
60 _, err = s.swarm.AddListener(list)
@@ -60,21 +65,22 @@ func (s *Swarm) setupListener(maddr ma.Multiaddr) error {
65 // here we configure it slightly. Note that this is sequential, so if anything
66 // will take a while do it in a goroutine.
67 // See https://godoc.org/github.com/jbenet/go-peerstream for more information
63 -func (s *Swarm) connHandler(c *ps.Conn) {
64 - go func() {
65 - ctx := context.Background()
66 - // this context is for running the handshake, which -- when receiveing connections
67 - // -- we have no bound on beyond what the transport protocol bounds it at.
68 - // note that setup + the handshake are bounded by underlying io.
69 - // (i.e. if TCP or UDP disconnects (or the swarm closes), we're done.
70 - // Q: why not have a shorter handshake? think about an HTTP server on really slow conns.
71 - // as long as the conn is live (TCP says its online), it tries its best. we follow suit.)
68 +func (s *Swarm) connHandler(c *ps.Conn) *Conn {
69 + ctx := context.Background()
70 + // this context is for running the handshake, which -- when receiveing connections
71 + // -- we have no bound on beyond what the transport protocol bounds it at.
72 + // note that setup + the handshake are bounded by underlying io.
73 + // (i.e. if TCP or UDP disconnects (or the swarm closes), we're done.
74 + // Q: why not have a shorter handshake? think about an HTTP server on really slow conns.
75 + // as long as the conn is live (TCP says its online), it tries its best. we follow suit.)
76
73 - if _, err := s.newConnSetup(ctx, c); err != nil {
74 - log.Error(err)
75 - log.Event(ctx, "newConnHandlerDisconnect", lgbl.NetConn(c.NetConn()), lgbl.Error(err))
76 - c.Close() // boom. close it.
77 - return
78 - }
79 - }()
77 + sc, err := s.newConnSetup(ctx, c)
78 + if err != nil {
79 + log.Error(err)
80 + log.Event(ctx, "newConnHandlerDisconnect", lgbl.NetConn(c.NetConn()), lgbl.Error(err))
81 + c.Close() // boom. close it.
82 + return nil
83 + }
84 +
85 + return sc
86 }
net/swarm/swarm_test.go
+83 -89
@@ -7,9 +7,7 @@ import (
7 "testing"
8 "time"
9
10 - ci "github.com/jbenet/go-ipfs/crypto"
10 peer "github.com/jbenet/go-ipfs/peer"
12 - u "github.com/jbenet/go-ipfs/util"
11 errors "github.com/jbenet/go-ipfs/util/debugerror"
12 testutil "github.com/jbenet/go-ipfs/util/testutil"
13
@@ -48,88 +46,68 @@ func EchoStreamHandler(stream *Stream) {
46 }()
47 }
48
51 -func setupPeer(t *testing.T, addr string) peer.Peer {
52 - tcp, err := ma.NewMultiaddr(addr)
53 - if err != nil {
54 - t.Fatal(err)
55 - }
49 +func makeSwarms(ctx context.Context, t *testing.T, num int) ([]*Swarm, []testutil.PeerNetParams) {
50 + swarms := make([]*Swarm, 0, num)
51 + peersnp := make([]testutil.PeerNetParams, 0, num)
52
57 - sk, pk, err := ci.GenerateKeyPair(ci.RSA, 512)
58 - if err != nil {
59 - t.Fatal(err)
60 - }
53 + for i := 0; i < num; i++ {
54 + localnp := testutil.RandPeerNetParams(t)
55 + peersnp = append(peersnp, localnp)
56
62 - p, err := testutil.NewPeerWithKeyPair(sk, pk)
63 - if err != nil {
64 - t.Fatal(err)
65 - }
66 - p.AddAddress(tcp)
67 - return p
68 -}
69 -
70 -func makeSwarms(ctx context.Context, t *testing.T, addrs []string) ([]*Swarm, []peer.Peer) {
71 - swarms := []*Swarm{}
72 -
73 - for _, addr := range addrs {
74 - local := setupPeer(t, addr)
57 peerstore := peer.NewPeerstore()
76 - swarm, err := NewSwarm(ctx, local.Addresses(), local, peerstore)
58 + peerstore.AddAddress(localnp.ID, localnp.Addr)
59 + peerstore.AddPubKey(localnp.ID, localnp.PubKey)
60 + peerstore.AddPrivKey(localnp.ID, localnp.PrivKey)
61 +
62 + addrs := peerstore.Addresses(localnp.ID)
63 + swarm, err := NewSwarm(ctx, addrs, localnp.ID, peerstore)
64 if err != nil {
65 t.Fatal(err)
66 }
67 +
68 swarm.SetStreamHandler(EchoStreamHandler)
69 swarms = append(swarms, swarm)
70 }
71
84 - peers := make([]peer.Peer, len(swarms))
85 - for i, s := range swarms {
86 - peers[i] = s.local
87 - }
88 -
89 - return swarms, peers
72 + return swarms, peersnp
73 }
74
92 -func SubtestSwarm(t *testing.T, addrs []string, MsgNum int) {
93 - // t.Skip("skipping for another test")
94 -
95 - ctx := context.Background()
96 - swarms, peers := makeSwarms(ctx, t, addrs)
97 -
98 - // connect everyone
99 - {
100 - var wg sync.WaitGroup
101 - connect := func(s *Swarm, dst peer.Peer) {
102 - // copy for other peer
75 +func connectSwarms(t *testing.T, ctx context.Context, swarms []*Swarm, peersnp []testutil.PeerNetParams) {
76
104 - cp, err := s.peers.FindOrCreate(dst.ID())
105 - if err != nil {
106 - t.Fatal(err)
107 - }
108 - cp.AddAddress(dst.Addresses()[0])
109 -
110 - log.Infof("SWARM TEST: %s dialing %s", s.local, dst)
111 - if _, err := s.Dial(ctx, cp); err != nil {
112 - t.Fatal("error swarm dialing to peer", err)
113 - }
114 - log.Infof("SWARM TEST: %s connected to %s", s.local, dst)
115 - wg.Done()
77 + var wg sync.WaitGroup
78 + connect := func(s *Swarm, dst peer.ID, addr ma.Multiaddr) {
79 + // TODO: make a DialAddr func.
80 + s.peers.AddAddress(dst, addr)
81 + if _, err := s.Dial(ctx, dst); err != nil {
82 + t.Fatal("error swarm dialing to peer", err)
83 }
84 + wg.Done()
85 + }
86
118 - log.Info("Connecting swarms simultaneously.")
119 - for _, s := range swarms {
120 - for _, p := range peers {
121 - if p != s.local { // don't connect to self.
122 - wg.Add(1)
123 - connect(s, p)
124 - }
87 + log.Info("Connecting swarms simultaneously.")
88 + for _, s := range swarms {
89 + for _, p := range peersnp {
90 + if p.ID != s.local { // don't connect to self.
91 + wg.Add(1)
92 + connect(s, p.ID, p.Addr)
93 }
94 }
127 - wg.Wait()
95 + }
96 + wg.Wait()
97
129 - for _, s := range swarms {
130 - log.Infof("%s swarm routing table: %s", s.local, s.Peers())
131 - }
98 + for _, s := range swarms {
99 + log.Infof("%s swarm routing table: %s", s.local, s.Peers())
100 }
101 +}
102 +
103 +func SubtestSwarm(t *testing.T, SwarmNum int, MsgNum int) {
104 + // t.Skip("skipping for another test")
105 +
106 + ctx := context.Background()
107 + swarms, peersnp := makeSwarms(ctx, t, SwarmNum)
108 +
109 + // connect everyone
110 + connectSwarms(t, ctx, swarms, peersnp)
111
112 // ping/pong
113 for _, s1 := range swarms {
@@ -138,13 +116,8 @@ func SubtestSwarm(t *testing.T, addrs []string, MsgNum int) {
116 log.Debugf("-------------------------------------------------------")
117
118 _, cancel := context.WithCancel(ctx)
141 - peers, err := s1.peers.All()
142 - if err != nil {
143 - t.Fatal(err)
144 - }
145 -
146 - got := map[u.Key]int{}
147 - errChan := make(chan error, MsgNum*len(*peers))
119 + got := map[peer.ID]int{}
120 + errChan := make(chan error, MsgNum*len(peersnp))
121 streamChan := make(chan *Stream, MsgNum)
122
123 // send out "ping" x MsgNum to every peer
@@ -152,7 +125,7 @@ func SubtestSwarm(t *testing.T, addrs []string, MsgNum int) {
125 defer close(streamChan)
126
127 var wg sync.WaitGroup
155 - send := func(p peer.Peer) {
128 + send := func(p peer.ID) {
129 defer wg.Done()
130
131 // first, one stream per peer (nice)
@@ -173,13 +146,13 @@ func SubtestSwarm(t *testing.T, addrs []string, MsgNum int) {
146 streamChan <- stream
147 }
148
176 - for _, p := range *peers {
177 - if p == s1.local {
149 + for _, p := range peersnp {
150 + if p.ID == s1.local {
151 continue // dont send to self...
152 }
153
154 wg.Add(1)
182 - go send(p)
155 + go send(p.ID)
156 }
157 wg.Wait()
158 }()
@@ -188,7 +161,7 @@ func SubtestSwarm(t *testing.T, addrs []string, MsgNum int) {
161 go func() {
162 defer close(errChan)
163 count := 0
191 - countShouldBe := MsgNum * (len(*peers) - 1)
164 + countShouldBe := MsgNum * (len(peersnp) - 1)
165 for stream := range streamChan { // one per peer
166 defer stream.Close()
167
@@ -215,7 +188,7 @@ func SubtestSwarm(t *testing.T, addrs []string, MsgNum int) {
188 msgCount++
189 }
190
218 - got[p.Key()] = msgCount
191 + got[p] = msgCount
192 count += msgCount
193 }
194
@@ -232,8 +205,8 @@ func SubtestSwarm(t *testing.T, addrs []string, MsgNum int) {
205 }
206
207 log.Debugf("%s got pongs", s1.local)
235 - if (len(*peers) - 1) != len(got) {
236 - t.Error("got less messages than sent")
208 + if (len(peersnp) - 1) != len(got) {
209 + t.Errorf("got (%d) less messages than sent (%d).", len(got), len(peersnp))
210 }
211
212 for p, n := range got {
@@ -254,15 +227,36 @@ func SubtestSwarm(t *testing.T, addrs []string, MsgNum int) {
227 func TestSwarm(t *testing.T) {
228 // t.Skip("skipping for another test")
229
257 - addrs := []string{
258 - "/ip4/127.0.0.1/tcp/10234",
259 - "/ip4/127.0.0.1/tcp/10235",
260 - "/ip4/127.0.0.1/tcp/10236",
261 - "/ip4/127.0.0.1/tcp/10237",
262 - "/ip4/127.0.0.1/tcp/10238",
263 - }
264 -
230 // msgs := 1000
231 msgs := 100
267 - SubtestSwarm(t, addrs, msgs)
232 + swarms := 5
233 + SubtestSwarm(t, swarms, msgs)
234 +}
235 +
236 +func TestConnHandler(t *testing.T) {
237 + // t.Skip("skipping for another test")
238 +
239 + ctx := context.Background()
240 + swarms, peersnp := makeSwarms(ctx, t, 5)
241 +
242 + gotconn := make(chan struct{}, 10)
243 + swarms[0].SetConnHandler(func(conn *Conn) {
244 + gotconn <- struct{}{}
245 + })
246 +
247 + connectSwarms(t, ctx, swarms, peersnp)
248 +
249 + <-time.After(time.Millisecond)
250 + // should've gotten 5 by now.
251 + close(gotconn)
252 +
253 + expect := 4
254 + actual := 0
255 + for _ = range gotconn {
256 + actual++
257 + }
258 +
259 + if actual != expect {
260 + t.Fatal("should have connected to %d swarms. got: %d", actual, expect)
261 + }
262 }
peer/metrics.go new
+63
@@ -0,0 +1,63 @@
1 +package peer
2 +
3 +import (
4 + "sync"
5 + "time"
6 +)
7 +
8 +// LatencyEWMASmooting governs the decay of the EWMA (the speed
9 +// at which it changes). This must be a normalized (0-1) value.
10 +// 1 is 100% change, 0 is no change.
11 +var LatencyEWMASmoothing = 0.1
12 +
13 +// Metrics is just an object that tracks metrics
14 +// across a set of peers.
15 +type Metrics interface {
16 +
17 + // RecordLatency records a new latency measurement
18 + RecordLatency(ID, time.Duration)
19 +
20 + // LatencyEWMA returns an exponentially-weighted moving avg.
21 + // of all measurements of a peer's latency.
22 + LatencyEWMA(ID) time.Duration
23 +}
24 +
25 +type metrics struct {
26 + latmap map[ID]time.Duration
27 + latmu sync.RWMutex
28 +}
29 +
30 +func NewMetrics() Metrics {
31 + return &metrics{
32 + latmap: make(map[ID]time.Duration),
33 + }
34 +}
35 +
36 +// RecordLatency records a new latency measurement
37 +func (m *metrics) RecordLatency(p ID, next time.Duration) {
38 + nextf := float64(next)
39 + s := LatencyEWMASmoothing
40 + if s > 1 || s < 0 {
41 + s = 0.1 // ignore the knob. it's broken. look, it jiggles.
42 + }
43 +
44 + m.latmu.Lock()
45 + ewma, found := m.latmap[p]
46 + ewmaf := float64(ewma)
47 + if !found {
48 + m.latmap[p] = next // when no data, just take it as the mean.
49 + } else {
50 + nextf = ((1.0 - s) * ewmaf) + (s * nextf)
51 + m.latmap[p] = time.Duration(nextf)
52 + }
53 + m.latmu.Unlock()
54 +}
55 +
56 +// LatencyEWMA returns an exponentially-weighted moving avg.
57 +// of all measurements of a peer's latency.
58 +func (m *metrics) LatencyEWMA(p ID) time.Duration {
59 + m.latmu.RLock()
60 + lat := m.latmap[p]
61 + m.latmu.RUnlock()
62 + return time.Duration(lat)
63 +}
peer/metrics_test.go new
+40
@@ -0,0 +1,40 @@
1 +package peer_test
2 +
3 +import (
4 + "fmt"
5 + "math/rand"
6 + "testing"
7 + "time"
8 +
9 + peer "github.com/jbenet/go-ipfs/peer"
10 + testutil "github.com/jbenet/go-ipfs/util/testutil"
11 +)
12 +
13 +func TestLatencyEWMAFun(t *testing.T) {
14 + t.Skip("run it for fun")
15 +
16 + m := peer.NewMetrics()
17 + id, err := testutil.RandPeerID()
18 + if err != nil {
19 + t.Fatal(err)
20 + }
21 +
22 + mu := 100.0
23 + sig := 10.0
24 + next := func() time.Duration {
25 + mu = (rand.NormFloat64() * sig) + mu
26 + return time.Duration(mu)
27 + }
28 +
29 + print := func() {
30 + fmt.Printf("%3.f %3.f --> %d\n", sig, mu, m.LatencyEWMA(id))
31 + }
32 +
33 + for {
34 + select {
35 + case <-time.After(200 * time.Millisecond):
36 + m.RecordLatency(id, next())
37 + print()
38 + }
39 + }
40 +}
peer/peer.go
+67 -335
@@ -2,11 +2,8 @@
2 package peer
3
4 import (
5 - "bytes"
6 - "errors"
5 + "encoding/hex"
6 "fmt"
8 - "sync"
9 - "time"
7
8 b58 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
9 ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
@@ -18,139 +15,18 @@ import (
15
16 var log = u.Logger("peer")
17
21 -// ID is a byte slice representing the identity of a peer.
22 -type ID mh.Multihash
23 -
24 -// String is utililty function for printing out peer ID strings.
25 -func (id ID) String() string {
26 - return id.Pretty()
27 -}
28 -
29 -// Equal is utililty function for comparing two peer ID's
30 -func (id ID) Equal(other ID) bool {
31 - return bytes.Equal(id, other)
32 -}
18 +// ID represents the identity of a peer.
19 +type ID string
20
21 // Pretty returns a b58-encoded string of the ID
22 func (id ID) Pretty() string {
36 - return b58.Encode(id)
37 -}
38 -
39 -// DecodePrettyID returns a b58-encoded string of the ID
40 -func DecodePrettyID(s string) (ID, error) {
41 - m, err := mh.FromB58String(s)
42 - if err != nil {
43 - return nil, err
44 - }
45 - return ID(m), err
46 -}
47 -
48 -// IDFromPubKey retrieves a Public Key from the peer given by pk
49 -func IDFromPubKey(pk ic.PubKey) (ID, error) {
50 - b, err := pk.Bytes()
51 - if err != nil {
52 - return nil, err
53 - }
54 - hash := u.Hash(b)
55 - return ID(hash), nil
23 + return IDB58Encode(id)
24 }
25
58 -// Map maps Key (string) : *peer (slices are not comparable).
59 -type Map map[u.Key]Peer
60 -
61 -// Peer represents the identity information of an IPFS Node, including
62 -// ID, and relevant Addresses.
63 -type Peer interface {
64 -
65 - // TODO reduce the peer interface to be read-only. Force mutations to occur
66 - // on the peer store eg. peerstore.SetLatency(peerId, value).
67 -
68 - // ID returns the peer's ID
69 - ID() ID
70 -
71 - // Key returns the ID as a Key (string) for maps.
72 - Key() u.Key
73 -
74 - // Addresses returns the peer's multiaddrs
75 - Addresses() []ma.Multiaddr
76 -
77 - // AddAddress adds the given Multiaddr address to Peer's addresses.
78 - // returns whether this was a newly added address.
79 - AddAddress(a ma.Multiaddr) bool
80 -
81 - // NetAddress returns the first Multiaddr found for a given network.
82 - NetAddress(n string) ma.Multiaddr
83 -
84 - // Services returns the peer's services
85 - // Services() []mux.ProtocolID
86 - // SetServices([]mux.ProtocolID)
87 -
88 - // Priv/PubKey returns the peer's Private Key
89 - PrivKey() ic.PrivKey
90 - PubKey() ic.PubKey
91 -
92 - // LoadAndVerifyKeyPair unmarshalls, loads a private/public key pair.
93 - // Error if (a) unmarshalling fails, or (b) pubkey does not match id.
94 - LoadAndVerifyKeyPair(marshalled []byte) error
95 - VerifyAndSetPrivKey(sk ic.PrivKey) error
96 - VerifyAndSetPubKey(pk ic.PubKey) error
97 -
98 - // Get/SetLatency manipulate the current latency measurement.
99 - GetLatency() (out time.Duration)
100 - SetLatency(laten time.Duration)
101 -
102 - // Get/SetType indicate whether this is a local or remote peer
103 - GetType() Type
104 - SetType(Type)
105 -
106 - //Get/Set Agent and Protocol Versions
107 - GetVersions() (agent, protocol string)
108 - SetVersions(agent, protocol string)
109 - // Update with the data of another peer instance
110 - Update(Peer) error
111 -
112 - Loggable() map[string]interface{}
113 -}
114 -
115 -type Type uint8
116 -
117 -const (
118 - // Unspecified indicates peer was created without specifying Type
119 - Unspecified Type = iota
120 - Local
121 - Remote
122 -)
123 -
124 -func (t Type) String() string {
125 - switch t {
126 - case Local:
127 - return "localPeer"
128 - case Remote:
129 - return "remotePeer"
130 - default:
26 +func (id ID) Loggable() map[string]interface{} {
27 + return map[string]interface{}{
28 + "peerID": id.Pretty(),
29 }
132 - return "unspecifiedPeer"
133 -}
134 -
135 -type peer struct {
136 - id ID
137 - addresses []ma.Multiaddr
138 - // services []mux.ProtocolID
139 -
140 - privKey ic.PrivKey
141 - pubKey ic.PubKey
142 -
143 - // TODO move latency away from peer into the package that uses it. Instead,
144 - // within that package, map from ID to latency value.
145 - latency time.Duration
146 -
147 - protocolVersion string
148 - agentVersion string
149 -
150 - // typ can be Local, Remote, or Unspecified (default)
151 - typ Type
152 -
153 - sync.RWMutex
30 }
31
32 // String prints out the peer.
@@ -159,242 +35,98 @@ type peer struct {
35 // enforce this by only exposing functions that generate
36 // IDs safely. Then any peer.ID type found in the
37 // codebase is known to be correct.
162 -func (p *peer) String() string {
163 - pid := p.id.String()
38 +func (id ID) String() string {
39 + pid := id.Pretty()
40 maxRunes := 6
41 if len(pid) < maxRunes {
42 maxRunes = len(pid)
43 }
168 - return fmt.Sprintf("peer %s", pid[:maxRunes])
169 -}
170 -
171 -func (p *peer) Loggable() map[string]interface{} {
172 - return map[string]interface{}{
173 - p.GetType().String(): map[string]interface{}{
174 - "id": p.ID().String(),
175 - "latency": p.GetLatency(),
176 - },
177 - }
178 -}
179 -
180 -// Key returns the ID as a Key (string) for maps.
181 -func (p *peer) Key() u.Key {
182 - return u.Key(p.id)
183 -}
184 -
185 -// ID returns the peer's ID
186 -func (p *peer) ID() ID {
187 - return p.id
188 -}
189 -
190 -// PrivKey returns the peer's Private Key
191 -func (p *peer) PrivKey() ic.PrivKey {
192 - return p.privKey
193 -}
194 -
195 -// PubKey returns the peer's Private Key
196 -func (p *peer) PubKey() ic.PubKey {
197 - return p.pubKey
44 + return fmt.Sprintf("<peer.ID %s>", pid[:maxRunes])
45 }
46
200 -// Addresses returns the peer's multiaddrs
201 -func (p *peer) Addresses() []ma.Multiaddr {
202 - cp := make([]ma.Multiaddr, len(p.addresses))
203 - p.RLock()
204 - copy(cp, p.addresses)
205 - defer p.RUnlock()
206 - return cp
47 +// MatchesPrivateKey tests whether this ID was derived from sk
48 +func (id ID) MatchesPrivateKey(sk ic.PrivKey) bool {
49 + return id.MatchesPublicKey(sk.GetPublic())
50 }
51
209 -// AddAddress adds the given Multiaddr address to Peer's addresses.
210 -// Returns whether this address was a newly added address
211 -func (p *peer) AddAddress(a ma.Multiaddr) bool {
212 - if a == nil {
213 - panic("adding a nil Multiaddr")
214 - }
215 -
216 - p.Lock()
217 - defer p.Unlock()
218 -
219 - for _, addr := range p.addresses {
220 - if addr.Equal(a) {
221 - return false
222 - }
52 +// MatchesPublicKey tests whether this ID was derived from pk
53 +func (id ID) MatchesPublicKey(pk ic.PubKey) bool {
54 + oid, err := IDFromPublicKey(pk)
55 + if err != nil {
56 + return false
57 }
224 - p.addresses = append(p.addresses, a)
225 - return true
58 + return oid == id
59 }
60
228 -// NetAddress returns the first Multiaddr found for a given network.
229 -func (p *peer) NetAddress(n string) ma.Multiaddr {
230 - p.RLock()
231 - defer p.RUnlock()
232 -
233 - for _, a := range p.addresses {
234 - for _, p := range a.Protocols() {
235 - if p.Name == n {
236 - return a
237 - }
238 - }
61 +// IDFromString cast a string to ID type, and validate
62 +// the id to make sure it is a multihash.
63 +func IDFromString(s string) (ID, error) {
64 + if _, err := mh.Cast([]byte(s)); err != nil {
65 + return ID(""), err
66 }
240 - return nil
241 -}
242 -
243 -// func (p *peer) Services() []mux.ProtocolID {
244 -// p.RLock()
245 -// defer p.RUnlock()
246 -// return p.services
247 -// }
248 -//
249 -// func (p *peer) SetServices(s []mux.ProtocolID) {
250 -// p.Lock()
251 -// defer p.Unlock()
252 -// p.services = s
253 -// }
254 -
255 -// GetLatency retrieves the current latency measurement.
256 -func (p *peer) GetLatency() (out time.Duration) {
257 - p.RLock()
258 - out = p.latency
259 - p.RUnlock()
260 - return
67 + return ID(s), nil
68 }
69
263 -// SetLatency sets the latency measurement.
264 -// TODO: Instead of just keeping a single number,
265 -// keep a running average over the last hour or so
266 -// Yep, should be EWMA or something. (-jbenet)
267 -func (p *peer) SetLatency(laten time.Duration) {
268 - p.Lock()
269 - if p.latency == 0 {
270 - p.latency = laten
271 - } else {
272 - p.latency = ((p.latency * 9) + laten) / 10
70 +// IDFromBytes cast a string to ID type, and validate
71 +// the id to make sure it is a multihash.
72 +func IDFromBytes(b []byte) (ID, error) {
73 + if _, err := mh.Cast(b); err != nil {
74 + return ID(""), err
75 }
274 - p.Unlock()
76 + return ID(b), nil
77 }
78
277 -func (p *peer) SetType(t Type) {
278 - p.Lock()
279 - p.typ = t
280 - defer p.Unlock()
79 +// IDB58Decode returns a b58-decoded Peer
80 +func IDB58Decode(s string) (ID, error) {
81 + m, err := mh.FromB58String(s)
82 + if err != nil {
83 + return "", err
84 + }
85 + return ID(m), err
86 }
87
283 -func (p *peer) GetType() Type {
284 - p.Lock()
285 - defer p.Unlock()
286 - return p.typ
88 +// IDB58Encode returns b58-encoded string
89 +func IDB58Encode(id ID) string {
90 + return b58.Encode([]byte(id))
91 }
92
289 -// LoadAndVerifyKeyPair unmarshalls, loads a private/public key pair.
290 -// Error if (a) unmarshalling fails, or (b) pubkey does not match id.
291 -func (p *peer) LoadAndVerifyKeyPair(marshalled []byte) error {
292 - sk, err := ic.UnmarshalPrivateKey(marshalled)
93 +// IDHexDecode returns a b58-decoded Peer
94 +func IDHexDecode(s string) (ID, error) {
95 + m, err := mh.FromHexString(s)
96 if err != nil {
294 - return fmt.Errorf("Failed to unmarshal private key: %v", err)
97 + return "", err
98 }
296 -
297 - return p.VerifyAndSetPrivKey(sk)
99 + return ID(m), err
100 }
101
300 -// VerifyAndSetPrivKey sets private key, given its pubkey matches the peer.ID
301 -func (p *peer) VerifyAndSetPrivKey(sk ic.PrivKey) error {
302 -
303 - // construct and assign pubkey. ensure it matches this peer
304 - if err := p.VerifyAndSetPubKey(sk.GetPublic()); err != nil {
305 - return err
306 - }
307 -
308 - p.Lock()
309 - defer p.Unlock()
310 -
311 - // if we didn't have the priavte key, assign it
312 - if p.privKey == nil {
313 - p.privKey = sk
314 - return nil
315 - }
316 -
317 - // if we already had the keys, check they're equal.
318 - if p.privKey.Equals(sk) {
319 - return nil // as expected. keep the old objects.
320 - }
321 -
322 - // keys not equal. invariant violated. this warrants a panic.
323 - // these keys should be _the same_ because peer.ID = H(pk)
324 - // this mismatch should never happen.
325 - log.Errorf("%s had PrivKey: %v -- got %v", p, p.privKey, sk)
326 - panic("invariant violated: unexpected key mismatch")
102 +// IDHexEncode returns b58-encoded string
103 +func IDHexEncode(id ID) string {
104 + return hex.EncodeToString([]byte(id))
105 }
106
329 -// VerifyAndSetPubKey sets public key, given it matches the peer.ID
330 -func (p *peer) VerifyAndSetPubKey(pk ic.PubKey) error {
331 - pkid, err := IDFromPubKey(pk)
107 +// IDFromPublicKey returns the Peer ID corresponding to pk
108 +func IDFromPublicKey(pk ic.PubKey) (ID, error) {
109 + b, err := pk.Bytes()
110 if err != nil {
333 - return fmt.Errorf("Failed to hash public key: %v", err)
111 + return "", err
112 }
335 -
336 - p.Lock()
337 - defer p.Unlock()
338 -
339 - if !p.id.Equal(pkid) {
340 - return fmt.Errorf("Public key does not match peer.ID.")
341 - }
342 -
343 - // if we didn't have the keys, assign them.
344 - if p.pubKey == nil {
345 - p.pubKey = pk
346 - return nil
347 - }
348 -
349 - // if we already had the pubkey, check they're equal.
350 - if p.pubKey.Equals(pk) {
351 - return nil // as expected. keep the old objects.
352 - }
353 -
354 - // keys not equal. invariant violated. this warrants a panic.
355 - // these keys should be _the same_ because peer.ID = H(pk)
356 - // this mismatch should never happen.
357 - log.Errorf("%s had PubKey: %v -- got %v", p, p.pubKey, pk)
358 - panic("invariant violated: unexpected key mismatch")
113 + hash := u.Hash(b)
114 + return ID(hash), nil
115 }
116
361 -// Updates this peer with information from another peer instance
362 -func (p *peer) Update(other Peer) error {
363 - if !p.ID().Equal(other.ID()) {
364 - return errors.New("peer ids do not match")
365 - }
366 -
367 - for _, a := range other.Addresses() {
368 - p.AddAddress(a)
369 - }
370 -
371 - p.SetLatency(other.GetLatency())
372 -
373 - p.SetType(other.GetType())
374 -
375 - sk := other.PrivKey()
376 - pk := other.PubKey()
377 - p.Lock()
378 - if p.privKey == nil {
379 - p.privKey = sk
380 - }
381 -
382 - if p.pubKey == nil {
383 - p.pubKey = pk
384 - }
385 - defer p.Unlock()
386 - return nil
117 +// IDFromPrivateKey returns the Peer ID corresponding to sk
118 +func IDFromPrivateKey(sk ic.PrivKey) (ID, error) {
119 + return IDFromPublicKey(sk.GetPublic())
120 }
121
389 -func (p *peer) GetVersions() (agent, protocol string) {
390 - p.RLock()
391 - defer p.RUnlock()
392 - return p.agentVersion, p.protocolVersion
393 -}
122 +// Map maps a Peer ID to a struct.
123 +type Set map[ID]struct{}
124
395 -func (p *peer) SetVersions(agent, protocol string) {
396 - p.Lock()
397 - defer p.Unlock()
398 - p.agentVersion = agent
399 - p.protocolVersion = protocol
125 +// PeerInfo is a small struct used to pass around a peer with
126 +// a set of addresses (and later, keys?). This is not meant to be
127 +// a complete view of the system, but rather to model updates to
128 +// the peerstore. It is used by things like the routing system.
129 +type PeerInfo struct {
130 + ID ID
131 + Addrs []ma.Multiaddr
132 }
peer/peer_test.go
+132 -36
@@ -1,65 +1,161 @@
1 package peer
2
3 import (
4 + "encoding/base64"
5 + "fmt"
6 + "strings"
7 "testing"
8
6 - ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
7 - mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
9 + ic "github.com/jbenet/go-ipfs/crypto"
10 + u "github.com/jbenet/go-ipfs/util"
11 +
12 + b58 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
13 )
14
10 -func TestNetAddress(t *testing.T) {
15 +var gen1 keyset // generated
16 +var gen2 keyset // generated
17 +var man keyset // manual
18
12 - tcp, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/1234")
13 - if err != nil {
14 - t.Error(err)
15 - return
19 +func init() {
20 + if err := gen1.generate(); err != nil {
21 + panic(err)
22 }
23 + if err := gen2.generate(); err != nil {
24 + panic(err)
25 + }
26 +
27 + skManBytes = strings.Replace(skManBytes, "\n", "", -1)
28 + if err := man.load(hpkpMan, skManBytes); err != nil {
29 + panic(err)
30 + }
31 +}
32 +
33 +type keyset struct {
34 + sk ic.PrivKey
35 + pk ic.PubKey
36 + hpk string
37 + hpkp string
38 +}
39
18 - udp, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/2345")
40 +func (ks *keyset) generate() error {
41 + var err error
42 + ks.sk, ks.pk, err = ic.GenerateKeyPair(ic.RSA, 1024)
43 if err != nil {
20 - t.Error(err)
21 - return
44 + return err
45 }
46
24 - mh, err := mh.FromHexString("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")
47 + bpk, err := ks.pk.Bytes()
48 if err != nil {
26 - t.Error(err)
27 - return
49 + return err
50 }
51
30 - p := NewPeerstore().WithID(ID(mh))
31 - p.AddAddress(tcp)
32 - p.AddAddress(udp)
33 - p.AddAddress(tcp)
52 + ks.hpk = string(u.Hash(bpk))
53 + ks.hpkp = b58.Encode([]byte(ks.hpk))
54 + return nil
55 +}
56
35 - if len(p.Addresses()) == 3 {
36 - t.Error("added same address twice")
57 +func (ks *keyset) load(hpkp, skBytesStr string) error {
58 + skBytes, err := base64.StdEncoding.DecodeString(skBytesStr)
59 + if err != nil {
60 + return err
61 }
62
39 - tcp2 := p.NetAddress("tcp")
40 - if tcp2 != tcp {
41 - t.Error("NetAddress lookup failed", tcp, tcp2)
63 + ks.sk, err = ic.UnmarshalPrivateKey(skBytes)
64 + if err != nil {
65 + return err
66 + }
67 +
68 + ks.pk = ks.sk.GetPublic()
69 + bpk, err := ks.pk.Bytes()
70 + if err != nil {
71 + return err
72 }
73
44 - udp2 := p.NetAddress("udp")
45 - if udp2 != udp {
46 - t.Error("NetAddress lookup failed", udp, udp2)
74 + ks.hpk = string(u.Hash(bpk))
75 + ks.hpkp = b58.Encode([]byte(ks.hpk))
76 + if ks.hpkp != hpkp {
77 + return fmt.Errorf("hpkp doesn't match key. %s", hpkp)
78 }
79 + return nil
80 }
81
50 -func TestStringMethodWithSmallId(t *testing.T) {
51 - p := NewPeerstore().WithID([]byte(string(0)))
52 - p1, ok := p.(*peer)
53 - if !ok {
54 - t.Fatal("WithID doesn't return a peer")
82 +func TestIDMatchesPublicKey(t *testing.T) {
83 +
84 + test := func(ks keyset) {
85 + p1, err := IDB58Decode(ks.hpkp)
86 + if err != nil {
87 + t.Fatal(err)
88 + }
89 +
90 + if ks.hpk != string(p1) {
91 + t.Error("p1 and hpk differ")
92 + }
93 +
94 + if !p1.MatchesPublicKey(ks.pk) {
95 + t.Fatal("p1 does not match pk")
96 + }
97 +
98 + p2, err := IDFromPublicKey(ks.pk)
99 + if err != nil {
100 + t.Fatal(err)
101 + }
102 +
103 + if p1 != p2 {
104 + t.Error("p1 and p2 differ", p1.Pretty(), p2.Pretty())
105 + }
106 +
107 + if p2.Pretty() != ks.hpkp {
108 + t.Error("hpkp and p2.Pretty differ", ks.hpkp, p2.Pretty())
109 + }
110 }
56 - p1.String()
111 +
112 + test(gen1)
113 + test(gen2)
114 + test(man)
115 }
116
59 -func TestDefaultType(t *testing.T) {
60 - t.Log("Ensure that peers are initialized to Unspecified by default")
61 - p := peer{}
62 - if p.GetType() != Unspecified {
63 - t.Fatalf("Peer's default type is was not `Unspecified`")
117 +func TestIDMatchesPrivateKey(t *testing.T) {
118 +
119 + test := func(ks keyset) {
120 + p1, err := IDB58Decode(ks.hpkp)
121 + if err != nil {
122 + t.Fatal(err)
123 + }
124 +
125 + if ks.hpk != string(p1) {
126 + t.Error("p1 and hpk differ")
127 + }
128 +
129 + if !p1.MatchesPrivateKey(ks.sk) {
130 + t.Fatal("p1 does not match sk")
131 + }
132 +
133 + p2, err := IDFromPrivateKey(ks.sk)
134 + if err != nil {
135 + t.Fatal(err)
136 + }
137 +
138 + if p1 != p2 {
139 + t.Error("p1 and p2 differ", p1.Pretty(), p2.Pretty())
140 + }
141 }
142 +
143 + test(gen1)
144 + test(gen2)
145 + test(man)
146 }
147 +
148 +var hpkpMan = `QmRK3JgmVEGiewxWbhpXLJyjWuGuLeSTMTndA1coMHEy5o`
149 +var skManBytes = `
150 +CAAS4AQwggJcAgEAAoGBAL7w+Wc4VhZhCdM/+Hccg5Nrf4q9NXWwJylbSrXz/unFS24wyk6pEk0zi3W
151 +7li+vSNVO+NtJQw9qGNAMtQKjVTP+3Vt/jfQRnQM3s6awojtjueEWuLYVt62z7mofOhCtj+VwIdZNBo
152 +/EkLZ0ETfcvN5LVtLYa8JkXybnOPsLvK+PAgMBAAECgYBdk09HDM7zzL657uHfzfOVrdslrTCj6p5mo
153 +DzvCxLkkjIzYGnlPuqfNyGjozkpSWgSUc+X+EGLLl3WqEOVdWJtbM61fewEHlRTM5JzScvwrJ39t7o6
154 +CCAjKA0cBWBd6UWgbN/t53RoWvh9HrA2AW5YrT0ZiAgKe9y7EMUaENVJ8QJBAPhpdmb4ZL4Fkm4OKia
155 +NEcjzn6mGTlZtef7K/0oRC9+2JkQnCuf6HBpaRhJoCJYg7DW8ZY+AV6xClKrgjBOfERMCQQDExhnzu2
156 +dsQ9k8QChBlpHO0TRbZBiQfC70oU31kM1AeLseZRmrxv9Yxzdl8D693NNWS2JbKOXl0kMHHcuGQLMVA
157 +kBZ7WvkmPV3aPL6jnwp2pXepntdVnaTiSxJ1dkXShZ/VSSDNZMYKY306EtHrIu3NZHtXhdyHKcggDXr
158 +qkBrdgErAkAlpGPojUwemOggr4FD8sLX1ot2hDJyyV7OK2FXfajWEYJyMRL1Gm9Uk1+Un53RAkJneqp
159 +JGAzKpyttXBTIDO51AkEA98KTiROMnnU8Y6Mgcvr68/SMIsvCYMt9/mtwSBGgl80VaTQ5Hpaktl6Xbh
160 +VUt5Wv0tRxlXZiViCGCD1EtrrwTw==
161 +`
peer/peerstore.go
+202 -82
@@ -1,132 +1,252 @@
1 package peer
2
3 import (
4 + "errors"
5 "sync"
6
7 ic "github.com/jbenet/go-ipfs/crypto"
7 - u "github.com/jbenet/go-ipfs/util"
8 - errors "github.com/jbenet/go-ipfs/util/debugerror"
8 +
9 + ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
10 + dssync "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync"
11 + ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
12 )
13
11 -// Peerstore provides a threadsafe collection for peers.
14 +// Peerstore provides a threadsafe store of Peer related
15 +// information.
16 type Peerstore interface {
13 - FindOrCreate(ID) (Peer, error)
14 - Add(Peer) (Peer, error)
15 - Delete(ID) error
16 - All() (*Map, error)
17 + KeyBook
18 + AddressBook
19 + Metrics
20 +
21 + // Peers returns a list of all peer.IDs in this Peerstore
22 + Peers() []ID
23 +
24 + // PeerInfo returns a peer.PeerInfo struct for given peer.ID.
25 + // This is a small slice of the information Peerstore has on
26 + // that peer, useful to other services.
27 + PeerInfo(ID) PeerInfo
28 +
29 + // Get/Put is a simple registry for other peer-related key/value pairs.
30 + // if we find something we use often, it should become its own set of
31 + // methods. this is a last resort.
32 + Get(id ID, key string) (interface{}, error)
33 + Put(id ID, key string, val interface{}) error
34 +}
35
18 - WithKeyPair(sk ic.PrivKey, pk ic.PubKey) (Peer, error)
19 - WithID(id ID) Peer
20 - WithIDString(id string) Peer
36 +// AddressBook tracks the addresses of Peers
37 +type AddressBook interface {
38 + Addresses(ID) []ma.Multiaddr
39 + AddAddress(ID, ma.Multiaddr)
40 + AddAddresses(ID, []ma.Multiaddr)
41 }
42
23 -type peerstore struct {
43 +type addressMap map[string]ma.Multiaddr
44 +
45 +type addressbook struct {
46 + addrs map[ID]addressMap
47 sync.RWMutex
25 - data map[string]Peer // key is string(ID)
48 }
49
28 -// NewPeerstore creates a threadsafe collection of peers.
29 -func NewPeerstore() Peerstore {
30 - return &peerstore{
31 - data: make(map[string]Peer),
50 +func newAddressbook() *addressbook {
51 + return &addressbook{addrs: map[ID]addressMap{}}
52 +}
53 +
54 +func (ab *addressbook) Peers() []ID {
55 + ab.RLock()
56 + ps := make([]ID, 0, len(ab.addrs))
57 + for p := range ab.addrs {
58 + ps = append(ps, p)
59 }
60 + ab.RUnlock()
61 + return ps
62 }
63
35 -func (ps *peerstore) FindOrCreate(i ID) (Peer, error) {
36 - ps.Lock()
37 - defer ps.Unlock()
64 +func (ab *addressbook) Addresses(p ID) []ma.Multiaddr {
65 + ab.RLock()
66 + defer ab.RUnlock()
67 +
68 + maddrs, found := ab.addrs[p]
69 + if !found {
70 + return nil
71 + }
72
39 - if i == nil {
40 - panic("wat")
73 + maddrs2 := make([]ma.Multiaddr, 0, len(maddrs))
74 + for _, m := range maddrs {
75 + maddrs2 = append(maddrs2, m)
76 }
77 + return maddrs2
78 +}
79
43 - p, ok := ps.data[i.String()]
44 - if !ok { // not found, construct it ourselves, add it to datastore, and return.
80 +func (ab *addressbook) AddAddress(p ID, m ma.Multiaddr) {
81 + ab.Lock()
82 + defer ab.Unlock()
83
46 - // TODO(brian) kinda dangerous, no? If ID is invalid and doesn't
47 - // correspond to an actual valid peer ID, this peerstore will return an
48 - // instantiated peer value, allowing the error to propagate. It might
49 - // be better to nip this at the bud by returning nil and making the
50 - // client manually add a Peer. To keep the peerstore in control, this
51 - // can even be a peerstore method that performs cursory validation.
52 - //
53 - // Potential bad case: Suppose values arrive from untrusted providers
54 - // in the DHT.
55 - p = &peer{id: i}
56 - ps.data[i.String()] = p
84 + _, found := ab.addrs[p]
85 + if !found {
86 + ab.addrs[p] = addressMap{}
87 }
88 + ab.addrs[p][m.String()] = m
89 +}
90
59 - // no error, got it back fine
60 - return p, nil
91 +func (ab *addressbook) AddAddresses(p ID, ms []ma.Multiaddr) {
92 + ab.Lock()
93 + defer ab.Unlock()
94 +
95 + for _, m := range ms {
96 + _, found := ab.addrs[p]
97 + if !found {
98 + ab.addrs[p] = addressMap{}
99 + }
100 + ab.addrs[p][m.String()] = m
101 + }
102 +}
103 +
104 +// KeyBook tracks the Public keys of Peers.
105 +type KeyBook interface {
106 + PubKey(ID) ic.PubKey
107 + AddPubKey(ID, ic.PubKey) error
108 +
109 + PrivKey(ID) ic.PrivKey
110 + AddPrivKey(ID, ic.PrivKey) error
111 +}
112 +
113 +type keybook struct {
114 + pks map[ID]ic.PubKey
115 + sks map[ID]ic.PrivKey
116 +
117 + sync.RWMutex // same lock. wont happen a ton.
118 }
119
63 -func (p *peerstore) Add(peer Peer) (Peer, error) {
64 - p.Lock()
65 - defer p.Unlock()
120 +func newKeybook() *keybook {
121 + return &keybook{
122 + pks: map[ID]ic.PubKey{},
123 + sks: map[ID]ic.PrivKey{},
124 + }
125 +}
126
67 - existing, ok := p.data[peer.Key().String()]
68 - if !ok { // not found? just add and return.
69 - p.data[peer.Key().String()] = peer
70 - return peer, nil
127 +func (kb *keybook) Peers() []ID {
128 + kb.RLock()
129 + ps := make([]ID, 0, len(kb.pks)+len(kb.sks))
130 + for p := range kb.pks {
131 + ps = append(ps, p)
132 }
72 - // already here.
73 - if peer == existing {
74 - return peer, nil
133 + for p := range kb.sks {
134 + if _, found := kb.pks[p]; !found {
135 + ps = append(ps, p)
136 + }
137 }
76 - existing.Update(peer) // must do some merging.
77 - return existing, nil
138 + kb.RUnlock()
139 + return ps
140 +}
141 +
142 +func (kb *keybook) PubKey(p ID) ic.PubKey {
143 + kb.RLock()
144 + pk := kb.pks[p]
145 + kb.RUnlock()
146 + return pk
147 }
148
80 -func (p *peerstore) Delete(i ID) error {
81 - p.Lock()
82 - defer p.Unlock()
149 +func (kb *keybook) AddPubKey(p ID, pk ic.PubKey) error {
150
84 - delete(p.data, i.String())
151 + // check it's correct first
152 + if !p.MatchesPublicKey(pk) {
153 + return errors.New("ID does not match PublicKey")
154 + }
155 +
156 + kb.Lock()
157 + kb.pks[p] = pk
158 + kb.Unlock()
159 return nil
160 }
161
88 -func (p *peerstore) All() (*Map, error) {
89 - p.Lock()
90 - defer p.Unlock()
162 +func (kb *keybook) PrivKey(p ID) ic.PrivKey {
163 + kb.RLock()
164 + sk := kb.sks[p]
165 + kb.RUnlock()
166 + return sk
167 +}
168 +
169 +func (kb *keybook) AddPrivKey(p ID, sk ic.PrivKey) error {
170
92 - ps := Map{}
93 - for k, v := range p.data {
94 - ps[u.Key(k)] = v
171 + if sk == nil {
172 + return errors.New("sk is nil (PrivKey)")
173 }
96 - return &ps, nil
174 +
175 + // check it's correct first
176 + if !p.MatchesPrivateKey(sk) {
177 + return errors.New("ID does not match PrivateKey")
178 + }
179 +
180 + kb.Lock()
181 + kb.sks[p] = sk
182 + kb.Unlock()
183 + return nil
184 +}
185 +
186 +type peerstore struct {
187 + keybook
188 + addressbook
189 + metrics
190 +
191 + // store other data, like versions
192 + ds ds.ThreadSafeDatastore
193 }
194
99 -// WithKeyPair returns a Peer object with given keys.
100 -func (ps *peerstore) WithKeyPair(sk ic.PrivKey, pk ic.PubKey) (Peer, error) {
101 - if sk == nil && pk == nil {
102 - return nil, errors.Errorf("PeerWithKeyPair nil keys")
195 +// NewPeerstore creates a threadsafe collection of peers.
196 +func NewPeerstore() Peerstore {
197 + return &peerstore{
198 + keybook: *newKeybook(),
199 + addressbook: *newAddressbook(),
200 + metrics: *(NewMetrics()).(*metrics),
201 + ds: dssync.MutexWrap(ds.NewMapDatastore()),
202 }
203 +}
204 +
205 +func (ps *peerstore) Put(p ID, key string, val interface{}) error {
206 + dsk := ds.NewKey(string(p) + "/" + key)
207 + return ps.ds.Put(dsk, val)
208 +}
209 +
210 +func (ps *peerstore) Get(p ID, key string) (interface{}, error) {
211 + dsk := ds.NewKey(string(p) + "/" + key)
212 + return ps.ds.Get(dsk)
213 +}
214
105 - pk2 := sk.GetPublic()
106 - if pk == nil {
107 - pk = pk2
108 - } else if !pk.Equals(pk2) {
109 - return nil, errors.Errorf("key mismatch. pubkey is not privkey's pubkey")
215 +func (ps *peerstore) Peers() []ID {
216 + set := map[ID]struct{}{}
217 + for _, p := range ps.keybook.Peers() {
218 + set[p] = struct{}{}
219 + }
220 + for _, p := range ps.addressbook.Peers() {
221 + set[p] = struct{}{}
222 }
223
112 - pkid, err := IDFromPubKey(pk)
113 - if err != nil {
114 - return nil, errors.Errorf("Failed to hash public key: %v", err)
224 + pps := make([]ID, 0, len(set))
225 + for p := range set {
226 + pps = append(pps, p)
227 }
228 + return pps
229 +}
230
117 - p := &peer{id: pkid, pubKey: pk, privKey: sk}
118 - ps.Add(p)
119 - return p, nil
231 +func (ps *peerstore) PeerInfo(p ID) PeerInfo {
232 + return PeerInfo{
233 + ID: p,
234 + Addrs: ps.addressbook.Addresses(p),
235 + }
236 }
237
122 -// WithID constructs a peer with given ID.
123 -func (ps *peerstore) WithID(id ID) Peer {
124 - p := &peer{id: id}
125 - ps.Add(p)
126 - return p
238 +func PeerInfos(ps Peerstore, peers []ID) []PeerInfo {
239 + pi := make([]PeerInfo, len(peers))
240 + for i, p := range peers {
241 + pi[i] = ps.PeerInfo(p)
242 + }
243 + return pi
244 }
245
129 -// WithIDString constructs a peer with given ID (string).
130 -func (ps *peerstore) WithIDString(id string) Peer {
131 - return ps.WithID(ID(id))
246 +func PeerInfoIDs(pis []PeerInfo) []ID {
247 + ps := make([]ID, len(pis))
248 + for i, pi := range pis {
249 + ps[i] = pi.ID
250 + }
251 + return ps
252 }
peer/peerstore_test.go
+56 -69
@@ -1,90 +1,77 @@
1 package peer
2
3 import (
4 - "errors"
4 "testing"
5
6 ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
7 )
8
10 -func setupPeer(ps Peerstore, id string, addr string) (Peer, error) {
11 - tcp, err := ma.NewMultiaddr(addr)
9 +func IDS(t *testing.T, ids string) ID {
10 + id, err := IDB58Decode(ids)
11 if err != nil {
13 - return nil, err
12 + t.Fatal(err)
13 }
15 -
16 - p := ps.WithIDString(id)
17 - p.AddAddress(tcp)
18 - return p, nil
14 + return id
15 }
16
21 -func TestPeerstore(t *testing.T) {
22 -
23 - ps := NewPeerstore()
24 -
25 - p11, _ := setupPeer(ps, "11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31", "/ip4/127.0.0.1/tcp/1234")
26 - p21, _ := setupPeer(ps, "11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a32", "/ip4/127.0.0.1/tcp/2345")
27 - // p31, _ := setupPeer("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33", "/ip4/127.0.0.1/tcp/3456")
28 - // p41, _ := setupPeer("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a34", "/ip4/127.0.0.1/tcp/4567")
29 -
30 - p13, err := ps.Add(p11)
31 - if err != nil {
32 - t.Error(err)
33 - }
34 -
35 - if p13 != p11 {
36 - t.Error("these should be the same")
37 - }
38 -
39 - p12, err := ps.FindOrCreate(ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31"))
40 - if err != nil {
41 - t.Error(err)
42 - }
43 -
44 - if p11 != p12 {
45 - t.Error(errors.New("peers should be the same"))
46 - }
47 -
48 - p23, err := ps.Add(p21)
49 - if err != nil {
50 - t.Error(err)
51 - }
52 - if p23 != p21 {
53 - t.Error("These should be the same")
54 - }
55 -
56 - p22, err := ps.FindOrCreate(ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a32"))
57 - if err != nil {
58 - t.Error(err)
59 - }
60 -
61 - if p21 != p22 {
62 - t.Error(errors.New("peers should be the same"))
63 - }
64 -
65 - _, err = ps.FindOrCreate(ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"))
17 +func MA(t *testing.T, m string) ma.Multiaddr {
18 + maddr, err := ma.NewMultiaddr(m)
19 if err != nil {
67 - t.Error(errors.New("should not have an error here"))
20 + t.Fatal(err)
21 }
22 + return maddr
23 +}
24
70 - err = ps.Delete(ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31"))
71 - if err != nil {
72 - t.Error(err)
73 - }
25 +func TestAddresses(t *testing.T) {
26
75 - // reconstruct!
76 - _, err = ps.FindOrCreate(ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31"))
77 - if err != nil {
78 - t.Error(errors.New("should not have an error anyway. reconstruct!"))
79 - }
27 + ps := NewPeerstore()
28
81 - p22, err = ps.FindOrCreate(ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a32"))
82 - if err != nil {
83 - t.Error(err)
29 + id1 := IDS(t, "QmcNstKuwBBoVTpSCSDrwzjgrRcaYXK833Psuz2EMHwyQN")
30 + id2 := IDS(t, "QmRmPL3FDZKE3Qiwv1RosLdwdvbvg17b2hB39QPScgWKKZ")
31 + id3 := IDS(t, "QmPhi7vBsChP7sjRoZGgg7bcKqF6MmCcQwvRbDte8aJ6Kn")
32 +
33 + ma11 := MA(t, "/ip4/1.2.3.1/tcp/1111")
34 + ma21 := MA(t, "/ip4/1.2.3.2/tcp/1111")
35 + ma22 := MA(t, "/ip4/1.2.3.2/tcp/2222")
36 + ma31 := MA(t, "/ip4/1.2.3.3/tcp/1111")
37 + ma32 := MA(t, "/ip4/1.2.3.3/tcp/2222")
38 + ma33 := MA(t, "/ip4/1.2.3.3/tcp/3333")
39 +
40 + ps.AddAddress(id1, ma11)
41 + ps.AddAddress(id2, ma21)
42 + ps.AddAddress(id2, ma22)
43 + ps.AddAddress(id3, ma31)
44 + ps.AddAddress(id3, ma32)
45 + ps.AddAddress(id3, ma33)
46 +
47 + test := func(exp, act []ma.Multiaddr) {
48 + if len(exp) != len(act) {
49 + t.Fatal("lengths not the same")
50 + }
51 +
52 + for _, a := range exp {
53 + found := false
54 +
55 + for _, b := range act {
56 + if a.Equal(b) {
57 + found = true
58 + break
59 + }
60 + }
61 +
62 + if !found {
63 + t.Fatal("expected address %s not found", a)
64 + }
65 + }
66 }
67
86 - if p21 != p22 {
87 - t.Error(errors.New("peers should be the same"))
88 - }
68 + // test the Addresses return value
69 + test([]ma.Multiaddr{ma11}, ps.Addresses(id1))
70 + test([]ma.Multiaddr{ma21, ma22}, ps.Addresses(id2))
71 + test([]ma.Multiaddr{ma31, ma32, ma33}, ps.Addresses(id3))
72
73 + // test also the PeerInfo return
74 + test([]ma.Multiaddr{ma11}, ps.PeerInfo(id1).Addrs)
75 + test([]ma.Multiaddr{ma21, ma22}, ps.PeerInfo(id2).Addrs)
76 + test([]ma.Multiaddr{ma31, ma32, ma33}, ps.PeerInfo(id3).Addrs)
77 }
peer/queue/distance.go
+4 -4
@@ -13,7 +13,7 @@ import (
13 // peerMetric tracks a peer and its distance to something else.
14 type peerMetric struct {
15 // the peer
16 - peer peer.Peer
16 + peer peer.ID
17
18 // big.Int for XOR metric
19 metric *big.Int
@@ -64,11 +64,11 @@ func (pq *distancePQ) Len() int {
64 return len(pq.heap)
65 }
66
67 -func (pq *distancePQ) Enqueue(p peer.Peer) {
67 +func (pq *distancePQ) Enqueue(p peer.ID) {
68 pq.Lock()
69 defer pq.Unlock()
70
71 - distance := ks.XORKeySpace.Key(p.ID()).Distance(pq.from)
71 + distance := ks.XORKeySpace.Key([]byte(p)).Distance(pq.from)
72
73 heap.Push(&pq.heap, &peerMetric{
74 peer: p,
@@ -76,7 +76,7 @@ func (pq *distancePQ) Enqueue(p peer.Peer) {
76 })
77 }
78
79 -func (pq *distancePQ) Dequeue() peer.Peer {
79 +func (pq *distancePQ) Dequeue() peer.ID {
80 pq.Lock()
81 defer pq.Unlock()
82
peer/queue/interface.go
+2 -2
@@ -11,8 +11,8 @@ type PeerQueue interface {
11 Len() int
12
13 // Enqueue adds this node to the queue.
14 - Enqueue(peer.Peer)
14 + Enqueue(peer.ID)
15
16 // Dequeue retrieves the highest (smallest int) priority node
17 - Dequeue() peer.Peer
17 + Dequeue() peer.ID
18 }
peer/queue/queue_test.go
+8 -12
@@ -8,22 +8,18 @@ import (
8
9 peer "github.com/jbenet/go-ipfs/peer"
10 u "github.com/jbenet/go-ipfs/util"
11 - testutil "github.com/jbenet/go-ipfs/util/testutil"
11
12 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
13 )
14
16 -func newPeer(id string) peer.Peer {
17 - return testutil.NewPeerWithIDString(id)
18 -}
19 -
15 func TestQueue(t *testing.T) {
16
22 - p1 := newPeer("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31")
23 - p2 := newPeer("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a32")
24 - p3 := newPeer("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")
25 - p4 := newPeer("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a34")
26 - p5 := newPeer("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31")
17 + p1 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31") // these aren't valid, because need to hex-decode.
18 + p2 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a32") // these aren't valid, because need to hex-decode.
19 + p3 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33") // these aren't valid, because need to hex-decode.
20 + p4 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a34") // these aren't valid, because need to hex-decode.
21 + p5 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31") // these aren't valid, because need to hex-decode.
22 + // but they work.
23
24 // these are the peer.IDs' XORKeySpace Key values:
25 // [228 47 151 130 156 102 222 232 218 31 132 94 170 208 80 253 120 103 55 35 91 237 48 157 81 245 57 247 66 150 9 40]
@@ -67,10 +63,10 @@ func TestQueue(t *testing.T) {
63
64 }
65
70 -func newPeerTime(t time.Time) peer.Peer {
66 +func newPeerTime(t time.Time) peer.ID {
67 s := fmt.Sprintf("hmmm time: %v", t)
68 h := u.Hash([]byte(s))
73 - return testutil.NewPeerWithID(peer.ID(h))
69 + return peer.ID(h)
70 }
71
72 func TestSyncQueue(t *testing.T) {
peer/queue/sync.go
+8 -8
@@ -9,8 +9,8 @@ import (
9 // ChanQueue makes any PeerQueue synchronizable through channels.
10 type ChanQueue struct {
11 Queue PeerQueue
12 - EnqChan chan<- peer.Peer
13 - DeqChan <-chan peer.Peer
12 + EnqChan chan<- peer.ID
13 + DeqChan <-chan peer.ID
14 }
15
16 // NewChanQueue creates a ChanQueue by wrapping pq.
@@ -23,8 +23,8 @@ func NewChanQueue(ctx context.Context, pq PeerQueue) *ChanQueue {
23 func (cq *ChanQueue) process(ctx context.Context) {
24
25 // construct the channels here to be able to use them bidirectionally
26 - enqChan := make(chan peer.Peer)
27 - deqChan := make(chan peer.Peer)
26 + enqChan := make(chan peer.ID)
27 + deqChan := make(chan peer.ID)
28
29 cq.EnqChan = enqChan
30 cq.DeqChan = deqChan
@@ -32,8 +32,8 @@ func (cq *ChanQueue) process(ctx context.Context) {
32 go func() {
33 defer close(deqChan)
34
35 - var next peer.Peer
36 - var item peer.Peer
35 + var next peer.ID
36 + var item peer.ID
37 var more bool
38
39 for {
@@ -60,10 +60,10 @@ func (cq *ChanQueue) process(ctx context.Context) {
60
61 cq.Queue.Enqueue(item)
62 cq.Queue.Enqueue(next)
63 - next = nil
63 + next = ""
64
65 case deqChan <- next:
66 - next = nil
66 + next = ""
67
68 case <-ctx.Done():
69 return
routing/dht/dht.go
+67 -121
@@ -34,11 +34,10 @@ const doPinging = false
34 // It is used to implement the base IpfsRouting module.
35 type IpfsDHT struct {
36 network inet.Network // the network services we need
37 - self peer.Peer // Local peer (yourself)
38 - peerstore peer.Peerstore // Other peers
37 + self peer.ID // Local peer (yourself)
38 + peerstore peer.Peerstore // Peer Registry
39
40 - datastore ds.Datastore // Local data
41 - dslock sync.Mutex
40 + datastore ds.ThreadSafeDatastore // Local data
41
42 routingTable *kb.RoutingTable // Array of routing tables for differently distanced nodes
43 providers *ProviderManager
@@ -53,19 +52,19 @@ type IpfsDHT struct {
52 }
53
54 // NewDHT creates a new DHT object with the given peer as the 'local' host
56 -func NewDHT(ctx context.Context, p peer.Peer, ps peer.Peerstore, n inet.Network, dstore ds.Datastore) *IpfsDHT {
55 +func NewDHT(ctx context.Context, p peer.ID, n inet.Network, dstore ds.ThreadSafeDatastore) *IpfsDHT {
56 dht := new(IpfsDHT)
57 dht.datastore = dstore
58 dht.self = p
60 - dht.peerstore = ps
59 + dht.peerstore = n.Peerstore()
60 dht.ContextGroup = ctxgroup.WithContext(ctx)
61 dht.network = n
62 n.SetHandler(inet.ProtocolDHT, dht.handleNewStream)
63
65 - dht.providers = NewProviderManager(dht.Context(), p.ID())
64 + dht.providers = NewProviderManager(dht.Context(), p)
65 dht.AddChildGroup(dht.providers)
66
68 - dht.routingTable = kb.NewRoutingTable(20, kb.ConvertPeerID(p.ID()), time.Minute)
67 + dht.routingTable = kb.NewRoutingTable(20, kb.ConvertPeerID(p), time.Minute, dht.peerstore)
68 dht.birth = time.Now()
69
70 dht.Validators = make(map[string]ValidatorFunc)
@@ -79,7 +78,7 @@ func NewDHT(ctx context.Context, p peer.Peer, ps peer.Peerstore, n inet.Network,
78 }
79
80 // Connect to a new peer at the given address, ping and add to the routing table
82 -func (dht *IpfsDHT) Connect(ctx context.Context, npeer peer.Peer) error {
81 +func (dht *IpfsDHT) Connect(ctx context.Context, npeer peer.ID) error {
82 if err := dht.network.DialPeer(ctx, npeer); err != nil {
83 return err
84 }
@@ -95,7 +94,8 @@ func (dht *IpfsDHT) Connect(ctx context.Context, npeer peer.Peer) error {
94 }
95
96 // putValueToNetwork stores the given key/value pair at the peer 'p'
98 -func (dht *IpfsDHT) putValueToNetwork(ctx context.Context, p peer.Peer,
97 +// meaning: it sends a PUT_VALUE message to p
98 +func (dht *IpfsDHT) putValueToNetwork(ctx context.Context, p peer.ID,
99 key string, rec *pb.Record) error {
100
101 pmes := pb.NewMessage(pb.Message_PUT_VALUE, string(key), 0)
@@ -113,12 +113,13 @@ func (dht *IpfsDHT) putValueToNetwork(ctx context.Context, p peer.Peer,
113
114 // putProvider sends a message to peer 'p' saying that the local node
115 // can provide the value of 'key'
116 -func (dht *IpfsDHT) putProvider(ctx context.Context, p peer.Peer, key string) error {
116 +func (dht *IpfsDHT) putProvider(ctx context.Context, p peer.ID, key string) error {
117
118 pmes := pb.NewMessage(pb.Message_ADD_PROVIDER, string(key), 0)
119
120 // add self as the provider
121 - pmes.ProviderPeers = pb.PeersToPBPeers(dht.network, []peer.Peer{dht.self})
121 + pi := dht.peerstore.PeerInfo(dht.self)
122 + pmes.ProviderPeers = pb.PeerInfosToPBPeers(dht.network, []peer.PeerInfo{pi})
123
124 err := dht.sendMessage(ctx, p, pmes)
125 if err != nil {
@@ -130,8 +131,12 @@ func (dht *IpfsDHT) putProvider(ctx context.Context, p peer.Peer, key string) er
131 return nil
132 }
133
133 -func (dht *IpfsDHT) getValueOrPeers(ctx context.Context, p peer.Peer,
134 - key u.Key) ([]byte, []peer.Peer, error) {
134 +// getValueOrPeers queries a particular peer p for the value for
135 +// key. It returns either the value or a list of closer peers.
136 +// NOTE: it will update the dht's peerstore with any new addresses
137 +// it finds for the given peer.
138 +func (dht *IpfsDHT) getValueOrPeers(ctx context.Context, p peer.ID,
139 + key u.Key) ([]byte, []peer.PeerInfo, error) {
140
141 pmes, err := dht.getValueSingle(ctx, p, key)
142 if err != nil {
@@ -142,8 +147,8 @@ func (dht *IpfsDHT) getValueOrPeers(ctx context.Context, p peer.Peer,
147 // Success! We were given the value
148 log.Debug("getValueOrPeers: got value")
149
145 - // make sure record is still valid
146 - err = dht.verifyRecord(record)
150 + // make sure record is valid.
151 + err = dht.verifyRecordOnline(ctx, record)
152 if err != nil {
153 log.Error("Received invalid record!")
154 return nil, nil, err
@@ -151,24 +156,8 @@ func (dht *IpfsDHT) getValueOrPeers(ctx context.Context, p peer.Peer,
156 return record.GetValue(), nil, nil
157 }
158
154 - // TODO decide on providers. This probably shouldn't be happening.
155 - if prv := pmes.GetProviderPeers(); prv != nil && len(prv) > 0 {
156 - val, err := dht.getFromPeerList(ctx, key, prv)
157 - if err != nil {
158 - return nil, nil, err
159 - }
160 - log.Debug("getValueOrPeers: get from providers")
161 - return val, nil, nil
162 - }
163 -
159 // Perhaps we were given closer peers
165 - peers, errs := pb.PBPeersToPeers(dht.peerstore, pmes.GetCloserPeers())
166 - for _, err := range errs {
167 - if err != nil {
168 - log.Error(err)
169 - }
170 - }
171 -
160 + peers := pb.PBPeersToPeerInfos(pmes.GetCloserPeers())
161 if len(peers) > 0 {
162 log.Debug("getValueOrPeers: peers")
163 return nil, peers, nil
@@ -179,51 +168,16 @@ func (dht *IpfsDHT) getValueOrPeers(ctx context.Context, p peer.Peer,
168 }
169
170 // getValueSingle simply performs the get value RPC with the given parameters
182 -func (dht *IpfsDHT) getValueSingle(ctx context.Context, p peer.Peer,
171 +func (dht *IpfsDHT) getValueSingle(ctx context.Context, p peer.ID,
172 key u.Key) (*pb.Message, error) {
173
174 pmes := pb.NewMessage(pb.Message_GET_VALUE, string(key), 0)
175 return dht.sendRequest(ctx, p, pmes)
176 }
177
189 -// TODO: Im not certain on this implementation, we get a list of peers/providers
190 -// from someone what do we do with it? Connect to each of them? randomly pick
191 -// one to get the value from? Or just connect to one at a time until we get a
192 -// successful connection and request the value from it?
193 -func (dht *IpfsDHT) getFromPeerList(ctx context.Context, key u.Key,
194 - peerlist []*pb.Message_Peer) ([]byte, error) {
195 -
196 - for _, pinfo := range peerlist {
197 - p, err := dht.ensureConnectedToPeer(ctx, pinfo)
198 - if err != nil {
199 - log.Errorf("getFromPeers error: %s", err)
200 - continue
201 - }
202 -
203 - pmes, err := dht.getValueSingle(ctx, p, key)
204 - if err != nil {
205 - log.Errorf("getFromPeers error: %s\n", err)
206 - continue
207 - }
208 -
209 - if record := pmes.GetRecord(); record != nil {
210 - // Success! We were given the value
211 -
212 - err := dht.verifyRecord(record)
213 - if err != nil {
214 - return nil, err
215 - }
216 - dht.providers.AddProvider(key, p)
217 - return record.GetValue(), nil
218 - }
219 - }
220 - return nil, routing.ErrNotFound
221 -}
222 -
178 // getLocal attempts to retrieve the value from the datastore
179 func (dht *IpfsDHT) getLocal(key u.Key) ([]byte, error) {
225 - dht.dslock.Lock()
226 - defer dht.dslock.Unlock()
180 +
181 log.Debug("getLocal %s", key)
182 v, err := dht.datastore.Get(key.DsKey())
183 if err != nil {
@@ -243,7 +197,7 @@ func (dht *IpfsDHT) getLocal(key u.Key) ([]byte, error) {
197
198 // TODO: 'if paranoid'
199 if u.Debug {
246 - err = dht.verifyRecord(rec)
200 + err = dht.verifyRecordLocally(rec)
201 if err != nil {
202 log.Errorf("local record verify failed: %s", err)
203 return nil, err
@@ -269,41 +223,40 @@ func (dht *IpfsDHT) putLocal(key u.Key, value []byte) error {
223
224 // Update signals the routingTable to Update its last-seen status
225 // on the given peer.
272 -func (dht *IpfsDHT) Update(ctx context.Context, p peer.Peer) {
226 +func (dht *IpfsDHT) Update(ctx context.Context, p peer.ID) {
227 log.Event(ctx, "updatePeer", p)
228 dht.routingTable.Update(p)
229 }
230
231 // FindLocal looks for a peer with a given ID connected to this dht and returns the peer and the table it was found in.
278 -func (dht *IpfsDHT) FindLocal(id peer.ID) (peer.Peer, *kb.RoutingTable) {
232 +func (dht *IpfsDHT) FindLocal(id peer.ID) (peer.PeerInfo, *kb.RoutingTable) {
233 p := dht.routingTable.Find(id)
280 - if p != nil {
281 - return p, dht.routingTable
234 + if p != "" {
235 + return dht.peerstore.PeerInfo(p), dht.routingTable
236 }
283 - return nil, nil
237 + return peer.PeerInfo{}, nil
238 }
239
240 // findPeerSingle asks peer 'p' if they know where the peer with id 'id' is
287 -func (dht *IpfsDHT) findPeerSingle(ctx context.Context, p peer.Peer, id peer.ID) (*pb.Message, error) {
241 +func (dht *IpfsDHT) findPeerSingle(ctx context.Context, p peer.ID, id peer.ID) (*pb.Message, error) {
242 pmes := pb.NewMessage(pb.Message_FIND_NODE, string(id), 0)
243 return dht.sendRequest(ctx, p, pmes)
244 }
245
292 -func (dht *IpfsDHT) findProvidersSingle(ctx context.Context, p peer.Peer, key u.Key) (*pb.Message, error) {
246 +func (dht *IpfsDHT) findProvidersSingle(ctx context.Context, p peer.ID, key u.Key) (*pb.Message, error) {
247 pmes := pb.NewMessage(pb.Message_GET_PROVIDERS, string(key), 0)
248 return dht.sendRequest(ctx, p, pmes)
249 }
250
297 -func (dht *IpfsDHT) addProviders(key u.Key, pbps []*pb.Message_Peer) []peer.Peer {
298 - peers, errs := pb.PBPeersToPeers(dht.peerstore, pbps)
299 - for _, err := range errs {
300 - log.Errorf("error converting peer: %v", err)
301 - }
251 +func (dht *IpfsDHT) addProviders(key u.Key, pbps []*pb.Message_Peer) []peer.ID {
252 + peers := pb.PBPeersToPeerInfos(pbps)
253 +
254 + var provArr []peer.ID
255 + for _, pi := range peers {
256 + p := pi.ID
257
303 - var provArr []peer.Peer
304 - for _, p := range peers {
258 // Dont add outselves to the list
306 - if p.ID().Equal(dht.self.ID()) {
259 + if p == dht.self {
260 continue
261 }
262
@@ -316,14 +269,14 @@ func (dht *IpfsDHT) addProviders(key u.Key, pbps []*pb.Message_Peer) []peer.Peer
269 }
270
271 // nearestPeersToQuery returns the routing tables closest peers.
319 -func (dht *IpfsDHT) nearestPeersToQuery(pmes *pb.Message, count int) []peer.Peer {
272 +func (dht *IpfsDHT) nearestPeersToQuery(pmes *pb.Message, count int) []peer.ID {
273 key := u.Key(pmes.GetKey())
274 closer := dht.routingTable.NearestPeers(kb.ConvertKey(key), count)
275 return closer
276 }
277
278 // betterPeerToQuery returns nearestPeersToQuery, but iff closer than self.
326 -func (dht *IpfsDHT) betterPeersToQuery(pmes *pb.Message, count int) []peer.Peer {
279 +func (dht *IpfsDHT) betterPeersToQuery(pmes *pb.Message, count int) []peer.ID {
280 closer := dht.nearestPeersToQuery(pmes, count)
281
282 // no node? nil
@@ -333,17 +286,17 @@ func (dht *IpfsDHT) betterPeersToQuery(pmes *pb.Message, count int) []peer.Peer
286
287 // == to self? thats bad
288 for _, p := range closer {
336 - if p.ID().Equal(dht.self.ID()) {
289 + if p == dht.self {
290 log.Error("Attempted to return self! this shouldnt happen...")
291 return nil
292 }
293 }
294
342 - var filtered []peer.Peer
295 + var filtered []peer.ID
296 for _, p := range closer {
297 // must all be closer than self
298 key := u.Key(pmes.GetKey())
346 - if !kb.Closer(dht.self.ID(), p.ID(), key) {
299 + if !kb.Closer(dht.self, p, key) {
300 filtered = append(filtered, p)
301 }
302 }
@@ -352,30 +305,13 @@ func (dht *IpfsDHT) betterPeersToQuery(pmes *pb.Message, count int) []peer.Peer
305 return filtered
306 }
307
355 -// getPeer searches the peerstore for a peer with the given peer ID
356 -func (dht *IpfsDHT) getPeer(id peer.ID) (peer.Peer, error) {
357 - p, err := dht.peerstore.FindOrCreate(id)
358 - if err != nil {
359 - err = fmt.Errorf("Failed to get peer from peerstore: %s", err)
360 - log.Error(err)
361 - return nil, err
362 - }
363 - return p, nil
364 -}
365 -
366 -func (dht *IpfsDHT) ensureConnectedToPeer(ctx context.Context, pbp *pb.Message_Peer) (peer.Peer, error) {
367 - p, err := pb.PBPeerToPeer(dht.peerstore, pbp)
368 - if err != nil {
369 - return nil, err
370 - }
371 -
372 - if dht.self.ID().Equal(p.ID()) {
373 - return nil, errors.New("attempting to ensure connection to self")
308 +func (dht *IpfsDHT) ensureConnectedToPeer(ctx context.Context, p peer.ID) error {
309 + if p == dht.self {
310 + return errors.New("attempting to ensure connection to self")
311 }
312
313 // dial connection
377 - err = dht.network.DialPeer(ctx, p)
378 - return p, err
314 + return dht.network.DialPeer(ctx, p)
315 }
316
317 //TODO: this should be smarter about which keys it selects.
@@ -421,14 +357,24 @@ func (dht *IpfsDHT) PingRoutine(t time.Duration) {
357
358 // Bootstrap builds up list of peers by requesting random peer IDs
359 func (dht *IpfsDHT) Bootstrap(ctx context.Context) {
424 - id := make([]byte, 16)
425 - rand.Read(id)
426 - p, err := dht.FindPeer(ctx, peer.ID(id))
427 - if err != nil {
428 - log.Errorf("Bootstrap peer error: %s", err)
429 - }
430 - err = dht.network.DialPeer(ctx, p)
431 - if err != nil {
432 - log.Errorf("Bootstrap peer error: %s", err)
360 +
361 + var wg sync.WaitGroup
362 + for i := 0; i < 10; i++ {
363 + wg.Add(1)
364 + go func() {
365 + defer wg.Done()
366 +
367 + id := make([]byte, 16)
368 + rand.Read(id)
369 + pi, err := dht.FindPeer(ctx, peer.ID(id))
370 + if err != nil {
371 + // NOTE: this is not an error. this is expected!
372 + log.Errorf("Bootstrap peer error: %s", err)
373 + }
374 +
375 + // woah, we got a peer under a random id? it _cannot_ be valid.
376 + log.Errorf("dht seemingly found a peer at a random bootstrap id (%s)...", pi)
377 + }()
378 }
379 + wg.Wait()
380 }
routing/dht/dht_net.go
+3 -3
@@ -67,7 +67,7 @@ func (dht *IpfsDHT) handleNewMessage(s inet.Stream) {
67
68 // sendRequest sends out a request, but also makes sure to
69 // measure the RTT for latency measurements.
70 -func (dht *IpfsDHT) sendRequest(ctx context.Context, p peer.Peer, pmes *pb.Message) (*pb.Message, error) {
70 +func (dht *IpfsDHT) sendRequest(ctx context.Context, p peer.ID, pmes *pb.Message) (*pb.Message, error) {
71
72 log.Debugf("%s dht starting stream", dht.self)
73 s, err := dht.network.NewStream(inet.ProtocolDHT, p)
@@ -98,13 +98,13 @@ func (dht *IpfsDHT) sendRequest(ctx context.Context, p peer.Peer, pmes *pb.Messa
98 return nil, errors.New("no response to request")
99 }
100
101 - p.SetLatency(time.Since(start))
101 + dht.peerstore.RecordLatency(p, time.Since(start))
102 log.Event(ctx, "dhtReceivedMessage", dht.self, p, rpmes)
103 return rpmes, nil
104 }
105
106 // sendMessage sends out a message
107 -func (dht *IpfsDHT) sendMessage(ctx context.Context, p peer.Peer, pmes *pb.Message) error {
107 +func (dht *IpfsDHT) sendMessage(ctx context.Context, p peer.ID, pmes *pb.Message) error {
108
109 log.Debugf("%s dht starting stream", dht.self)
110 s, err := dht.network.NewStream(inet.ProtocolDHT, p)
routing/dht/dht_test.go
+107 -190
@@ -2,44 +2,47 @@ package dht
2
3 import (
4 "bytes"
5 - "math/rand"
5 "sort"
6 "testing"
7 + "time"
8
9 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
10
11 ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
12 + dssync "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync"
13 ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
14
14 - ci "github.com/jbenet/go-ipfs/crypto"
15 + // ci "github.com/jbenet/go-ipfs/crypto"
16 inet "github.com/jbenet/go-ipfs/net"
17 peer "github.com/jbenet/go-ipfs/peer"
18 u "github.com/jbenet/go-ipfs/util"
19 testutil "github.com/jbenet/go-ipfs/util/testutil"
19 -
20 - "fmt"
21 - "time"
20 )
21
24 -func randMultiaddr(t *testing.T) ma.Multiaddr {
22 +func setupDHT(ctx context.Context, t *testing.T, addr ma.Multiaddr) *IpfsDHT {
23
26 - s := fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 10000+rand.Intn(40000))
27 - a, err := ma.NewMultiaddr(s)
24 + sk, pk, err := testutil.RandKeyPair(512)
25 + if err != nil {
26 + t.Fatal(err)
27 + }
28 +
29 + p, err := peer.IDFromPublicKey(pk)
30 if err != nil {
31 t.Fatal(err)
32 }
31 - return a
32 -}
33
34 -func setupDHT(ctx context.Context, t *testing.T, p peer.Peer) *IpfsDHT {
34 peerstore := peer.NewPeerstore()
35 + peerstore.AddPrivKey(p, sk)
36 + peerstore.AddPubKey(p, pk)
37 + peerstore.AddAddress(p, addr)
38
37 - n, err := inet.NewNetwork(ctx, p.Addresses(), p, peerstore)
39 + n, err := inet.NewNetwork(ctx, []ma.Multiaddr{addr}, p, peerstore)
40 if err != nil {
41 t.Fatal(err)
42 }
43
42 - d := NewDHT(ctx, p, peerstore, n, ds.NewMapDatastore())
44 + dss := dssync.MutexWrap(ds.NewMapDatastore())
45 + d := NewDHT(ctx, p, n, dss)
46
47 d.Validators["v"] = func(u.Key, []byte) error {
48 return nil
@@ -47,77 +50,53 @@ func setupDHT(ctx context.Context, t *testing.T, p peer.Peer) *IpfsDHT {
50 return d
51 }
52
50 -func setupDHTS(ctx context.Context, n int, t *testing.T) ([]ma.Multiaddr, []peer.Peer, []*IpfsDHT) {
51 - var addrs []ma.Multiaddr
52 - for i := 0; i < n; i++ {
53 - r := rand.Intn(40000)
54 - a, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 10000+r))
55 - if err != nil {
56 - t.Fatal(err)
57 - }
58 - addrs = append(addrs, a)
59 - }
60 -
61 - var peers []peer.Peer
62 - for i := 0; i < n; i++ {
63 - p := makePeer(addrs[i])
64 - peers = append(peers, p)
65 - }
66 -
53 +func setupDHTS(ctx context.Context, n int, t *testing.T) ([]ma.Multiaddr, []peer.ID, []*IpfsDHT) {
54 + addrs := make([]ma.Multiaddr, n)
55 dhts := make([]*IpfsDHT, n)
56 + peers := make([]peer.ID, n)
57 +
58 for i := 0; i < n; i++ {
69 - dhts[i] = setupDHT(ctx, t, peers[i])
59 + addrs[i] = testutil.RandLocalTCPAddress()
60 + dhts[i] = setupDHT(ctx, t, addrs[i])
61 + peers[i] = dhts[i].self
62 }
63
64 return addrs, peers, dhts
65 }
66
75 -func makePeerString(t *testing.T, addr string) peer.Peer {
76 - maddr, err := ma.NewMultiaddr(addr)
77 - if err != nil {
78 - t.Fatal(err)
79 - }
80 - return makePeer(maddr)
81 -}
67 +func connect(t *testing.T, ctx context.Context, a, b *IpfsDHT) {
68
83 -func makePeer(addr ma.Multiaddr) peer.Peer {
84 - sk, pk, err := ci.GenerateKeyPair(ci.RSA, 512)
85 - if err != nil {
86 - panic(err)
69 + idB := b.self
70 + addrB := b.peerstore.Addresses(idB)
71 + if len(addrB) == 0 {
72 + t.Fatal("peers setup incorrectly: no local address")
73 }
88 - p, err := testutil.NewPeerWithKeyPair(sk, pk)
89 - if err != nil {
90 - panic(err)
74 +
75 + a.peerstore.AddAddresses(idB, addrB)
76 + if err := a.Connect(ctx, idB); err != nil {
77 + t.Fatal(err)
78 }
92 - p.AddAddress(addr)
93 - return p
79 }
80
81 func TestPing(t *testing.T) {
82 // t.Skip("skipping test to debug another")
83 ctx := context.Background()
84
100 - addrA := randMultiaddr(t)
101 - addrB := randMultiaddr(t)
85 + addrA := testutil.RandLocalTCPAddress()
86 + addrB := testutil.RandLocalTCPAddress()
87
103 - peerA := makePeer(addrA)
104 - peerB := makePeer(addrB)
88 + dhtA := setupDHT(ctx, t, addrA)
89 + dhtB := setupDHT(ctx, t, addrB)
90
106 - dhtA := setupDHT(ctx, t, peerA)
107 - dhtB := setupDHT(ctx, t, peerB)
91 + peerA := dhtA.self
92 + peerB := dhtB.self
93
94 defer dhtA.Close()
95 defer dhtB.Close()
96 defer dhtA.network.Close()
97 defer dhtB.network.Close()
98
114 - if err := dhtA.Connect(ctx, peerB); err != nil {
115 - t.Fatal(err)
116 - }
117 -
118 - // if err := dhtB.Connect(ctx, peerA); err != nil {
119 - // t.Fatal(err)
120 - // }
99 + connect(t, ctx, dhtA, dhtB)
100
101 //Test that we can ping the node
102 ctxT, _ := context.WithTimeout(ctx, 100*time.Millisecond)
@@ -136,14 +115,16 @@ func TestValueGetSet(t *testing.T) {
115
116 ctx := context.Background()
117
139 - addrA := randMultiaddr(t)
140 - addrB := randMultiaddr(t)
118 + addrA := testutil.RandLocalTCPAddress()
119 + addrB := testutil.RandLocalTCPAddress()
120
142 - peerA := makePeer(addrA)
143 - peerB := makePeer(addrB)
121 + dhtA := setupDHT(ctx, t, addrA)
122 + dhtB := setupDHT(ctx, t, addrB)
123
145 - dhtA := setupDHT(ctx, t, peerA)
146 - dhtB := setupDHT(ctx, t, peerB)
124 + defer dhtA.Close()
125 + defer dhtB.Close()
126 + defer dhtA.network.Close()
127 + defer dhtB.network.Close()
128
129 vf := func(u.Key, []byte) error {
130 return nil
@@ -151,15 +132,7 @@ func TestValueGetSet(t *testing.T) {
132 dhtA.Validators["v"] = vf
133 dhtB.Validators["v"] = vf
134
154 - defer dhtA.Close()
155 - defer dhtB.Close()
156 - defer dhtA.network.Close()
157 - defer dhtB.network.Close()
158 -
159 - err := dhtA.Connect(ctx, peerB)
160 - if err != nil {
161 - t.Fatal(err)
162 - }
135 + connect(t, ctx, dhtA, dhtB)
136
137 ctxT, _ := context.WithTimeout(ctx, time.Second)
138 dhtA.PutValue(ctxT, "/v/hello", []byte("world"))
@@ -189,7 +162,7 @@ func TestProvides(t *testing.T) {
162 // t.Skip("skipping test to debug another")
163 ctx := context.Background()
164
192 - _, peers, dhts := setupDHTS(ctx, 4, t)
165 + _, _, dhts := setupDHTS(ctx, 4, t)
166 defer func() {
167 for i := 0; i < 4; i++ {
168 dhts[i].Close()
@@ -197,22 +170,11 @@ func TestProvides(t *testing.T) {
170 }
171 }()
172
200 - err := dhts[0].Connect(ctx, peers[1])
201 - if err != nil {
202 - t.Fatal(err)
203 - }
173 + connect(t, ctx, dhts[0], dhts[1])
174 + connect(t, ctx, dhts[1], dhts[2])
175 + connect(t, ctx, dhts[1], dhts[3])
176
205 - err = dhts[1].Connect(ctx, peers[2])
206 - if err != nil {
207 - t.Fatal(err)
208 - }
209 -
210 - err = dhts[1].Connect(ctx, peers[3])
211 - if err != nil {
212 - t.Fatal(err)
213 - }
214 -
215 - err = dhts[3].putLocal(u.Key("hello"), []byte("world"))
177 + err := dhts[3].putLocal(u.Key("hello"), []byte("world"))
178 if err != nil {
179 t.Fatal(err)
180 }
@@ -227,18 +189,21 @@ func TestProvides(t *testing.T) {
189 t.Fatal(err)
190 }
191
230 - time.Sleep(time.Millisecond * 60)
192 + // what is this timeout for? was 60ms before.
193 + time.Sleep(time.Millisecond * 6)
194
195 ctxT, _ := context.WithTimeout(ctx, time.Second)
196 provchan := dhts[0].FindProvidersAsync(ctxT, u.Key("hello"), 1)
197
235 - after := time.After(time.Second)
198 select {
199 case prov := <-provchan:
238 - if prov == nil {
200 + if prov.ID == "" {
201 t.Fatal("Got back nil provider")
202 }
241 - case <-after:
203 + if prov.ID != dhts[3].self {
204 + t.Fatal("Got back nil provider")
205 + }
206 + case <-ctxT.Done():
207 t.Fatal("Did not get a provider back.")
208 }
209 }
@@ -250,7 +215,7 @@ func TestProvidesAsync(t *testing.T) {
215
216 ctx := context.Background()
217
253 - _, peers, dhts := setupDHTS(ctx, 4, t)
218 + _, _, dhts := setupDHTS(ctx, 4, t)
219 defer func() {
220 for i := 0; i < 4; i++ {
221 dhts[i].Close()
@@ -258,22 +223,11 @@ func TestProvidesAsync(t *testing.T) {
223 }
224 }()
225
261 - err := dhts[0].Connect(ctx, peers[1])
262 - if err != nil {
263 - t.Fatal(err)
264 - }
265 -
266 - err = dhts[1].Connect(ctx, peers[2])
267 - if err != nil {
268 - t.Fatal(err)
269 - }
270 -
271 - err = dhts[1].Connect(ctx, peers[3])
272 - if err != nil {
273 - t.Fatal(err)
274 - }
226 + connect(t, ctx, dhts[0], dhts[1])
227 + connect(t, ctx, dhts[1], dhts[2])
228 + connect(t, ctx, dhts[1], dhts[3])
229
276 - err = dhts[3].putLocal(u.Key("hello"), []byte("world"))
230 + err := dhts[3].putLocal(u.Key("hello"), []byte("world"))
231 if err != nil {
232 t.Fatal(err)
233 }
@@ -297,10 +251,10 @@ func TestProvidesAsync(t *testing.T) {
251 if !ok {
252 t.Fatal("Provider channel was closed...")
253 }
300 - if p == nil {
254 + if p.ID == "" {
255 t.Fatal("Got back nil provider!")
256 }
303 - if !p.ID().Equal(dhts[3].self.ID()) {
257 + if p.ID != dhts[3].self {
258 t.Fatalf("got a provider, but not the right one. %s", p)
259 }
260 case <-ctxT.Done():
@@ -315,7 +269,7 @@ func TestLayeredGet(t *testing.T) {
269
270 ctx := context.Background()
271
318 - _, peers, dhts := setupDHTS(ctx, 4, t)
272 + _, _, dhts := setupDHTS(ctx, 4, t)
273 defer func() {
274 for i := 0; i < 4; i++ {
275 dhts[i].Close()
@@ -323,22 +277,11 @@ func TestLayeredGet(t *testing.T) {
277 }
278 }()
279
326 - err := dhts[0].Connect(ctx, peers[1])
327 - if err != nil {
328 - t.Fatalf("Failed to connect: %s", err)
329 - }
280 + connect(t, ctx, dhts[0], dhts[1])
281 + connect(t, ctx, dhts[1], dhts[2])
282 + connect(t, ctx, dhts[1], dhts[3])
283
331 - err = dhts[1].Connect(ctx, peers[2])
332 - if err != nil {
333 - t.Fatal(err)
334 - }
335 -
336 - err = dhts[1].Connect(ctx, peers[3])
337 - if err != nil {
338 - t.Fatal(err)
339 - }
340 -
341 - err = dhts[3].putLocal(u.Key("/v/hello"), []byte("world"))
284 + err := dhts[3].putLocal(u.Key("/v/hello"), []byte("world"))
285 if err != nil {
286 t.Fatal(err)
287 }
@@ -377,32 +320,21 @@ func TestFindPeer(t *testing.T) {
320 }
321 }()
322
380 - err := dhts[0].Connect(ctx, peers[1])
381 - if err != nil {
382 - t.Fatal(err)
383 - }
384 -
385 - err = dhts[1].Connect(ctx, peers[2])
386 - if err != nil {
387 - t.Fatal(err)
388 - }
389 -
390 - err = dhts[1].Connect(ctx, peers[3])
391 - if err != nil {
392 - t.Fatal(err)
393 - }
323 + connect(t, ctx, dhts[0], dhts[1])
324 + connect(t, ctx, dhts[1], dhts[2])
325 + connect(t, ctx, dhts[1], dhts[3])
326
327 ctxT, _ := context.WithTimeout(ctx, time.Second)
396 - p, err := dhts[0].FindPeer(ctxT, peers[2].ID())
328 + p, err := dhts[0].FindPeer(ctxT, peers[2])
329 if err != nil {
330 t.Fatal(err)
331 }
332
401 - if p == nil {
333 + if p.ID == "" {
334 t.Fatal("Failed to find peer.")
335 }
336
405 - if !p.ID().Equal(peers[2].ID()) {
337 + if p.ID != peers[2] {
338 t.Fatal("Didnt find expected peer.")
339 }
340 }
@@ -426,25 +358,10 @@ func TestFindPeersConnectedToPeer(t *testing.T) {
358
359 // topology:
360 // 0-1, 1-2, 1-3, 2-3
429 - err := dhts[0].Connect(ctx, peers[1])
430 - if err != nil {
431 - t.Fatal(err)
432 - }
433 -
434 - err = dhts[1].Connect(ctx, peers[2])
435 - if err != nil {
436 - t.Fatal(err)
437 - }
438 -
439 - err = dhts[1].Connect(ctx, peers[3])
440 - if err != nil {
441 - t.Fatal(err)
442 - }
443 -
444 - err = dhts[2].Connect(ctx, peers[3])
445 - if err != nil {
446 - t.Fatal(err)
447 - }
361 + connect(t, ctx, dhts[0], dhts[1])
362 + connect(t, ctx, dhts[1], dhts[2])
363 + connect(t, ctx, dhts[1], dhts[3])
364 + connect(t, ctx, dhts[2], dhts[3])
365
366 // fmt.Println("0 is", peers[0])
367 // fmt.Println("1 is", peers[1])
@@ -452,13 +369,13 @@ func TestFindPeersConnectedToPeer(t *testing.T) {
369 // fmt.Println("3 is", peers[3])
370
371 ctxT, _ := context.WithTimeout(ctx, time.Second)
455 - pchan, err := dhts[0].FindPeersConnectedToPeer(ctxT, peers[2].ID())
372 + pchan, err := dhts[0].FindPeersConnectedToPeer(ctxT, peers[2])
373 if err != nil {
374 t.Fatal(err)
375 }
376
460 - // shouldFind := []peer.Peer{peers[1], peers[3]}
461 - found := []peer.Peer{}
377 + // shouldFind := []peer.ID{peers[1], peers[3]}
378 + found := []peer.PeerInfo{}
379 for nextp := range pchan {
380 found = append(found, nextp)
381 }
@@ -475,7 +392,7 @@ func TestFindPeersConnectedToPeer(t *testing.T) {
392 }
393 }
394
478 -func testPeerListsMatch(t *testing.T, p1, p2 []peer.Peer) {
395 +func testPeerListsMatch(t *testing.T, p1, p2 []peer.ID) {
396
397 if len(p1) != len(p2) {
398 t.Fatal("did not find as many peers as should have", p1, p2)
@@ -485,11 +402,11 @@ func testPeerListsMatch(t *testing.T, p1, p2 []peer.Peer) {
402 ids2 := make([]string, len(p2))
403
404 for i, p := range p1 {
488 - ids1[i] = p.ID().Pretty()
405 + ids1[i] = string(p)
406 }
407
408 for i, p := range p2 {
492 - ids2[i] = p.ID().Pretty()
409 + ids2[i] = string(p)
410 }
411
412 sort.Sort(sort.StringSlice(ids1))
@@ -514,39 +431,41 @@ func TestConnectCollision(t *testing.T) {
431
432 ctx := context.Background()
433
517 - addrA := randMultiaddr(t)
518 - addrB := randMultiaddr(t)
434 + addrA := testutil.RandLocalTCPAddress()
435 + addrB := testutil.RandLocalTCPAddress()
436
520 - peerA := makePeer(addrA)
521 - peerB := makePeer(addrB)
437 + dhtA := setupDHT(ctx, t, addrA)
438 + dhtB := setupDHT(ctx, t, addrB)
439
523 - dhtA := setupDHT(ctx, t, peerA)
524 - dhtB := setupDHT(ctx, t, peerB)
440 + peerA := dhtA.self
441 + peerB := dhtB.self
442
526 - done := make(chan struct{})
443 + errs := make(chan error)
444 go func() {
445 + dhtA.peerstore.AddAddress(peerB, addrB)
446 err := dhtA.Connect(ctx, peerB)
529 - if err != nil {
530 - t.Fatal(err)
531 - }
532 - done <- struct{}{}
447 + errs <- err
448 }()
449 go func() {
450 + dhtB.peerstore.AddAddress(peerA, addrA)
451 err := dhtB.Connect(ctx, peerA)
536 - if err != nil {
537 - t.Fatal(err)
538 - }
539 - done <- struct{}{}
452 + errs <- err
453 }()
454
455 timeout := time.After(time.Second)
456 select {
544 - case <-done:
457 + case e := <-errs:
458 + if e != nil {
459 + t.Fatal(e)
460 + }
461 case <-timeout:
462 t.Fatal("Timeout received!")
463 }
464 select {
549 - case <-done:
465 + case e := <-errs:
466 + if e != nil {
467 + t.Fatal(e)
468 + }
469 case <-timeout:
470 t.Fatal("Timeout received!")
471 }
@@ -555,7 +474,5 @@ func TestConnectCollision(t *testing.T) {
474 dhtB.Close()
475 dhtA.network.Close()
476 dhtB.network.Close()
558 -
559 - <-time.After(200 * time.Millisecond)
477 }
478 }
routing/dht/diag.go
+2 -2
@@ -32,12 +32,12 @@ func (di *diagInfo) Marshal() []byte {
32 func (dht *IpfsDHT) getDiagInfo() *diagInfo {
33 di := new(diagInfo)
34 di.CodeVersion = "github.com/jbenet/go-ipfs"
35 - di.ID = dht.self.ID()
35 + di.ID = dht.self
36 di.LifeSpan = time.Since(dht.birth)
37 di.Keys = nil // Currently no way to query datastore
38
39 for _, p := range dht.routingTable.ListPeers() {
40 - d := connDiagInfo{p.GetLatency(), p.ID()}
40 + d := connDiagInfo{dht.peerstore.LatencyEWMA(p), p}
41 di.Connections = append(di.Connections, d)
42 }
43 return di
routing/dht/ext_test.go
+16 -22
@@ -4,19 +4,17 @@ import (
4 "math/rand"
5 "testing"
6
7 - crand "crypto/rand"
8 -
7 inet "github.com/jbenet/go-ipfs/net"
8 mocknet "github.com/jbenet/go-ipfs/net/mock"
9 peer "github.com/jbenet/go-ipfs/peer"
10 routing "github.com/jbenet/go-ipfs/routing"
11 pb "github.com/jbenet/go-ipfs/routing/dht/pb"
12 u "github.com/jbenet/go-ipfs/util"
15 - testutil "github.com/jbenet/go-ipfs/util/testutil"
13
14 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
15 ggio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/io"
16 ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
17 + dssync "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync"
18
19 "time"
20 )
@@ -34,8 +32,8 @@ func TestGetFailures(t *testing.T) {
32 nets := mn.Nets()
33 peers := mn.Peers()
34
37 - ps := peer.NewPeerstore()
38 - d := NewDHT(ctx, peers[0], ps, nets[0], ds.NewMapDatastore())
35 + tsds := dssync.MutexWrap(ds.NewMapDatastore())
36 + d := NewDHT(ctx, peers[0], nets[0], tsds)
37 d.Update(ctx, peers[1])
38
39 // This one should time out
@@ -126,14 +124,6 @@ func TestGetFailures(t *testing.T) {
124 }
125 }
126
129 -// TODO: Maybe put these in some sort of "ipfs_testutil" package
130 -func _randPeer() peer.Peer {
131 - id := make(peer.ID, 16)
132 - crand.Read(id)
133 - p := testutil.NewPeerWithID(id)
134 - return p
135 -}
136 -
127 func TestNotFound(t *testing.T) {
128 if testing.Short() {
129 t.SkipNow()
@@ -146,9 +136,8 @@ func TestNotFound(t *testing.T) {
136 }
137 nets := mn.Nets()
138 peers := mn.Peers()
149 - peerstore := peer.NewPeerstore()
150 -
151 - d := NewDHT(ctx, peers[0], peerstore, nets[0], ds.NewMapDatastore())
139 + tsds := dssync.MutexWrap(ds.NewMapDatastore())
140 + d := NewDHT(ctx, peers[0], nets[0], tsds)
141
142 for _, p := range peers {
143 d.Update(ctx, p)
@@ -156,6 +145,7 @@ func TestNotFound(t *testing.T) {
145
146 // Reply with random peers to every message
147 for _, neti := range nets {
148 + neti := neti // shadow loop var
149 neti.SetHandler(inet.ProtocolDHT, func(s inet.Stream) {
150 defer s.Close()
151
@@ -171,12 +161,14 @@ func TestNotFound(t *testing.T) {
161 case pb.Message_GET_VALUE:
162 resp := &pb.Message{Type: pmes.Type}
163
174 - ps := []peer.Peer{}
164 + ps := []peer.PeerInfo{}
165 for i := 0; i < 7; i++ {
176 - ps = append(ps, peers[rand.Intn(len(peers))])
166 + p := peers[rand.Intn(len(peers))]
167 + pi := neti.Peerstore().PeerInfo(p)
168 + ps = append(ps, pi)
169 }
170
179 - resp.CloserPeers = pb.PeersToPBPeers(d.network, peers)
171 + resp.CloserPeers = pb.PeerInfosToPBPeers(d.network, ps)
172 if err := pbw.WriteMsg(resp); err != nil {
173 panic(err)
174 }
@@ -216,9 +208,9 @@ func TestLessThanKResponses(t *testing.T) {
208 }
209 nets := mn.Nets()
210 peers := mn.Peers()
219 - peerstore := peer.NewPeerstore()
211
221 - d := NewDHT(ctx, peers[0], peerstore, nets[0], ds.NewMapDatastore())
212 + tsds := dssync.MutexWrap(ds.NewMapDatastore())
213 + d := NewDHT(ctx, peers[0], nets[0], tsds)
214
215 for i := 1; i < 5; i++ {
216 d.Update(ctx, peers[i])
@@ -226,6 +218,7 @@ func TestLessThanKResponses(t *testing.T) {
218
219 // Reply with random peers to every message
220 for _, neti := range nets {
221 + neti := neti // shadow loop var
222 neti.SetHandler(inet.ProtocolDHT, func(s inet.Stream) {
223 defer s.Close()
224
@@ -239,9 +232,10 @@ func TestLessThanKResponses(t *testing.T) {
232
233 switch pmes.GetType() {
234 case pb.Message_GET_VALUE:
235 + pi := neti.Peerstore().PeerInfo(peers[1])
236 resp := &pb.Message{
237 Type: pmes.Type,
244 - CloserPeers: pb.PeersToPBPeers(d.network, []peer.Peer{peers[1]}),
238 + CloserPeers: pb.PeerInfosToPBPeers(d.network, []peer.PeerInfo{pi}),
239 }
240
241 if err := pbw.WriteMsg(resp); err != nil {
routing/dht/handlers.go
+55 -51
@@ -17,7 +17,7 @@ import (
17 var CloserPeerCount = 4
18
19 // dhthandler specifies the signature of functions that handle DHT messages.
20 -type dhtHandler func(context.Context, peer.Peer, *pb.Message) (*pb.Message, error)
20 +type dhtHandler func(context.Context, peer.ID, *pb.Message) (*pb.Message, error)
21
22 func (dht *IpfsDHT) handlerForMsgType(t pb.Message_MessageType) dhtHandler {
23 switch t {
@@ -38,16 +38,17 @@ func (dht *IpfsDHT) handlerForMsgType(t pb.Message_MessageType) dhtHandler {
38 }
39 }
40
41 -func (dht *IpfsDHT) handleGetValue(ctx context.Context, p peer.Peer, pmes *pb.Message) (*pb.Message, error) {
41 +func (dht *IpfsDHT) handleGetValue(ctx context.Context, p peer.ID, pmes *pb.Message) (*pb.Message, error) {
42 log.Debugf("%s handleGetValue for key: %s\n", dht.self, pmes.GetKey())
43
44 // setup response
45 resp := pb.NewMessage(pmes.GetType(), pmes.GetKey(), pmes.GetClusterLevel())
46
47 - // first, is the key even a key?
47 + // first, is there even a key?
48 key := pmes.GetKey()
49 if key == "" {
50 return nil, errors.New("handleGetValue but no key was provided")
51 + // TODO: send back an error response? could be bad, but the other node's hanging.
52 }
53
54 // let's first check if we have the value locally.
@@ -85,36 +86,38 @@ func (dht *IpfsDHT) handleGetValue(ctx context.Context, p peer.Peer, pmes *pb.Me
86
87 // if we know any providers for the requested value, return those.
88 provs := dht.providers.GetProviders(ctx, u.Key(pmes.GetKey()))
89 + provinfos := peer.PeerInfos(dht.peerstore, provs)
90 if len(provs) > 0 {
91 log.Debugf("handleGetValue returning %d provider[s]", len(provs))
90 - resp.ProviderPeers = pb.PeersToPBPeers(dht.network, provs)
92 + resp.ProviderPeers = pb.PeerInfosToPBPeers(dht.network, provinfos)
93 }
94
95 // Find closest peer on given cluster to desired key and reply with that info
96 closer := dht.betterPeersToQuery(pmes, CloserPeerCount)
97 + closerinfos := peer.PeerInfos(dht.peerstore, closer)
98 if closer != nil {
96 - for _, p := range closer {
97 - log.Debugf("handleGetValue returning closer peer: '%s'", p)
98 - if len(p.Addresses()) < 1 {
99 - log.Critical("no addresses on peer being sent!")
99 + for _, pi := range closerinfos {
100 + log.Debugf("handleGetValue returning closer peer: '%s'", pi.ID)
101 + if len(pi.Addrs) < 1 {
102 + log.Criticalf(`no addresses on peer being sent!
103 + [local:%s]
104 + [sending:%s]
105 + [remote:%s]`, dht.self, pi.ID, p)
106 }
107 }
102 - resp.CloserPeers = pb.PeersToPBPeers(dht.network, closer)
108 +
109 + resp.CloserPeers = pb.PeerInfosToPBPeers(dht.network, closerinfos)
110 }
111
112 return resp, nil
113 }
114
115 // Store a value in this peer local storage
109 -func (dht *IpfsDHT) handlePutValue(ctx context.Context, p peer.Peer, pmes *pb.Message) (*pb.Message, error) {
110 - dht.dslock.Lock()
111 - defer dht.dslock.Unlock()
116 +func (dht *IpfsDHT) handlePutValue(ctx context.Context, p peer.ID, pmes *pb.Message) (*pb.Message, error) {
117 dskey := u.Key(pmes.GetKey()).DsKey()
118
114 - err := dht.verifyRecord(pmes.GetRecord())
115 - if err != nil {
116 - fmt.Println(u.Key(pmes.GetRecord().GetAuthor()))
117 - log.Error("Bad dht record in put request")
119 + if err := dht.verifyRecordLocally(pmes.GetRecord()); err != nil {
120 + log.Errorf("Bad dht record in PUT from: %s. %s", u.Key(pmes.GetRecord().GetAuthor()), err)
121 return nil, err
122 }
123
@@ -128,18 +131,18 @@ func (dht *IpfsDHT) handlePutValue(ctx context.Context, p peer.Peer, pmes *pb.Me
131 return pmes, err
132 }
133
131 -func (dht *IpfsDHT) handlePing(_ context.Context, p peer.Peer, pmes *pb.Message) (*pb.Message, error) {
134 +func (dht *IpfsDHT) handlePing(_ context.Context, p peer.ID, pmes *pb.Message) (*pb.Message, error) {
135 log.Debugf("%s Responding to ping from %s!\n", dht.self, p)
136 return pmes, nil
137 }
138
136 -func (dht *IpfsDHT) handleFindPeer(ctx context.Context, p peer.Peer, pmes *pb.Message) (*pb.Message, error) {
139 +func (dht *IpfsDHT) handleFindPeer(ctx context.Context, p peer.ID, pmes *pb.Message) (*pb.Message, error) {
140 resp := pb.NewMessage(pmes.GetType(), "", pmes.GetClusterLevel())
138 - var closest []peer.Peer
141 + var closest []peer.ID
142
143 // if looking for self... special case where we send it on CloserPeers.
141 - if peer.ID(pmes.GetKey()).Equal(dht.self.ID()) {
142 - closest = []peer.Peer{dht.self}
144 + if peer.ID(pmes.GetKey()) == dht.self {
145 + closest = []peer.ID{dht.self}
146 } else {
147 closest = dht.betterPeersToQuery(pmes, CloserPeerCount)
148 }
@@ -149,22 +152,20 @@ func (dht *IpfsDHT) handleFindPeer(ctx context.Context, p peer.Peer, pmes *pb.Me
152 return resp, nil
153 }
154
152 - var withAddresses []peer.Peer
153 - for _, p := range closest {
154 - if len(p.Addresses()) > 0 {
155 - withAddresses = append(withAddresses, p)
155 + var withAddresses []peer.PeerInfo
156 + closestinfos := peer.PeerInfos(dht.peerstore, closest)
157 + for _, pi := range closestinfos {
158 + if len(pi.Addrs) > 0 {
159 + withAddresses = append(withAddresses, pi)
160 + log.Debugf("handleFindPeer: sending back '%s'", pi.ID)
161 }
162 }
163
159 - for _, p := range withAddresses {
160 - log.Debugf("handleFindPeer: sending back '%s'", p)
161 - }
162 -
163 - resp.CloserPeers = pb.PeersToPBPeers(dht.network, withAddresses)
164 + resp.CloserPeers = pb.PeerInfosToPBPeers(dht.network, withAddresses)
165 return resp, nil
166 }
167
167 -func (dht *IpfsDHT) handleGetProviders(ctx context.Context, p peer.Peer, pmes *pb.Message) (*pb.Message, error) {
168 +func (dht *IpfsDHT) handleGetProviders(ctx context.Context, p peer.ID, pmes *pb.Message) (*pb.Message, error) {
169 resp := pb.NewMessage(pmes.GetType(), pmes.GetKey(), pmes.GetClusterLevel())
170
171 // check if we have this value, to add ourselves as provider.
@@ -183,13 +184,15 @@ func (dht *IpfsDHT) handleGetProviders(ctx context.Context, p peer.Peer, pmes *p
184 }
185
186 if providers != nil && len(providers) > 0 {
186 - resp.ProviderPeers = pb.PeersToPBPeers(dht.network, providers)
187 + infos := peer.PeerInfos(dht.peerstore, providers)
188 + resp.ProviderPeers = pb.PeerInfosToPBPeers(dht.network, infos)
189 }
190
191 // Also send closer peers.
192 closer := dht.betterPeersToQuery(pmes, CloserPeerCount)
193 if closer != nil {
192 - resp.CloserPeers = pb.PeersToPBPeers(dht.network, closer)
194 + infos := peer.PeerInfos(dht.peerstore, providers)
195 + resp.CloserPeers = pb.PeerInfosToPBPeers(dht.network, infos)
196 }
197
198 return resp, nil
@@ -197,34 +200,35 @@ func (dht *IpfsDHT) handleGetProviders(ctx context.Context, p peer.Peer, pmes *p
200
201 type providerInfo struct {
202 Creation time.Time
200 - Value peer.Peer
203 + Value peer.ID
204 }
205
203 -func (dht *IpfsDHT) handleAddProvider(ctx context.Context, p peer.Peer, pmes *pb.Message) (*pb.Message, error) {
206 +func (dht *IpfsDHT) handleAddProvider(ctx context.Context, p peer.ID, pmes *pb.Message) (*pb.Message, error) {
207 key := u.Key(pmes.GetKey())
208
209 log.Debugf("%s adding %s as a provider for '%s'\n", dht.self, p, peer.ID(key))
210
211 // add provider should use the address given in the message
209 - for _, pb := range pmes.GetProviderPeers() {
210 - pid := peer.ID(pb.GetId())
211 - if pid.Equal(p.ID()) {
212 -
213 - maddrs, err := pb.Addresses()
214 - if err != nil {
215 - log.Errorf("provider %s error with addresses %s", p, pb.Addrs)
216 - continue
217 - }
212 + pinfos := pb.PBPeersToPeerInfos(pmes.GetProviderPeers())
213 + for _, pi := range pinfos {
214 + if pi.ID != p {
215 + // we should ignore this provider reccord! not from originator.
216 + // (we chould sign them and check signature later...)
217 + log.Errorf("handleAddProvider received provider %s from %s. Ignore.", pi.ID, p)
218 + continue
219 + }
220
219 - log.Infof("received provider %s %s for %s", p, maddrs, key)
220 - for _, maddr := range maddrs {
221 - p.AddAddress(maddr)
222 - }
223 - dht.providers.AddProvider(key, p)
221 + if len(pi.Addrs) < 1 {
222 + log.Errorf("got no valid addresses for provider %s. Ignore.", p)
223 + continue
224 + }
225
225 - } else {
226 - log.Errorf("handleAddProvider received provider %s from %s", pid, p)
226 + log.Infof("received provider %s for %s (addrs: %s)", p, key, pi.Addrs)
227 + for _, maddr := range pi.Addrs {
228 + // add the received addresses to our peerstore.
229 + dht.peerstore.AddAddress(p, maddr)
230 }
231 + dht.providers.AddProvider(key, p)
232 }
233
234 return pmes, nil // send back same msg as confirmation.
routing/dht/pb/dht.pb.go
+2 -2
@@ -182,7 +182,7 @@ type Message_Peer struct {
182 // ID of a given peer.
183 Id *string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
184 // multiaddrs for a given peer
185 - Addrs []string `protobuf:"bytes,2,rep,name=addrs" json:"addrs,omitempty"`
185 + Addrs [][]byte `protobuf:"bytes,2,rep,name=addrs" json:"addrs,omitempty"`
186 // used to signal the sender's connection capabilities to the peer
187 Connection *Message_ConnectionType `protobuf:"varint,3,opt,name=connection,enum=dht.pb.Message_ConnectionType" json:"connection,omitempty"`
188 XXX_unrecognized []byte `json:"-"`
@@ -199,7 +199,7 @@ func (m *Message_Peer) GetId() string {
199 return ""
200 }
201
202 -func (m *Message_Peer) GetAddrs() []string {
202 +func (m *Message_Peer) GetAddrs() [][]byte {
203 if m != nil {
204 return m.Addrs
205 }
routing/dht/pb/dht.proto
+1 -1
@@ -32,7 +32,7 @@ message Message {
32 optional string id = 1;
33
34 // multiaddrs for a given peer
35 - repeated string addrs = 2;
35 + repeated bytes addrs = 2;
36
37 // used to signal the sender's connection capabilities to the peer
38 optional ConnectionType connection = 3;
routing/dht/pb/message.go
+34 -52
@@ -1,15 +1,15 @@
1 package dht_pb
2
3 import (
4 - "errors"
5 - "fmt"
6 -
4 ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
5
6 inet "github.com/jbenet/go-ipfs/net"
7 peer "github.com/jbenet/go-ipfs/peer"
8 + eventlog "github.com/jbenet/go-ipfs/util/eventlog"
9 )
10
11 +var log = eventlog.Logger("dht.pb")
12 +
13 // NewMessage constructs a new dht message with given type, key, and level
14 func NewMessage(typ Message_MessageType, key string, level int) *Message {
15 m := &Message{
@@ -20,43 +20,32 @@ func NewMessage(typ Message_MessageType, key string, level int) *Message {
20 return m
21 }
22
23 -func peerToPBPeer(p peer.Peer) *Message_Peer {
23 +func peerInfoToPBPeer(p peer.PeerInfo) *Message_Peer {
24 pbp := new(Message_Peer)
25
26 - maddrs := p.Addresses()
27 - pbp.Addrs = make([]string, len(maddrs))
28 - for i, maddr := range maddrs {
29 - pbp.Addrs[i] = maddr.String()
26 + pbp.Addrs = make([][]byte, len(p.Addrs))
27 + for i, maddr := range p.Addrs {
28 + pbp.Addrs[i] = maddr.Bytes() // Bytes, not String. Compressed.
29 }
31 - pid := string(p.ID())
32 - pbp.Id = &pid
30 + s := string(p.ID)
31 + pbp.Id = &s
32 return pbp
33 }
34
36 -// PBPeerToPeer turns a *Message_Peer into its peer.Peer counterpart
37 -func PBPeerToPeer(ps peer.Peerstore, pbp *Message_Peer) (peer.Peer, error) {
38 - p, err := ps.FindOrCreate(peer.ID(pbp.GetId()))
39 - if err != nil {
40 - return nil, fmt.Errorf("Failed to get peer from peerstore: %s", err)
41 - }
42 -
43 - // add addresses
44 - maddrs, err := pbp.Addresses()
45 - if err != nil {
46 - return nil, fmt.Errorf("Received peer with bad or missing addresses: %s", pbp.Addrs)
35 +// PBPeerToPeer turns a *Message_Peer into its peer.PeerInfo counterpart
36 +func PBPeerToPeerInfo(pbp *Message_Peer) peer.PeerInfo {
37 + return peer.PeerInfo{
38 + ID: peer.ID(pbp.GetId()),
39 + Addrs: pbp.Addresses(),
40 }
48 - for _, maddr := range maddrs {
49 - p.AddAddress(maddr)
50 - }
51 - return p, nil
41 }
42
54 -// RawPeersToPBPeers converts a slice of Peers into a slice of *Message_Peers,
43 +// RawPeerInfosToPBPeers converts a slice of Peers into a slice of *Message_Peers,
44 // ready to go out on the wire.
56 -func RawPeersToPBPeers(peers []peer.Peer) []*Message_Peer {
45 +func RawPeerInfosToPBPeers(peers []peer.PeerInfo) []*Message_Peer {
46 pbpeers := make([]*Message_Peer, len(peers))
47 for i, p := range peers {
59 - pbpeers[i] = peerToPBPeer(p)
48 + pbpeers[i] = peerInfoToPBPeer(p)
49 }
50 return pbpeers
51 }
@@ -64,49 +53,42 @@ func RawPeersToPBPeers(peers []peer.Peer) []*Message_Peer {
53 // PeersToPBPeers converts given []peer.Peer into a set of []*Message_Peer,
54 // which can be written to a message and sent out. the key thing this function
55 // does (in addition to PeersToPBPeers) is set the ConnectionType with
67 -// information from the given inet.Dialer.
68 -func PeersToPBPeers(d inet.Network, peers []peer.Peer) []*Message_Peer {
69 - pbps := RawPeersToPBPeers(peers)
56 +// information from the given inet.Network.
57 +func PeerInfosToPBPeers(n inet.Network, peers []peer.PeerInfo) []*Message_Peer {
58 + pbps := RawPeerInfosToPBPeers(peers)
59 for i, pbp := range pbps {
71 - c := ConnectionType(d.Connectedness(peers[i]))
60 + c := ConnectionType(n.Connectedness(peers[i].ID))
61 pbp.Connection = &c
62 }
63 return pbps
64 }
65
77 -// PBPeersToPeers converts given []*Message_Peer into a set of []peer.Peer
78 -// Returns two slices, one of peers, and one of errors. The slice of peers
79 -// will ONLY contain successfully converted peers. The slice of errors contains
80 -// whether each input Message_Peer was successfully converted.
81 -func PBPeersToPeers(ps peer.Peerstore, pbps []*Message_Peer) ([]peer.Peer, []error) {
82 - errs := make([]error, len(pbps))
83 - peers := make([]peer.Peer, 0, len(pbps))
84 - for i, pbp := range pbps {
85 - p, err := PBPeerToPeer(ps, pbp)
86 - if err != nil {
87 - errs[i] = err
88 - } else {
89 - peers = append(peers, p)
90 - }
66 +// PBPeersToPeerInfos converts given []*Message_Peer into []peer.PeerInfo
67 +// Invalid addresses will be silently omitted.
68 +func PBPeersToPeerInfos(pbps []*Message_Peer) []peer.PeerInfo {
69 + peers := make([]peer.PeerInfo, 0, len(pbps))
70 + for _, pbp := range pbps {
71 + peers = append(peers, PBPeerToPeerInfo(pbp))
72 }
92 - return peers, errs
73 + return peers
74 }
75
76 // Addresses returns a multiaddr associated with the Message_Peer entry
96 -func (m *Message_Peer) Addresses() ([]ma.Multiaddr, error) {
77 +func (m *Message_Peer) Addresses() []ma.Multiaddr {
78 if m == nil {
98 - return nil, errors.New("MessagePeer is nil")
79 + return nil
80 }
81
82 var err error
83 maddrs := make([]ma.Multiaddr, len(m.Addrs))
84 for i, addr := range m.Addrs {
104 - maddrs[i], err = ma.NewMultiaddr(addr)
85 + maddrs[i], err = ma.NewMultiaddrBytes(addr)
86 if err != nil {
106 - return nil, err
87 + log.Error("error decoding Multiaddr for peer: %s", m.GetId())
88 + continue
89 }
90 }
109 - return maddrs, nil
91 + return maddrs
92 }
93
94 // GetClusterLevel gets and adjusts the cluster level on the message.
routing/dht/providers.go
+7 -7
@@ -23,12 +23,12 @@ type ProviderManager struct {
23
24 type addProv struct {
25 k u.Key
26 - val peer.Peer
26 + val peer.ID
27 }
28
29 type getProv struct {
30 k u.Key
31 - resp chan []peer.Peer
31 + resp chan []peer.ID
32 }
33
34 func NewProviderManager(ctx context.Context, local peer.ID) *ProviderManager {
@@ -53,7 +53,7 @@ func (pm *ProviderManager) run() {
53 for {
54 select {
55 case np := <-pm.newprovs:
56 - if np.val.ID().Equal(pm.lpeer) {
56 + if np.val == pm.lpeer {
57 pm.local[np.k] = struct{}{}
58 }
59 pi := new(providerInfo)
@@ -63,7 +63,7 @@ func (pm *ProviderManager) run() {
63 pm.providers[np.k] = append(arr, pi)
64
65 case gp := <-pm.getprovs:
66 - var parr []peer.Peer
66 + var parr []peer.ID
67 provs := pm.providers[gp.k]
68 for _, p := range provs {
69 parr = append(parr, p.Value)
@@ -94,17 +94,17 @@ func (pm *ProviderManager) run() {
94 }
95 }
96
97 -func (pm *ProviderManager) AddProvider(k u.Key, val peer.Peer) {
97 +func (pm *ProviderManager) AddProvider(k u.Key, val peer.ID) {
98 pm.newprovs <- &addProv{
99 k: k,
100 val: val,
101 }
102 }
103
104 -func (pm *ProviderManager) GetProviders(ctx context.Context, k u.Key) []peer.Peer {
104 +func (pm *ProviderManager) GetProviders(ctx context.Context, k u.Key) []peer.ID {
105 gp := &getProv{
106 k: k,
107 - resp: make(chan []peer.Peer, 1), // buffered to prevent sender from blocking
107 + resp: make(chan []peer.ID, 1), // buffered to prevent sender from blocking
108 }
109 select {
110 case <-ctx.Done():
routing/dht/providers_test.go
+2 -3
@@ -3,9 +3,8 @@ package dht
3 import (
4 "testing"
5
6 - "github.com/jbenet/go-ipfs/peer"
6 + peer "github.com/jbenet/go-ipfs/peer"
7 u "github.com/jbenet/go-ipfs/util"
8 - testutil "github.com/jbenet/go-ipfs/util/testutil"
8
9 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
10 )
@@ -15,7 +14,7 @@ func TestProviderManager(t *testing.T) {
14 mid := peer.ID("testing")
15 p := NewProviderManager(ctx, mid)
16 a := u.Key("test")
18 - p.AddProvider(a, testutil.NewPeerWithIDString("testingprovider"))
17 + p.AddProvider(a, peer.ID("testingprovider"))
18 resp := p.GetProviders(ctx, a)
19 if len(resp) != 1 {
20 t.Fatal("Could not retrieve provider.")
routing/dht/query.go
+24 -24
@@ -31,10 +31,10 @@ type dhtQuery struct {
31 }
32
33 type dhtQueryResult struct {
34 - value []byte // GetValue
35 - peer peer.Peer // FindPeer
36 - providerPeers []peer.Peer // GetProviders
37 - closerPeers []peer.Peer // *
34 + value []byte // GetValue
35 + peer peer.PeerInfo // FindPeer
36 + providerPeers []peer.PeerInfo // GetProviders
37 + closerPeers []peer.PeerInfo // *
38 success bool
39 }
40
@@ -53,10 +53,10 @@ func newQuery(k u.Key, d inet.Dialer, f queryFunc) *dhtQuery {
53 // - the value
54 // - a list of peers potentially better able to serve the query
55 // - an error
56 -type queryFunc func(context.Context, peer.Peer) (*dhtQueryResult, error)
56 +type queryFunc func(context.Context, peer.ID) (*dhtQueryResult, error)
57
58 // Run runs the query at hand. pass in a list of peers to use first.
59 -func (q *dhtQuery) Run(ctx context.Context, peers []peer.Peer) (*dhtQueryResult, error) {
59 +func (q *dhtQuery) Run(ctx context.Context, peers []peer.ID) (*dhtQueryResult, error) {
60 runner := newQueryRunner(ctx, q)
61 return runner.Run(peers)
62 }
@@ -70,7 +70,7 @@ type dhtQueryRunner struct {
70 peersToQuery *queue.ChanQueue
71
72 // peersSeen are all the peers queried. used to prevent querying same peer 2x
73 - peersSeen peer.Map
73 + peersSeen peer.Set
74
75 // rateLimit is a channel used to rate limit our processing (semaphore)
76 rateLimit chan struct{}
@@ -101,12 +101,12 @@ func newQueryRunner(ctx context.Context, q *dhtQuery) *dhtQueryRunner {
101 query: q,
102 peersToQuery: queue.NewChanQueue(ctx, queue.NewXORDistancePQ(q.key)),
103 peersRemaining: todoctr.NewSyncCounter(),
104 - peersSeen: peer.Map{},
104 + peersSeen: peer.Set{},
105 rateLimit: make(chan struct{}, q.concurrency),
106 }
107 }
108
109 -func (r *dhtQueryRunner) Run(peers []peer.Peer) (*dhtQueryResult, error) {
109 +func (r *dhtQueryRunner) Run(peers []peer.ID) (*dhtQueryResult, error) {
110 log.Debugf("Run query with %d peers.", len(peers))
111 if len(peers) == 0 {
112 log.Warning("Running query with no peers!")
@@ -120,7 +120,7 @@ func (r *dhtQueryRunner) Run(peers []peer.Peer) (*dhtQueryResult, error) {
120
121 // add all the peers we got first.
122 for _, p := range peers {
123 - r.addPeerToQuery(p, nil) // don't have access to self here...
123 + r.addPeerToQuery(p, "") // don't have access to self here...
124 }
125
126 // go do this thing.
@@ -154,31 +154,30 @@ func (r *dhtQueryRunner) Run(peers []peer.Peer) (*dhtQueryResult, error) {
154 return nil, err
155 }
156
157 -func (r *dhtQueryRunner) addPeerToQuery(next peer.Peer, benchmark peer.Peer) {
158 - if next == nil {
159 - // wtf why are peers nil?!?
160 - log.Error("Query getting nil peers!!!\n")
161 - return
162 - }
163 -
157 +func (r *dhtQueryRunner) addPeerToQuery(next peer.ID, benchmark peer.ID) {
158 // if new peer is ourselves...
165 - if next.ID().Equal(r.query.dialer.LocalPeer().ID()) {
159 + if next == r.query.dialer.LocalPeer() {
160 return
161 }
162
163 // if new peer further away than whom we got it from, don't bother (loops)
170 - if benchmark != nil && kb.Closer(benchmark.ID(), next.ID(), r.query.key) {
164 + // TODO----------- this benchmark should be replaced by a heap:
165 + // we should be doing the s/kademlia "continue to search"
166 + // (i.e. put all of them in a heap sorted by dht distance and then just
167 + // pull from the the top until a) you exhaust all peers you get,
168 + // b) you succeed, c) your context expires.
169 + if benchmark != "" && kb.Closer(benchmark, next, r.query.key) {
170 return
171 }
172
173 // if already seen, no need.
174 r.Lock()
176 - _, found := r.peersSeen[next.Key()]
175 + _, found := r.peersSeen[next]
176 if found {
177 r.Unlock()
178 return
179 }
181 - r.peersSeen[next.Key()] = next
180 + r.peersSeen[next] = struct{}{}
181 r.Unlock()
182
183 log.Debugf("adding peer to query: %v\n", next)
@@ -211,7 +210,7 @@ func (r *dhtQueryRunner) spawnWorkers() {
210 }
211 }
212
214 -func (r *dhtQueryRunner) queryPeer(p peer.Peer) {
213 +func (r *dhtQueryRunner) queryPeer(p peer.ID) {
214 log.Debugf("spawned worker for: %v", p)
215
216 // make sure we rate limit concurrency.
@@ -234,7 +233,6 @@ func (r *dhtQueryRunner) queryPeer(p peer.Peer) {
233 }()
234
235 // make sure we're connected to the peer.
237 - // (Incidentally, this will add it to the peerstore too)
236 err := r.query.dialer.DialPeer(r.ctx, p)
237 if err != nil {
238 log.Debugf("ERROR worker for: %v -- err connecting: %v", p, err)
@@ -263,7 +261,9 @@ func (r *dhtQueryRunner) queryPeer(p peer.Peer) {
261 } else if res.closerPeers != nil {
262 log.Debugf("PEERS CLOSER -- worker for: %v", p)
263 for _, next := range res.closerPeers {
266 - r.addPeerToQuery(next, p)
264 + // add their addresses to the dialer's peerstore
265 + r.query.dialer.Peerstore().AddAddresses(next.ID, next.Addrs)
266 + r.addPeerToQuery(next.ID, p)
267 }
268 }
269 }
routing/dht/records.go
+123 -22
@@ -3,15 +3,17 @@ package dht
3 import (
4 "bytes"
5 "errors"
6 + "fmt"
7 "strings"
7 - "time"
8
9 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
10 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
11 +
12 ci "github.com/jbenet/go-ipfs/crypto"
13 "github.com/jbenet/go-ipfs/peer"
14 pb "github.com/jbenet/go-ipfs/routing/dht/pb"
15 u "github.com/jbenet/go-ipfs/util"
16 + ctxutil "github.com/jbenet/go-ipfs/util/ctx"
17 )
18
19 // ValidatorFunc is a function that is called to validate a given
@@ -26,64 +28,163 @@ var ErrBadRecord = errors.New("bad dht record")
28 // is not found in the Validator map of the DHT.
29 var ErrInvalidRecordType = errors.New("invalid record keytype")
30
31 +// KeyForPublicKey returns the key used to retrieve public keys
32 +// from the dht.
33 +func KeyForPublicKey(id peer.ID) u.Key {
34 + return u.Key("/pk/" + string(id))
35 +}
36 +
37 +// RecordBlobForSig returns the blob protected by the record signature
38 +func RecordBlobForSig(r *pb.Record) []byte {
39 + k := []byte(r.GetKey())
40 + v := []byte(r.GetValue())
41 + a := []byte(r.GetAuthor())
42 + return bytes.Join([][]byte{k, v, a}, []byte{})
43 +}
44 +
45 // creates and signs a dht record for the given key/value pair
46 func (dht *IpfsDHT) makePutRecord(key u.Key, value []byte) (*pb.Record, error) {
47 record := new(pb.Record)
48
49 record.Key = proto.String(string(key))
50 record.Value = value
35 - record.Author = proto.String(string(dht.self.ID()))
36 - blob := bytes.Join([][]byte{[]byte(key), value, []byte(dht.self.ID())}, []byte{})
37 - sig, err := dht.self.PrivKey().Sign(blob)
51 + record.Author = proto.String(string(dht.self))
52 + blob := RecordBlobForSig(record)
53 +
54 + sk := dht.peerstore.PrivKey(dht.self)
55 + if sk == nil {
56 + log.Errorf("%s dht cannot get own private key!", dht.self)
57 + return nil, fmt.Errorf("cannot get private key to sign record!")
58 + }
59 +
60 + sig, err := sk.Sign(blob)
61 if err != nil {
62 return nil, err
63 }
64 +
65 record.Signature = sig
66 return record, nil
67 }
68
45 -func (dht *IpfsDHT) getPublicKey(pid peer.ID) (ci.PubKey, error) {
46 - log.Debug("getPublicKey for: %s", pid)
47 - p, err := dht.peerstore.FindOrCreate(pid)
48 - if err == nil {
49 - return p.PubKey(), nil
69 +func (dht *IpfsDHT) getPublicKeyOnline(ctx context.Context, p peer.ID) (ci.PubKey, error) {
70 + log.Debugf("getPublicKey for: %s", p)
71 +
72 + // check locally.
73 + pk := dht.peerstore.PubKey(p)
74 + if pk != nil {
75 + return pk, nil
76 + }
77 +
78 + // ok, try the node itself. if they're overwhelmed or slow we can move on.
79 + ctxT, _ := ctxutil.WithDeadlineFraction(ctx, 0.3)
80 + if pk, err := dht.getPublicKeyFromNode(ctx, p); err == nil {
81 + return pk, nil
82 }
83
52 - log.Debug("not in peerstore, searching dht.")
53 - ctxT, _ := context.WithTimeout(dht.ContextGroup.Context(), time.Second*5)
54 - val, err := dht.GetValue(ctxT, u.Key("/pk/"+string(pid)))
84 + // last ditch effort: let's try the dht.
85 + log.Debugf("pk for %s not in peerstore, and peer failed. trying dht.", p)
86 + pkkey := KeyForPublicKey(p)
87 +
88 + // ok, try the node itself. if they're overwhelmed or slow we can move on.
89 + val, err := dht.GetValue(ctxT, pkkey)
90 if err != nil {
91 log.Warning("Failed to find requested public key.")
92 return nil, err
93 }
94
60 - pubkey, err := ci.UnmarshalPublicKey(val)
95 + pk, err = ci.UnmarshalPublicKey(val)
96 if err != nil {
97 log.Errorf("Failed to unmarshal public key: %s", err)
98 return nil, err
99 }
65 - return pubkey, nil
100 + return pk, nil
101 }
102
68 -func (dht *IpfsDHT) verifyRecord(r *pb.Record) error {
103 +func (dht *IpfsDHT) getPublicKeyFromNode(ctx context.Context, p peer.ID) (ci.PubKey, error) {
104 +
105 + // check locally, just in case...
106 + pk := dht.peerstore.PubKey(p)
107 + if pk != nil {
108 + return pk, nil
109 + }
110 +
111 + pkkey := KeyForPublicKey(p)
112 + pmes, err := dht.getValueSingle(ctx, p, pkkey)
113 + if err != nil {
114 + return nil, err
115 + }
116 +
117 + // node doesn't have key :(
118 + record := pmes.GetRecord()
119 + if record == nil {
120 + return nil, fmt.Errorf("node not responding with its public key: %s", p)
121 + }
122 +
123 + // Success! We were given the value. we don't need to check
124 + // validity because a) we can't. b) we know the hash of the
125 + // key we're looking for.
126 + val := record.GetValue()
127 + log.Debug("dht got a value from other peer.")
128 +
129 + pk, err = ci.UnmarshalPublicKey(val)
130 + if err != nil {
131 + return nil, err
132 + }
133 +
134 + id, err := peer.IDFromPublicKey(pk)
135 + if err != nil {
136 + return nil, err
137 + }
138 + if id != p {
139 + return nil, fmt.Errorf("public key does not match id: %s", p)
140 + }
141 +
142 + // ok! it's valid. we got it!
143 + log.Debugf("dht got public key from node itself.")
144 + return pk, nil
145 +}
146 +
147 +// verifyRecordLocally attempts to verify a record. if we do not have the public
148 +// key, we fail. we do not search the dht.
149 +func (dht *IpfsDHT) verifyRecordLocally(r *pb.Record) error {
150 +
151 // First, validate the signature
70 - p, err := dht.peerstore.FindOrCreate(peer.ID(r.GetAuthor()))
152 + p := peer.ID(r.GetAuthor())
153 + pk := dht.peerstore.PubKey(p)
154 + if pk == nil {
155 + return fmt.Errorf("do not have public key for %s", p)
156 + }
157 +
158 + return dht.verifyRecord(r, pk)
159 +}
160 +
161 +// verifyRecordOnline verifies a record, searching the DHT for the public key
162 +// if necessary. The reason there is a distinction in the functions is that
163 +// retrieving arbitrary public keys from the DHT as a result of passively
164 +// receiving records (e.g. through a PUT_VALUE or ADD_PROVIDER) can cause a
165 +// massive amplification attack on the dht. Use with care.
166 +func (dht *IpfsDHT) verifyRecordOnline(ctx context.Context, r *pb.Record) error {
167 +
168 + // get the public key, search for it if necessary.
169 + p := peer.ID(r.GetAuthor())
170 + pk, err := dht.getPublicKeyOnline(ctx, p)
171 if err != nil {
172 return err
173 }
74 - k := u.Key(r.GetKey())
174
76 - blob := bytes.Join([][]byte{[]byte(k),
77 - r.GetValue(),
78 - []byte(r.GetAuthor())}, []byte{})
175 + return dht.verifyRecord(r, pk)
176 +}
177
80 - ok, err := p.PubKey().Verify(blob, r.GetSignature())
178 +func (dht *IpfsDHT) verifyRecord(r *pb.Record, pk ci.PubKey) error {
179 + // First, validate the signature
180 + blob := RecordBlobForSig(r)
181 + ok, err := pk.Verify(blob, r.GetSignature())
182 if err != nil {
183 log.Error("Signature verify failed.")
184 return err
185 }
85 -
186 if !ok {
187 + log.Error("dht found a forged record! (ignored)")
188 return ErrBadRecord
189 }
190
routing/dht/routing.go
+47 -73
@@ -41,7 +41,7 @@ func (dht *IpfsDHT) PutValue(ctx context.Context, key u.Key, value []byte) error
41
42 peers := dht.routingTable.NearestPeers(kb.ConvertKey(key), KValue)
43
44 - query := newQuery(key, dht.network, func(ctx context.Context, p peer.Peer) (*dhtQueryResult, error) {
44 + query := newQuery(key, dht.network, func(ctx context.Context, p peer.ID) (*dhtQueryResult, error) {
45 log.Debugf("%s PutValue qry part %v", dht.self, p)
46 err := dht.putValueToNetwork(ctx, p, string(key), rec)
47 if err != nil {
@@ -61,7 +61,6 @@ func (dht *IpfsDHT) GetValue(ctx context.Context, key u.Key) ([]byte, error) {
61 log.Debugf("Get Value [%s]", key)
62
63 // If we have it local, dont bother doing an RPC!
64 - // NOTE: this might not be what we want to do...
64 val, err := dht.getLocal(key)
65 if err == nil {
66 log.Debug("Got value locally!")
@@ -76,7 +75,7 @@ func (dht *IpfsDHT) GetValue(ctx context.Context, key u.Key) ([]byte, error) {
75 }
76
77 // setup the Query
79 - query := newQuery(key, dht.network, func(ctx context.Context, p peer.Peer) (*dhtQueryResult, error) {
78 + query := newQuery(key, dht.network, func(ctx context.Context, p peer.ID) (*dhtQueryResult, error) {
79
80 val, peers, err := dht.getValueOrPeers(ctx, p, key)
81 if err != nil {
@@ -131,14 +130,14 @@ func (dht *IpfsDHT) Provide(ctx context.Context, key u.Key) error {
130 // FindProvidersAsync is the same thing as FindProviders, but returns a channel.
131 // Peers will be returned on the channel as soon as they are found, even before
132 // the search query completes.
134 -func (dht *IpfsDHT) FindProvidersAsync(ctx context.Context, key u.Key, count int) <-chan peer.Peer {
133 +func (dht *IpfsDHT) FindProvidersAsync(ctx context.Context, key u.Key, count int) <-chan peer.PeerInfo {
134 log.Event(ctx, "findProviders", &key)
136 - peerOut := make(chan peer.Peer, count)
135 + peerOut := make(chan peer.PeerInfo, count)
136 go dht.findProvidersAsyncRoutine(ctx, key, count, peerOut)
137 return peerOut
138 }
139
141 -func (dht *IpfsDHT) findProvidersAsyncRoutine(ctx context.Context, key u.Key, count int, peerOut chan peer.Peer) {
140 +func (dht *IpfsDHT) findProvidersAsyncRoutine(ctx context.Context, key u.Key, count int, peerOut chan peer.PeerInfo) {
141 defer close(peerOut)
142
143 ps := pset.NewLimited(count)
@@ -147,7 +146,7 @@ func (dht *IpfsDHT) findProvidersAsyncRoutine(ctx context.Context, key u.Key, co
146 // NOTE: assuming that this list of peers is unique
147 if ps.TryAdd(p) {
148 select {
150 - case peerOut <- p:
149 + case peerOut <- dht.peerstore.PeerInfo(p):
150 case <-ctx.Done():
151 return
152 }
@@ -160,23 +159,18 @@ func (dht *IpfsDHT) findProvidersAsyncRoutine(ctx context.Context, key u.Key, co
159 }
160
161 // setup the Query
163 - query := newQuery(key, dht.network, func(ctx context.Context, p peer.Peer) (*dhtQueryResult, error) {
162 + query := newQuery(key, dht.network, func(ctx context.Context, p peer.ID) (*dhtQueryResult, error) {
163
164 pmes, err := dht.findProvidersSingle(ctx, p, key)
165 if err != nil {
166 return nil, err
167 }
168
170 - provs, errs := pb.PBPeersToPeers(dht.peerstore, pmes.GetProviderPeers())
171 - for _, err := range errs {
172 - if err != nil {
173 - log.Warning(err)
174 - }
175 - }
169 + provs := pb.PBPeersToPeerInfos(pmes.GetProviderPeers())
170
171 // Add unique providers from request, up to 'count'
172 for _, prov := range provs {
179 - if ps.TryAdd(prov) {
173 + if ps.TryAdd(prov.ID) {
174 select {
175 case peerOut <- prov:
176 case <-ctx.Done():
@@ -191,13 +185,7 @@ func (dht *IpfsDHT) findProvidersAsyncRoutine(ctx context.Context, key u.Key, co
185
186 // Give closer peers back to the query to be queried
187 closer := pmes.GetCloserPeers()
194 - clpeers, errs := pb.PBPeersToPeers(dht.peerstore, closer)
195 - for _, err := range errs {
196 - if err != nil {
197 - log.Warning(err)
198 - }
199 - }
200 -
188 + clpeers := pb.PBPeersToPeerInfos(closer)
189 return &dhtQueryResult{closerPeers: clpeers}, nil
190 })
191
@@ -208,62 +196,58 @@ func (dht *IpfsDHT) findProvidersAsyncRoutine(ctx context.Context, key u.Key, co
196 }
197 }
198
211 -func (dht *IpfsDHT) addPeerListAsync(ctx context.Context, k u.Key, peers []*pb.Message_Peer, ps *pset.PeerSet, count int, out chan peer.Peer) {
199 +func (dht *IpfsDHT) addPeerListAsync(ctx context.Context, k u.Key, peers []*pb.Message_Peer, ps *pset.PeerSet, count int, out chan peer.PeerInfo) {
200 var wg sync.WaitGroup
213 - for _, pbp := range peers {
201 + peerInfos := pb.PBPeersToPeerInfos(peers)
202 + for _, pi := range peerInfos {
203 wg.Add(1)
215 - go func(mp *pb.Message_Peer) {
204 + go func(pi peer.PeerInfo) {
205 defer wg.Done()
217 - // construct new peer
218 - p, err := dht.ensureConnectedToPeer(ctx, mp)
219 - if err != nil {
206 +
207 + p := pi.ID
208 + if err := dht.ensureConnectedToPeer(ctx, p); err != nil {
209 log.Errorf("%s", err)
210 return
211 }
223 - if p == nil {
224 - log.Error("Got nil peer from ensureConnectedToPeer")
225 - return
226 - }
212
213 dht.providers.AddProvider(k, p)
214 if ps.TryAdd(p) {
215 select {
231 - case out <- p:
216 + case out <- pi:
217 case <-ctx.Done():
218 return
219 }
220 } else if ps.Size() >= count {
221 return
222 }
238 - }(pbp)
223 + }(pi)
224 }
225 wg.Wait()
226 }
227
228 // FindPeer searches for a peer with given ID.
244 -func (dht *IpfsDHT) FindPeer(ctx context.Context, id peer.ID) (peer.Peer, error) {
229 +func (dht *IpfsDHT) FindPeer(ctx context.Context, id peer.ID) (peer.PeerInfo, error) {
230
231 // Check if were already connected to them
247 - p, _ := dht.FindLocal(id)
248 - if p != nil {
249 - return p, nil
232 + if pi, _ := dht.FindLocal(id); pi.ID != "" {
233 + return pi, nil
234 }
235
236 closest := dht.routingTable.NearestPeers(kb.ConvertPeerID(id), AlphaValue)
237 if closest == nil || len(closest) == 0 {
254 - return nil, kb.ErrLookupFailure
238 + return peer.PeerInfo{}, kb.ErrLookupFailure
239 }
240
241 // Sanity...
242 for _, p := range closest {
259 - if p.ID().Equal(id) {
243 + if p == id {
244 log.Error("Found target peer in list of closest peers...")
261 - return p, nil
245 + return dht.peerstore.PeerInfo(p), nil
246 }
247 }
248
249 // setup the Query
266 - query := newQuery(u.Key(id), dht.network, func(ctx context.Context, p peer.Peer) (*dhtQueryResult, error) {
250 + query := newQuery(u.Key(id), dht.network, func(ctx context.Context, p peer.ID) (*dhtQueryResult, error) {
251
252 pmes, err := dht.findPeerSingle(ctx, p, id)
253 if err != nil {
@@ -271,45 +255,40 @@ func (dht *IpfsDHT) FindPeer(ctx context.Context, id peer.ID) (peer.Peer, error)
255 }
256
257 closer := pmes.GetCloserPeers()
274 - clpeers, errs := pb.PBPeersToPeers(dht.peerstore, closer)
275 - for _, err := range errs {
276 - if err != nil {
277 - log.Warning(err)
278 - }
279 - }
258 + clpeerInfos := pb.PBPeersToPeerInfos(closer)
259
260 // see it we got the peer here
282 - for _, np := range clpeers {
283 - if string(np.ID()) == string(id) {
261 + for _, npi := range clpeerInfos {
262 + if npi.ID == id {
263 return &dhtQueryResult{
285 - peer: np,
264 + peer: npi,
265 success: true,
266 }, nil
267 }
268 }
269
291 - return &dhtQueryResult{closerPeers: clpeers}, nil
270 + return &dhtQueryResult{closerPeers: clpeerInfos}, nil
271 })
272
273 // run it!
274 result, err := query.Run(ctx, closest)
275 if err != nil {
297 - return nil, err
276 + return peer.PeerInfo{}, err
277 }
278
279 log.Debugf("FindPeer %v %v", id, result.success)
301 - if result.peer == nil {
302 - return nil, routing.ErrNotFound
280 + if result.peer.ID == "" {
281 + return peer.PeerInfo{}, routing.ErrNotFound
282 }
283
284 return result.peer, nil
285 }
286
287 // FindPeersConnectedToPeer searches for peers directly connected to a given peer.
309 -func (dht *IpfsDHT) FindPeersConnectedToPeer(ctx context.Context, id peer.ID) (<-chan peer.Peer, error) {
288 +func (dht *IpfsDHT) FindPeersConnectedToPeer(ctx context.Context, id peer.ID) (<-chan peer.PeerInfo, error) {
289
311 - peerchan := make(chan peer.Peer, asyncQueryBuffer)
312 - peersSeen := map[string]peer.Peer{}
290 + peerchan := make(chan peer.PeerInfo, asyncQueryBuffer)
291 + peersSeen := peer.Set{}
292
293 closest := dht.routingTable.NearestPeers(kb.ConvertPeerID(id), AlphaValue)
294 if closest == nil || len(closest) == 0 {
@@ -317,42 +296,37 @@ func (dht *IpfsDHT) FindPeersConnectedToPeer(ctx context.Context, id peer.ID) (<
296 }
297
298 // setup the Query
320 - query := newQuery(u.Key(id), dht.network, func(ctx context.Context, p peer.Peer) (*dhtQueryResult, error) {
299 + query := newQuery(u.Key(id), dht.network, func(ctx context.Context, p peer.ID) (*dhtQueryResult, error) {
300
301 pmes, err := dht.findPeerSingle(ctx, p, id)
302 if err != nil {
303 return nil, err
304 }
305
327 - var clpeers []peer.Peer
306 + var clpeers []peer.PeerInfo
307 closer := pmes.GetCloserPeers()
308 for _, pbp := range closer {
330 - // skip peers already seen
331 - if _, found := peersSeen[string(pbp.GetId())]; found {
332 - continue
333 - }
309 + pi := pb.PBPeerToPeerInfo(pbp)
310
335 - // skip peers that fail to unmarshal
336 - p, err := pb.PBPeerToPeer(dht.peerstore, pbp)
337 - if err != nil {
338 - log.Warning(err)
311 + // skip peers already seen
312 + if _, found := peersSeen[pi.ID]; found {
313 continue
314 }
315 + peersSeen[pi.ID] = struct{}{}
316
317 // if peer is connected, send it to our client.
318 if pb.Connectedness(*pbp.Connection) == inet.Connected {
319 select {
320 case <-ctx.Done():
321 return nil, ctx.Err()
347 - case peerchan <- p:
322 + case peerchan <- pi:
323 }
324 }
325
351 - peersSeen[string(p.ID())] = p
352 -
326 // if peer is the peer we're looking for, don't bother querying it.
327 + // TODO maybe query it?
328 if pb.Connectedness(*pbp.Connection) != inet.Connected {
355 - clpeers = append(clpeers, p)
329 + clpeers = append(clpeers, pi)
330 }
331 }
332
@@ -374,7 +348,7 @@ func (dht *IpfsDHT) FindPeersConnectedToPeer(ctx context.Context, id peer.ID) (<
348 }
349
350 // Ping a peer, log the time it took
377 -func (dht *IpfsDHT) Ping(ctx context.Context, p peer.Peer) error {
351 +func (dht *IpfsDHT) Ping(ctx context.Context, p peer.ID) error {
352 // Thoughts: maybe this should accept an ID and do a peer lookup?
353 log.Debugf("ping %s start", p)
354
routing/kbucket/bucket.go
+5 -5
@@ -23,7 +23,7 @@ func (b *Bucket) find(id peer.ID) *list.Element {
23 b.lk.RLock()
24 defer b.lk.RUnlock()
25 for e := b.list.Front(); e != nil; e = e.Next() {
26 - if e.Value.(peer.Peer).ID().Equal(id) {
26 + if e.Value.(peer.ID) == id {
27 return e
28 }
29 }
@@ -36,18 +36,18 @@ func (b *Bucket) moveToFront(e *list.Element) {
36 b.lk.Unlock()
37 }
38
39 -func (b *Bucket) pushFront(p peer.Peer) {
39 +func (b *Bucket) pushFront(p peer.ID) {
40 b.lk.Lock()
41 b.list.PushFront(p)
42 b.lk.Unlock()
43 }
44
45 -func (b *Bucket) popBack() peer.Peer {
45 +func (b *Bucket) popBack() peer.ID {
46 b.lk.Lock()
47 defer b.lk.Unlock()
48 last := b.list.Back()
49 b.list.Remove(last)
50 - return last.Value.(peer.Peer)
50 + return last.Value.(peer.ID)
51 }
52
53 func (b *Bucket) len() int {
@@ -68,7 +68,7 @@ func (b *Bucket) Split(cpl int, target ID) *Bucket {
68 newbuck.list = out
69 e := b.list.Front()
70 for e != nil {
71 - peerID := ConvertPeerID(e.Value.(peer.Peer).ID())
71 + peerID := ConvertPeerID(e.Value.(peer.ID))
72 peerCPL := commonPrefixLen(peerID, target)
73 if peerCPL > cpl {
74 cur := e
routing/kbucket/table.go
+28 -24
@@ -23,6 +23,9 @@ type RoutingTable struct {
23 // Blanket lock, refine later for better performance
24 tabLock sync.RWMutex
25
26 + // latency metrics
27 + metrics peer.Metrics
28 +
29 // Maximum acceptable latency for peers in this cluster
30 maxLatency time.Duration
31
@@ -32,21 +35,22 @@ type RoutingTable struct {
35 }
36
37 // NewRoutingTable creates a new routing table with a given bucketsize, local ID, and latency tolerance.
35 -func NewRoutingTable(bucketsize int, localID ID, latency time.Duration) *RoutingTable {
38 +func NewRoutingTable(bucketsize int, localID ID, latency time.Duration, m peer.Metrics) *RoutingTable {
39 rt := new(RoutingTable)
40 rt.Buckets = []*Bucket{newBucket()}
41 rt.bucketsize = bucketsize
42 rt.local = localID
43 rt.maxLatency = latency
44 + rt.metrics = m
45 return rt
46 }
47
48 // Update adds or moves the given peer to the front of its respective bucket
49 // If a peer gets removed from a bucket, it is returned
46 -func (rt *RoutingTable) Update(p peer.Peer) peer.Peer {
50 +func (rt *RoutingTable) Update(p peer.ID) peer.ID {
51 rt.tabLock.Lock()
52 defer rt.tabLock.Unlock()
49 - peerID := ConvertPeerID(p.ID())
53 + peerID := ConvertPeerID(p)
54 cpl := commonPrefixLen(peerID, rt.local)
55
56 bucketID := cpl
@@ -55,12 +59,12 @@ func (rt *RoutingTable) Update(p peer.Peer) peer.Peer {
59 }
60
61 bucket := rt.Buckets[bucketID]
58 - e := bucket.find(p.ID())
62 + e := bucket.find(p)
63 if e == nil {
64 // New peer, add to bucket
61 - if p.GetLatency() > rt.maxLatency {
65 + if rt.metrics.LatencyEWMA(p) > rt.maxLatency {
66 // Connection doesnt meet requirements, skip!
63 - return nil
67 + return ""
68 }
69 bucket.pushFront(p)
70
@@ -75,16 +79,16 @@ func (rt *RoutingTable) Update(p peer.Peer) peer.Peer {
79 return bucket.popBack()
80 }
81 }
78 - return nil
82 + return ""
83 }
84 // If the peer is already in the table, move it to the front.
85 // This signifies that it it "more active" and the less active nodes
86 // Will as a result tend towards the back of the list
87 bucket.moveToFront(e)
84 - return nil
88 + return ""
89 }
90
87 -func (rt *RoutingTable) nextBucket() peer.Peer {
91 +func (rt *RoutingTable) nextBucket() peer.ID {
92 bucket := rt.Buckets[len(rt.Buckets)-1]
93 newBucket := bucket.Split(len(rt.Buckets)-1, rt.local)
94 rt.Buckets = append(rt.Buckets, newBucket)
@@ -96,12 +100,12 @@ func (rt *RoutingTable) nextBucket() peer.Peer {
100 if bucket.len() > rt.bucketsize {
101 return bucket.popBack()
102 }
99 - return nil
103 + return ""
104 }
105
106 // A helper struct to sort peers by their distance to the local node
107 type peerDistance struct {
104 - p peer.Peer
108 + p peer.ID
109 distance ID
110 }
111
@@ -118,8 +122,8 @@ func (p peerSorterArr) Less(a, b int) bool {
122
123 func copyPeersFromList(target ID, peerArr peerSorterArr, peerList *list.List) peerSorterArr {
124 for e := peerList.Front(); e != nil; e = e.Next() {
121 - p := e.Value.(peer.Peer)
122 - pID := ConvertPeerID(p.ID())
125 + p := e.Value.(peer.ID)
126 + pID := ConvertPeerID(p)
127 pd := peerDistance{
128 p: p,
129 distance: xor(target, pID),
@@ -134,27 +138,27 @@ func copyPeersFromList(target ID, peerArr peerSorterArr, peerList *list.List) pe
138 }
139
140 // Find a specific peer by ID or return nil
137 -func (rt *RoutingTable) Find(id peer.ID) peer.Peer {
141 +func (rt *RoutingTable) Find(id peer.ID) peer.ID {
142 srch := rt.NearestPeers(ConvertPeerID(id), 1)
139 - if len(srch) == 0 || !srch[0].ID().Equal(id) {
140 - return nil
143 + if len(srch) == 0 || srch[0] != id {
144 + return ""
145 }
146 return srch[0]
147 }
148
149 // NearestPeer returns a single peer that is nearest to the given ID
146 -func (rt *RoutingTable) NearestPeer(id ID) peer.Peer {
150 +func (rt *RoutingTable) NearestPeer(id ID) peer.ID {
151 peers := rt.NearestPeers(id, 1)
152 if len(peers) > 0 {
153 return peers[0]
154 }
155
156 log.Errorf("NearestPeer: Returning nil, table size = %d", rt.Size())
153 - return nil
157 + return ""
158 }
159
160 // NearestPeers returns a list of the 'count' closest peers to the given ID
157 -func (rt *RoutingTable) NearestPeers(id ID, count int) []peer.Peer {
161 +func (rt *RoutingTable) NearestPeers(id ID, count int) []peer.ID {
162 rt.tabLock.RLock()
163 defer rt.tabLock.RUnlock()
164 cpl := commonPrefixLen(id, rt.local)
@@ -186,7 +190,7 @@ func (rt *RoutingTable) NearestPeers(id ID, count int) []peer.Peer {
190 // Sort by distance to local peer
191 sort.Sort(peerArr)
192
189 - var out []peer.Peer
193 + var out []peer.ID
194 for i := 0; i < count && i < peerArr.Len(); i++ {
195 out = append(out, peerArr[i].p)
196 }
@@ -205,11 +209,11 @@ func (rt *RoutingTable) Size() int {
209
210 // ListPeers takes a RoutingTable and returns a list of all peers from all buckets in the table.
211 // NOTE: This is potentially unsafe... use at your own risk
208 -func (rt *RoutingTable) ListPeers() []peer.Peer {
209 - var peers []peer.Peer
212 +func (rt *RoutingTable) ListPeers() []peer.ID {
213 + var peers []peer.ID
214 for _, buck := range rt.Buckets {
215 for e := buck.getIter(); e != nil; e = e.Next() {
212 - peers = append(peers, e.Value.(peer.Peer))
216 + peers = append(peers, e.Value.(peer.ID))
217 }
218 }
219 return peers
@@ -221,6 +225,6 @@ func (rt *RoutingTable) Print() {
225 rt.tabLock.RLock()
226 peers := rt.ListPeers()
227 for i, p := range peers {
224 - fmt.Printf("%d) %s %s\n", i, p.ID().Pretty(), p.GetLatency().String())
228 + fmt.Printf("%d) %s %s\n", i, p.Pretty(), rt.metrics.LatencyEWMA(p).String())
229 }
230 }
routing/kbucket/table_test.go
+42 -46
@@ -1,8 +1,6 @@
1 package kbucket
2
3 import (
4 - crand "crypto/rand"
5 - "crypto/sha256"
4 "math/rand"
5 "testing"
6 "time"
@@ -12,37 +10,29 @@ import (
10 peer "github.com/jbenet/go-ipfs/peer"
11 )
12
15 -func RandID() ID {
16 - buf := make([]byte, 16)
17 - crand.Read(buf)
18 -
19 - hash := sha256.Sum256(buf)
20 - return ID(hash[:])
21 -}
22 -
13 // Test basic features of the bucket struct
14 func TestBucket(t *testing.T) {
15 b := newBucket()
16
27 - peers := make([]peer.Peer, 100)
17 + peers := make([]peer.ID, 100)
18 for i := 0; i < 100; i++ {
29 - peers[i] = tu.RandPeer()
19 + peers[i] = tu.RandPeerIDFatal(t)
20 b.pushFront(peers[i])
21 }
22
33 - local := tu.RandPeer()
34 - localID := ConvertPeerID(local.ID())
23 + local := tu.RandPeerIDFatal(t)
24 + localID := ConvertPeerID(local)
25
26 i := rand.Intn(len(peers))
37 - e := b.find(peers[i].ID())
27 + e := b.find(peers[i])
28 if e == nil {
29 t.Errorf("Failed to find peer: %v", peers[i])
30 }
31
42 - spl := b.Split(0, ConvertPeerID(local.ID()))
32 + spl := b.Split(0, ConvertPeerID(local))
33 llist := b.list
34 for e := llist.Front(); e != nil; e = e.Next() {
45 - p := ConvertPeerID(e.Value.(peer.Peer).ID())
35 + p := ConvertPeerID(e.Value.(peer.ID))
36 cpl := commonPrefixLen(p, localID)
37 if cpl > 0 {
38 t.Fatalf("Split failed. found id with cpl > 0 in 0 bucket")
@@ -51,7 +41,7 @@ func TestBucket(t *testing.T) {
41
42 rlist := spl.list
43 for e := rlist.Front(); e != nil; e = e.Next() {
54 - p := ConvertPeerID(e.Value.(peer.Peer).ID())
44 + p := ConvertPeerID(e.Value.(peer.ID))
45 cpl := commonPrefixLen(p, localID)
46 if cpl == 0 {
47 t.Fatalf("Split failed. found id with cpl == 0 in non 0 bucket")
@@ -61,24 +51,25 @@ func TestBucket(t *testing.T) {
51
52 // Right now, this just makes sure that it doesnt hang or crash
53 func TestTableUpdate(t *testing.T) {
64 - local := tu.RandPeer()
65 - rt := NewRoutingTable(10, ConvertPeerID(local.ID()), time.Hour)
54 + local := tu.RandPeerIDFatal(t)
55 + m := peer.NewMetrics()
56 + rt := NewRoutingTable(10, ConvertPeerID(local), time.Hour, m)
57
67 - peers := make([]peer.Peer, 100)
58 + peers := make([]peer.ID, 100)
59 for i := 0; i < 100; i++ {
69 - peers[i] = tu.RandPeer()
60 + peers[i] = tu.RandPeerIDFatal(t)
61 }
62
63 // Testing Update
64 for i := 0; i < 10000; i++ {
65 p := rt.Update(peers[rand.Intn(len(peers))])
75 - if p != nil {
66 + if p != "" {
67 //t.Log("evicted peer.")
68 }
69 }
70
71 for i := 0; i < 100; i++ {
81 - id := RandID()
72 + id := ConvertPeerID(tu.RandPeerIDFatal(t))
73 ret := rt.NearestPeers(id, 5)
74 if len(ret) == 0 {
75 t.Fatal("Failed to find node near ID.")
@@ -87,34 +78,36 @@ func TestTableUpdate(t *testing.T) {
78 }
79
80 func TestTableFind(t *testing.T) {
90 - local := tu.RandPeer()
91 - rt := NewRoutingTable(10, ConvertPeerID(local.ID()), time.Hour)
81 + local := tu.RandPeerIDFatal(t)
82 + m := peer.NewMetrics()
83 + rt := NewRoutingTable(10, ConvertPeerID(local), time.Hour, m)
84
93 - peers := make([]peer.Peer, 100)
85 + peers := make([]peer.ID, 100)
86 for i := 0; i < 5; i++ {
95 - peers[i] = tu.RandPeer()
87 + peers[i] = tu.RandPeerIDFatal(t)
88 rt.Update(peers[i])
89 }
90
91 t.Logf("Searching for peer: '%s'", peers[2])
100 - found := rt.NearestPeer(ConvertPeerID(peers[2].ID()))
101 - if !found.ID().Equal(peers[2].ID()) {
92 + found := rt.NearestPeer(ConvertPeerID(peers[2]))
93 + if !(found == peers[2]) {
94 t.Fatalf("Failed to lookup known node...")
95 }
96 }
97
98 func TestTableFindMultiple(t *testing.T) {
107 - local := tu.RandPeer()
108 - rt := NewRoutingTable(20, ConvertPeerID(local.ID()), time.Hour)
99 + local := tu.RandPeerIDFatal(t)
100 + m := peer.NewMetrics()
101 + rt := NewRoutingTable(20, ConvertPeerID(local), time.Hour, m)
102
110 - peers := make([]peer.Peer, 100)
103 + peers := make([]peer.ID, 100)
104 for i := 0; i < 18; i++ {
112 - peers[i] = tu.RandPeer()
105 + peers[i] = tu.RandPeerIDFatal(t)
106 rt.Update(peers[i])
107 }
108
109 t.Logf("Searching for peer: '%s'", peers[2])
117 - found := rt.NearestPeers(ConvertPeerID(peers[2].ID()), 15)
110 + found := rt.NearestPeers(ConvertPeerID(peers[2]), 15)
111 if len(found) != 15 {
112 t.Fatalf("Got back different number of peers than we expected.")
113 }
@@ -125,10 +118,11 @@ func TestTableFindMultiple(t *testing.T) {
118 // and set GOMAXPROCS above 1
119 func TestTableMultithreaded(t *testing.T) {
120 local := peer.ID("localPeer")
128 - tab := NewRoutingTable(20, ConvertPeerID(local), time.Hour)
129 - var peers []peer.Peer
121 + m := peer.NewMetrics()
122 + tab := NewRoutingTable(20, ConvertPeerID(local), time.Hour, m)
123 + var peers []peer.ID
124 for i := 0; i < 500; i++ {
131 - peers = append(peers, tu.RandPeer())
125 + peers = append(peers, tu.RandPeerIDFatal(t))
126 }
127
128 done := make(chan struct{})
@@ -151,7 +145,7 @@ func TestTableMultithreaded(t *testing.T) {
145 go func() {
146 for i := 0; i < 1000; i++ {
147 n := rand.Intn(len(peers))
154 - tab.Find(peers[n].ID())
148 + tab.Find(peers[n])
149 }
150 done <- struct{}{}
151 }()
@@ -163,11 +157,12 @@ func TestTableMultithreaded(t *testing.T) {
157 func BenchmarkUpdates(b *testing.B) {
158 b.StopTimer()
159 local := ConvertKey("localKey")
166 - tab := NewRoutingTable(20, local, time.Hour)
160 + m := peer.NewMetrics()
161 + tab := NewRoutingTable(20, local, time.Hour, m)
162
168 - var peers []peer.Peer
163 + var peers []peer.ID
164 for i := 0; i < b.N; i++ {
170 - peers = append(peers, tu.RandPeer())
165 + peers = append(peers, tu.RandPeerIDFatal(b))
166 }
167
168 b.StartTimer()
@@ -179,16 +174,17 @@ func BenchmarkUpdates(b *testing.B) {
174 func BenchmarkFinds(b *testing.B) {
175 b.StopTimer()
176 local := ConvertKey("localKey")
182 - tab := NewRoutingTable(20, local, time.Hour)
177 + m := peer.NewMetrics()
178 + tab := NewRoutingTable(20, local, time.Hour, m)
179
184 - var peers []peer.Peer
180 + var peers []peer.ID
181 for i := 0; i < b.N; i++ {
186 - peers = append(peers, tu.RandPeer())
182 + peers = append(peers, tu.RandPeerIDFatal(b))
183 tab.Update(peers[i])
184 }
185
186 b.StartTimer()
187 for i := 0; i < b.N; i++ {
192 - tab.Find(peers[i].ID())
188 + tab.Find(peers[i])
189 }
190 }
routing/kbucket/util.go
+1 -1
@@ -40,7 +40,7 @@ func commonPrefixLen(a, b ID) int {
40
41 // ConvertPeerID creates a DHT ID by hashing a Peer ID (Multihash)
42 func ConvertPeerID(id peer.ID) ID {
43 - hash := sha256.Sum256(id)
43 + hash := sha256.Sum256([]byte(id))
44 return hash[:]
45 }
46
routing/mock/client.go
+6 -6
@@ -15,7 +15,7 @@ var log = u.Logger("mockrouter")
15 type client struct {
16 datastore ds.Datastore
17 server server
18 - peer peer.Peer
18 + peer peer.PeerInfo
19 }
20
21 // FIXME(brian): is this method meant to simulate putting a value into the network?
@@ -40,17 +40,17 @@ func (c *client) GetValue(ctx context.Context, key u.Key) ([]byte, error) {
40 return data, nil
41 }
42
43 -func (c *client) FindProviders(ctx context.Context, key u.Key) ([]peer.Peer, error) {
43 +func (c *client) FindProviders(ctx context.Context, key u.Key) ([]peer.PeerInfo, error) {
44 return c.server.Providers(key), nil
45 }
46
47 -func (c *client) FindPeer(ctx context.Context, pid peer.ID) (peer.Peer, error) {
47 +func (c *client) FindPeer(ctx context.Context, pid peer.ID) (peer.PeerInfo, error) {
48 log.Debugf("FindPeer: %s", pid)
49 - return nil, nil
49 + return peer.PeerInfo{}, nil
50 }
51
52 -func (c *client) FindProvidersAsync(ctx context.Context, k u.Key, max int) <-chan peer.Peer {
53 - out := make(chan peer.Peer)
52 +func (c *client) FindProvidersAsync(ctx context.Context, k u.Key, max int) <-chan peer.PeerInfo {
53 + out := make(chan peer.PeerInfo)
54 go func() {
55 defer close(out)
56 for i, p := range c.server.Providers(k) {
routing/mock/interface.go
+4 -4
@@ -15,13 +15,13 @@ import (
15
16 // Server provides mockrouting Clients
17 type Server interface {
18 - Client(p peer.Peer) Client
19 - ClientWithDatastore(peer.Peer, ds.Datastore) Client
18 + Client(p peer.PeerInfo) Client
19 + ClientWithDatastore(peer.PeerInfo, ds.Datastore) Client
20 }
21
22 // Client implements IpfsRouting
23 type Client interface {
24 - FindProviders(context.Context, u.Key) ([]peer.Peer, error)
24 + FindProviders(context.Context, u.Key) ([]peer.PeerInfo, error)
25
26 routing.IpfsRouting
27 }
@@ -37,7 +37,7 @@ func NewServer() Server {
37 // NewServerWithDelay returns a mockrouting Server with a delay!
38 func NewServerWithDelay(conf DelayConfig) Server {
39 return &s{
40 - providers: make(map[u.Key]map[u.Key]providerRecord),
40 + providers: make(map[u.Key]map[peer.ID]providerRecord),
41 delayConf: conf,
42 }
43 }
routing/mock/mockrouting_test.go
+22 -24
@@ -1,7 +1,6 @@
1 package mockrouting
2
3 import (
4 - "bytes"
4 "testing"
5 "time"
6
@@ -9,17 +8,16 @@ import (
8 peer "github.com/jbenet/go-ipfs/peer"
9 u "github.com/jbenet/go-ipfs/util"
10 delay "github.com/jbenet/go-ipfs/util/delay"
12 - testutil "github.com/jbenet/go-ipfs/util/testutil"
11 )
12
13 func TestKeyNotFound(t *testing.T) {
14
17 - var peer = testutil.NewPeerWithID(peer.ID([]byte("the peer id")))
15 + var pi = peer.PeerInfo{ID: peer.ID("the peer id")}
16 var key = u.Key("mock key")
17 var ctx = context.Background()
18
19 rs := NewServer()
22 - providers := rs.Client(peer).FindProvidersAsync(ctx, key, 10)
20 + providers := rs.Client(pi).FindProvidersAsync(ctx, key, 10)
21 _, ok := <-providers
22 if ok {
23 t.Fatal("should be closed")
@@ -27,9 +25,9 @@ func TestKeyNotFound(t *testing.T) {
25 }
26
27 func TestClientFindProviders(t *testing.T) {
30 - peer := testutil.NewPeerWithIDString("42")
28 + pi := peer.PeerInfo{ID: peer.ID("42")}
29 rs := NewServer()
32 - client := rs.Client(peer)
30 + client := rs.Client(pi)
31
32 k := u.Key("hello")
33 err := client.Provide(context.Background(), k)
@@ -41,14 +39,14 @@ func TestClientFindProviders(t *testing.T) {
39 time.Sleep(time.Millisecond * 300)
40 max := 100
41
44 - providersFromHashTable, err := rs.Client(peer).FindProviders(context.Background(), k)
42 + providersFromHashTable, err := rs.Client(pi).FindProviders(context.Background(), k)
43 if err != nil {
44 t.Fatal(err)
45 }
46
47 isInHT := false
50 - for _, p := range providersFromHashTable {
51 - if bytes.Equal(p.ID(), peer.ID()) {
48 + for _, pi := range providersFromHashTable {
49 + if pi.ID == pi.ID {
50 isInHT = true
51 }
52 }
@@ -57,8 +55,8 @@ func TestClientFindProviders(t *testing.T) {
55 }
56 providersFromClient := client.FindProvidersAsync(context.Background(), u.Key("hello"), max)
57 isInClient := false
60 - for p := range providersFromClient {
61 - if bytes.Equal(p.ID(), peer.ID()) {
58 + for pi := range providersFromClient {
59 + if pi.ID == pi.ID {
60 isInClient = true
61 }
62 }
@@ -72,16 +70,16 @@ func TestClientOverMax(t *testing.T) {
70 k := u.Key("hello")
71 numProvidersForHelloKey := 100
72 for i := 0; i < numProvidersForHelloKey; i++ {
75 - peer := testutil.NewPeerWithIDString(string(i))
76 - err := rs.Client(peer).Provide(context.Background(), k)
73 + pi := peer.PeerInfo{ID: peer.ID(i)}
74 + err := rs.Client(pi).Provide(context.Background(), k)
75 if err != nil {
76 t.Fatal(err)
77 }
78 }
79
80 max := 10
83 - peer := testutil.NewPeerWithIDString("TODO")
84 - client := rs.Client(peer)
81 + pi := peer.PeerInfo{ID: peer.ID("TODO")}
82 + client := rs.Client(pi)
83
84 providersFromClient := client.FindProvidersAsync(context.Background(), k, max)
85 i := 0
@@ -102,16 +100,16 @@ func TestCanceledContext(t *testing.T) {
100 i := 0
101 go func() { // infinite stream
102 for {
105 - peer := testutil.NewPeerWithIDString(string(i))
106 - err := rs.Client(peer).Provide(context.Background(), k)
103 + pi := peer.PeerInfo{ID: peer.ID(i)}
104 + err := rs.Client(pi).Provide(context.Background(), k)
105 if err != nil {
108 - t.Fatal(err)
106 + t.Error(err)
107 }
108 i++
109 }
110 }()
111
114 - local := testutil.NewPeerWithIDString("peer id doesn't matter")
112 + local := peer.PeerInfo{ID: peer.ID("peer id doesn't matter")}
113 client := rs.Client(local)
114
115 t.Log("warning: max is finite so this test is non-deterministic")
@@ -137,7 +135,7 @@ func TestCanceledContext(t *testing.T) {
135
136 func TestValidAfter(t *testing.T) {
137
140 - var p = testutil.NewPeerWithID(peer.ID([]byte("the peer id")))
138 + var pi = peer.PeerInfo{ID: peer.ID("the peer id")}
139 var key = u.Key("mock key")
140 var ctx = context.Background()
141 conf := DelayConfig{
@@ -147,10 +145,10 @@ func TestValidAfter(t *testing.T) {
145
146 rs := NewServerWithDelay(conf)
147
150 - rs.Client(p).Provide(ctx, key)
148 + rs.Client(pi).Provide(ctx, key)
149
152 - var providers []peer.Peer
153 - providers, err := rs.Client(p).FindProviders(ctx, key)
150 + var providers []peer.PeerInfo
151 + providers, err := rs.Client(pi).FindProviders(ctx, key)
152 if err != nil {
153 t.Fatal(err)
154 }
@@ -159,7 +157,7 @@ func TestValidAfter(t *testing.T) {
157 }
158
159 conf.ValueVisibility.Set(0)
162 - providers, err = rs.Client(p).FindProviders(ctx, key)
160 + providers, err = rs.Client(pi).FindProviders(ctx, key)
161 if err != nil {
162 t.Fatal(err)
163 }
routing/mock/server.go
+11 -11
@@ -12,8 +12,8 @@ import (
12
13 // server is the mockrouting.Client's private interface to the routing server
14 type server interface {
15 - Announce(peer.Peer, u.Key) error
16 - Providers(u.Key) []peer.Peer
15 + Announce(peer.PeerInfo, u.Key) error
16 + Providers(u.Key) []peer.PeerInfo
17
18 Server
19 }
@@ -23,36 +23,36 @@ type s struct {
23 delayConf DelayConfig
24
25 lock sync.RWMutex
26 - providers map[u.Key]map[u.Key]providerRecord
26 + providers map[u.Key]map[peer.ID]providerRecord
27 }
28
29 type providerRecord struct {
30 - Peer peer.Peer
30 + Peer peer.PeerInfo
31 Created time.Time
32 }
33
34 -func (rs *s) Announce(p peer.Peer, k u.Key) error {
34 +func (rs *s) Announce(p peer.PeerInfo, k u.Key) error {
35 rs.lock.Lock()
36 defer rs.lock.Unlock()
37
38 _, ok := rs.providers[k]
39 if !ok {
40 - rs.providers[k] = make(map[u.Key]providerRecord)
40 + rs.providers[k] = make(map[peer.ID]providerRecord)
41 }
42 - rs.providers[k][p.Key()] = providerRecord{
42 + rs.providers[k][p.ID] = providerRecord{
43 Created: time.Now(),
44 Peer: p,
45 }
46 return nil
47 }
48
49 -func (rs *s) Providers(k u.Key) []peer.Peer {
49 +func (rs *s) Providers(k u.Key) []peer.PeerInfo {
50 rs.delayConf.Query.Wait() // before locking
51
52 rs.lock.RLock()
53 defer rs.lock.RUnlock()
54
55 - var ret []peer.Peer
55 + var ret []peer.PeerInfo
56 records, ok := rs.providers[k]
57 if !ok {
58 return ret
@@ -71,11 +71,11 @@ func (rs *s) Providers(k u.Key) []peer.Peer {
71 return ret
72 }
73
74 -func (rs *s) Client(p peer.Peer) Client {
74 +func (rs *s) Client(p peer.PeerInfo) Client {
75 return rs.ClientWithDatastore(p, ds.NewMapDatastore())
76 }
77
78 -func (rs *s) ClientWithDatastore(p peer.Peer, datastore ds.Datastore) Client {
78 +func (rs *s) ClientWithDatastore(p peer.PeerInfo, datastore ds.Datastore) Client {
79 return &client{
80 peer: p,
81 datastore: ds.NewMapDatastore(),
routing/routing.go
+4 -3
@@ -16,7 +16,7 @@ var ErrNotFound = errors.New("routing: not found")
16 // IpfsRouting is the routing module interface
17 // It is implemented by things like DHTs, etc.
18 type IpfsRouting interface {
19 - FindProvidersAsync(context.Context, u.Key, int) <-chan peer.Peer
19 + FindProvidersAsync(context.Context, u.Key, int) <-chan peer.PeerInfo
20
21 // Basic Put/Get
22
@@ -33,6 +33,7 @@ type IpfsRouting interface {
33 Provide(context.Context, u.Key) error
34
35 // Find specific Peer
36 - // FindPeer searches for a peer with given ID.
37 - FindPeer(context.Context, peer.ID) (peer.Peer, error)
36 + // FindPeer searches for a peer with given ID, returns a peer.PeerInfo
37 + // with relevant addresses.
38 + FindPeer(context.Context, peer.ID) (peer.PeerInfo, error)
39 }
util/peerset/peerset.go
+10 -10
@@ -7,34 +7,34 @@ import (
7
8 // PeerSet is a threadsafe set of peers
9 type PeerSet struct {
10 - ps map[string]bool // FIXME can be map[string]struct{}
10 + ps map[peer.ID]struct{}
11 lk sync.RWMutex
12 size int
13 }
14
15 func New() *PeerSet {
16 ps := new(PeerSet)
17 - ps.ps = make(map[string]bool)
17 + ps.ps = make(map[peer.ID]struct{})
18 ps.size = -1
19 return ps
20 }
21
22 func NewLimited(size int) *PeerSet {
23 ps := new(PeerSet)
24 - ps.ps = make(map[string]bool)
24 + ps.ps = make(map[peer.ID]struct{})
25 ps.size = size
26 return ps
27 }
28
29 -func (ps *PeerSet) Add(p peer.Peer) {
29 +func (ps *PeerSet) Add(p peer.ID) {
30 ps.lk.Lock()
31 - ps.ps[string(p.ID())] = true
31 + ps.ps[p] = struct{}{}
32 ps.lk.Unlock()
33 }
34
35 -func (ps *PeerSet) Contains(p peer.Peer) bool {
35 +func (ps *PeerSet) Contains(p peer.ID) bool {
36 ps.lk.RLock()
37 - _, ok := ps.ps[string(p.ID())]
37 + _, ok := ps.ps[p]
38 ps.lk.RUnlock()
39 return ok
40 }
@@ -49,12 +49,12 @@ func (ps *PeerSet) Size() int {
49 // This operation can fail for one of two reasons:
50 // 1) The given peer is already in the set
51 // 2) The number of peers in the set is equal to size
52 -func (ps *PeerSet) TryAdd(p peer.Peer) bool {
52 +func (ps *PeerSet) TryAdd(p peer.ID) bool {
53 var success bool
54 ps.lk.Lock()
55 - if _, ok := ps.ps[string(p.ID())]; !ok && (len(ps.ps) < ps.size || ps.size == -1) {
55 + if _, ok := ps.ps[p]; !ok && (len(ps.ps) < ps.size || ps.size == -1) {
56 success = true
57 - ps.ps[string(p.ID())] = true
57 + ps.ps[p] = struct{}{}
58 }
59 ps.lk.Unlock()
60 return success
util/testutil/gen.go
+86 -33
@@ -1,9 +1,12 @@
1 package testutil
2
3 import (
4 + "bytes"
5 crand "crypto/rand"
6 + "errors"
7 "fmt"
6 - "math/rand"
8 + "io"
9 + "testing"
10
11 ci "github.com/jbenet/go-ipfs/crypto"
12 peer "github.com/jbenet/go-ipfs/peer"
@@ -12,44 +15,30 @@ import (
15 ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
16 )
17
15 -func RandPeer() peer.Peer {
16 - id := make([]byte, 16)
17 - crand.Read(id)
18 - mhid := u.Hash(id)
19 - return NewPeerWithID(peer.ID(mhid))
18 +func RandKeyPair(bits int) (ci.PrivKey, ci.PubKey, error) {
19 + return ci.GenerateKeyPair(ci.RSA, bits)
20 }
21
22 -func PeerWithNewKeys() (peer.Peer, error) {
23 - sk, pk, err := ci.GenerateKeyPair(ci.RSA, 512)
24 - if err != nil {
25 - return nil, err
26 - }
27 -
28 - return NewPeerWithKeyPair(sk, pk)
29 -}
30 -
31 -func PeerWithKeysAndStringAddress(addr string) (peer.Peer, error) {
32 - maddr, err := ma.NewMultiaddr(addr)
33 - if err != nil {
34 - return nil, err
22 +// RandPeerID generates random "valid" peer IDs. it does not NEED to generate
23 +// keys because it is as if we lost the key right away. fine to read randomness
24 +// and hash it. to generate proper keys and corresponding PeerID, use:
25 +// sk, pk, _ := testutil.RandKeyPair()
26 +// id, _ := peer.IDFromPublicKey(pk)
27 +func RandPeerID() (peer.ID, error) {
28 + buf := make([]byte, 16)
29 + if _, err := io.ReadFull(crand.Reader, buf); err != nil {
30 + return "", err
31 }
36 -
37 - return PeerWithKeysAndAddress(maddr)
32 + h := u.Hash(buf)
33 + return peer.ID(h), nil
34 }
35
40 -func PeerWithKeysAndAddress(maddr ma.Multiaddr) (peer.Peer, error) {
41 - sk, pk, err := ci.GenerateKeyPair(ci.RSA, 512)
42 - if err != nil {
43 - return nil, err
44 - }
45 -
46 - p, err := NewPeerWithKeyPair(sk, pk)
36 +func RandPeerIDFatal(t testing.TB) peer.ID {
37 + p, err := RandPeerID()
38 if err != nil {
48 - return nil, err
39 + t.Fatal(err)
40 }
50 -
51 - p.AddAddress(maddr)
52 - return p, nil
41 + return p
42 }
43
44 // RandLocalTCPAddress returns a random multiaddr. it suppresses errors
@@ -60,7 +49,71 @@ func RandLocalTCPAddress() ma.Multiaddr {
49 // most ports above 10000 aren't in use by long running processes, so yay.
50 // (maybe there should be a range of "loopback" ports that are guaranteed
51 // to be open for the process, but naturally can only talk to self.)
63 - addr := fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 10000+rand.Intn(50000))
52 + if lastPort == 0 {
53 + lastPort = 10000 + SeededRand.Intn(50000)
54 + }
55 + lastPort++
56 +
57 + addr := fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", lastPort)
58 maddr, _ := ma.NewMultiaddr(addr)
59 return maddr
60 }
61 +
62 +var lastPort = 0
63 +
64 +// PeerNetParams is a struct to bundle together the four things
65 +// you need to run a connection with a peer: id, 2keys, and addr.
66 +type PeerNetParams struct {
67 + ID peer.ID
68 + PrivKey ci.PrivKey
69 + PubKey ci.PubKey
70 + Addr ma.Multiaddr
71 +}
72 +
73 +func (p *PeerNetParams) checkKeys() error {
74 + if !p.ID.MatchesPrivateKey(p.PrivKey) {
75 + return errors.New("p.ID does not match p.PrivKey")
76 + }
77 +
78 + if !p.ID.MatchesPublicKey(p.PubKey) {
79 + return errors.New("p.ID does not match p.PubKey")
80 + }
81 +
82 + var buf bytes.Buffer
83 + buf.Write([]byte("hello world. this is me, I swear."))
84 + b := buf.Bytes()
85 +
86 + sig, err := p.PrivKey.Sign(b)
87 + if err != nil {
88 + return fmt.Errorf("sig signing failed: %s", err)
89 + }
90 +
91 + sigok, err := p.PubKey.Verify(b, sig)
92 + if err != nil {
93 + return fmt.Errorf("sig verify failed: %s", err)
94 + }
95 + if !sigok {
96 + return fmt.Errorf("sig verify failed: sig invalid!")
97 + }
98 +
99 + return nil // ok. move along.
100 +}
101 +
102 +func RandPeerNetParams(t *testing.T) (p PeerNetParams) {
103 + var err error
104 + p.Addr = RandLocalTCPAddress()
105 + p.PrivKey, p.PubKey, err = ci.GenerateKeyPair(ci.RSA, 512)
106 + if err != nil {
107 + t.Fatal(err)
108 + }
109 +
110 + p.ID, err = peer.IDFromPublicKey(p.PubKey)
111 + if err != nil {
112 + t.Fatal(err)
113 + }
114 +
115 + if err := p.checkKeys(); err != nil {
116 + t.Fatal(err)
117 + }
118 + return p
119 +}
util/testutil/mock.go deleted
-18
@@ -1,18 +0,0 @@
1 -package testutil
2 -
3 -import (
4 - ic "github.com/jbenet/go-ipfs/crypto"
5 - peer "github.com/jbenet/go-ipfs/peer"
6 -)
7 -
8 -func NewPeerWithKeyPair(sk ic.PrivKey, pk ic.PubKey) (peer.Peer, error) {
9 - return peer.NewPeerstore().WithKeyPair(sk, pk)
10 -}
11 -
12 -func NewPeerWithID(id peer.ID) peer.Peer {
13 - return peer.NewPeerstore().WithID(id)
14 -}
15 -
16 -func NewPeerWithIDString(id string) peer.Peer {
17 - return peer.NewPeerstore().WithIDString(id)
18 -}