mirror of
https://github.com/libp2p/go-libp2p.git
synced 2025-10-30 19:36:36 +08:00
move some deps out as gx packages
This commit is contained in:
@@ -1,69 +0,0 @@
|
||||
// Package loggables includes a bunch of transaltor functions for commonplace/stdlib
|
||||
// objects. This is boilerplate code that shouldn't change much, and not sprinkled
|
||||
// all over the place (i.e. gather it here).
|
||||
//
|
||||
// Note: it may make sense to put all stdlib Loggable functions in the eventlog
|
||||
// package. Putting it here for now in case we don't want to polute it.
|
||||
package loggables
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
// NetConn returns an eventlog.Metadata with the conn addresses
|
||||
func NetConn(c net.Conn) logging.Loggable {
|
||||
return logging.Metadata{
|
||||
"localAddr": c.LocalAddr(),
|
||||
"remoteAddr": c.RemoteAddr(),
|
||||
}
|
||||
}
|
||||
|
||||
// Error returns an eventlog.Metadata with an error
|
||||
func Error(e error) logging.Loggable {
|
||||
return logging.Metadata{
|
||||
"error": e.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
// Dial metadata is metadata for dial events
|
||||
func Dial(sys string, lid, rid peer.ID, laddr, raddr ma.Multiaddr) DeferredMap {
|
||||
m := DeferredMap{}
|
||||
m["subsystem"] = sys
|
||||
if lid != "" {
|
||||
m["localPeer"] = func() interface{} { return lid.Pretty() }
|
||||
}
|
||||
if laddr != nil {
|
||||
m["localAddr"] = func() interface{} { return laddr.String() }
|
||||
}
|
||||
if rid != "" {
|
||||
m["remotePeer"] = func() interface{} { return rid.Pretty() }
|
||||
}
|
||||
if raddr != nil {
|
||||
m["remoteAddr"] = func() interface{} { return raddr.String() }
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// DeferredMap is a Loggable which may contained deffered values.
|
||||
type DeferredMap map[string]interface{}
|
||||
|
||||
// Loggable describes objects that can be marshalled into Metadata for logging
|
||||
func (m DeferredMap) Loggable() map[string]interface{} {
|
||||
m2 := map[string]interface{}{}
|
||||
for k, v := range m {
|
||||
|
||||
if vf, ok := v.(func() interface{}); ok {
|
||||
// if it's a DeferredVal, call it.
|
||||
m2[k] = vf()
|
||||
|
||||
} else {
|
||||
// else use the value as is.
|
||||
m2[k] = v
|
||||
}
|
||||
}
|
||||
return m2
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package crypto
|
||||
|
||||
import "testing"
|
||||
|
||||
func BenchmarkSign1B(b *testing.B) { RunBenchmarkSign(b, 1) }
|
||||
func BenchmarkSign10B(b *testing.B) { RunBenchmarkSign(b, 10) }
|
||||
func BenchmarkSign100B(b *testing.B) { RunBenchmarkSign(b, 100) }
|
||||
func BenchmarkSign1000B(b *testing.B) { RunBenchmarkSign(b, 1000) }
|
||||
func BenchmarkSign10000B(b *testing.B) { RunBenchmarkSign(b, 10000) }
|
||||
func BenchmarkSign100000B(b *testing.B) { RunBenchmarkSign(b, 100000) }
|
||||
|
||||
func BenchmarkVerify1B(b *testing.B) { RunBenchmarkVerify(b, 1) }
|
||||
func BenchmarkVerify10B(b *testing.B) { RunBenchmarkVerify(b, 10) }
|
||||
func BenchmarkVerify100B(b *testing.B) { RunBenchmarkVerify(b, 100) }
|
||||
func BenchmarkVerify1000B(b *testing.B) { RunBenchmarkVerify(b, 1000) }
|
||||
func BenchmarkVerify10000B(b *testing.B) { RunBenchmarkVerify(b, 10000) }
|
||||
func BenchmarkVerify100000B(b *testing.B) { RunBenchmarkVerify(b, 100000) }
|
||||
|
||||
func RunBenchmarkSign(b *testing.B, numBytes int) {
|
||||
secret, _, err := GenerateKeyPair(RSA, 1024)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
someData := make([]byte, numBytes)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := secret.Sign(someData)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RunBenchmarkVerify(b *testing.B, numBytes int) {
|
||||
secret, public, err := GenerateKeyPair(RSA, 1024)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
someData := make([]byte, numBytes)
|
||||
signature, err := secret.Sign(someData)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
valid, err := public.Verify(someData, signature)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if !valid {
|
||||
b.Fatal("signature should be valid")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,316 +0,0 @@
|
||||
// package crypto implements various cryptographic utilities used by ipfs.
|
||||
// This includes a Public and Private key interface and an RSA key implementation
|
||||
// that satisfies it.
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"crypto/elliptic"
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"hash"
|
||||
|
||||
pb "github.com/ipfs/go-libp2p/p2p/crypto/pb"
|
||||
|
||||
proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
|
||||
u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
|
||||
logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
|
||||
)
|
||||
|
||||
var log = logging.Logger("crypto")
|
||||
|
||||
var ErrBadKeyType = errors.New("invalid or unsupported key type")
|
||||
|
||||
const (
|
||||
RSA = iota
|
||||
)
|
||||
|
||||
// Key represents a crypto key that can be compared to another key
|
||||
type Key interface {
|
||||
// Bytes returns a serialized, storeable representation of this key
|
||||
Bytes() ([]byte, error)
|
||||
|
||||
// Hash returns the hash of this key
|
||||
Hash() ([]byte, error)
|
||||
|
||||
// Equals checks whether two PubKeys are the same
|
||||
Equals(Key) bool
|
||||
}
|
||||
|
||||
// PrivKey represents a private key that can be used to generate a public key,
|
||||
// sign data, and decrypt data that was encrypted with a public key
|
||||
type PrivKey interface {
|
||||
Key
|
||||
|
||||
// Cryptographically sign the given bytes
|
||||
Sign([]byte) ([]byte, error)
|
||||
|
||||
// Return a public key paired with this private key
|
||||
GetPublic() PubKey
|
||||
|
||||
// Generate a secret string of bytes
|
||||
GenSecret() []byte
|
||||
|
||||
Decrypt(b []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
type PubKey interface {
|
||||
Key
|
||||
|
||||
// Verify that 'sig' is the signed hash of 'data'
|
||||
Verify(data []byte, sig []byte) (bool, error)
|
||||
|
||||
// Encrypt data in a way that can be decrypted by a paired private key
|
||||
Encrypt(data []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
// Given a public key, generates the shared key.
|
||||
type GenSharedKey func([]byte) ([]byte, error)
|
||||
|
||||
func GenerateKeyPair(typ, bits int) (PrivKey, PubKey, error) {
|
||||
return GenerateKeyPairWithReader(typ, bits, rand.Reader)
|
||||
}
|
||||
|
||||
// Generates a keypair of the given type and bitsize
|
||||
func GenerateKeyPairWithReader(typ, bits int, src io.Reader) (PrivKey, PubKey, error) {
|
||||
switch typ {
|
||||
case RSA:
|
||||
priv, err := rsa.GenerateKey(src, bits)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pk := &priv.PublicKey
|
||||
return &RsaPrivateKey{sk: priv}, &RsaPublicKey{pk}, nil
|
||||
default:
|
||||
return nil, nil, ErrBadKeyType
|
||||
}
|
||||
}
|
||||
|
||||
// Generates an ephemeral public key and returns a function that will compute
|
||||
// the shared secret key. Used in the identify module.
|
||||
//
|
||||
// Focuses only on ECDH now, but can be made more general in the future.
|
||||
func GenerateEKeyPair(curveName string) ([]byte, GenSharedKey, error) {
|
||||
var curve elliptic.Curve
|
||||
|
||||
switch curveName {
|
||||
case "P-256":
|
||||
curve = elliptic.P256()
|
||||
case "P-384":
|
||||
curve = elliptic.P384()
|
||||
case "P-521":
|
||||
curve = elliptic.P521()
|
||||
}
|
||||
|
||||
priv, x, y, err := elliptic.GenerateKey(curve, rand.Reader)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
pubKey := elliptic.Marshal(curve, x, y)
|
||||
// log.Debug("GenerateEKeyPair %d", len(pubKey))
|
||||
|
||||
done := func(theirPub []byte) ([]byte, error) {
|
||||
// Verify and unpack node's public key.
|
||||
x, y := elliptic.Unmarshal(curve, theirPub)
|
||||
if x == nil {
|
||||
return nil, fmt.Errorf("Malformed public key: %d %v", len(theirPub), theirPub)
|
||||
}
|
||||
|
||||
if !curve.IsOnCurve(x, y) {
|
||||
return nil, errors.New("Invalid public key.")
|
||||
}
|
||||
|
||||
// Generate shared secret.
|
||||
secret, _ := curve.ScalarMult(x, y, priv)
|
||||
|
||||
return secret.Bytes(), nil
|
||||
}
|
||||
|
||||
return pubKey, done, nil
|
||||
}
|
||||
|
||||
type StretchedKeys struct {
|
||||
IV []byte
|
||||
MacKey []byte
|
||||
CipherKey []byte
|
||||
}
|
||||
|
||||
// Generates a set of keys for each party by stretching the shared key.
|
||||
// (myIV, theirIV, myCipherKey, theirCipherKey, myMACKey, theirMACKey)
|
||||
func KeyStretcher(cipherType string, hashType string, secret []byte) (StretchedKeys, StretchedKeys) {
|
||||
var cipherKeySize int
|
||||
var ivSize int
|
||||
switch cipherType {
|
||||
case "AES-128":
|
||||
ivSize = 16
|
||||
cipherKeySize = 16
|
||||
case "AES-256":
|
||||
ivSize = 16
|
||||
cipherKeySize = 32
|
||||
case "Blowfish":
|
||||
ivSize = 8
|
||||
// Note: 24 arbitrarily selected, needs more thought
|
||||
cipherKeySize = 32
|
||||
}
|
||||
|
||||
hmacKeySize := 20
|
||||
|
||||
seed := []byte("key expansion")
|
||||
|
||||
result := make([]byte, 2*(ivSize+cipherKeySize+hmacKeySize))
|
||||
|
||||
var h func() hash.Hash
|
||||
|
||||
switch hashType {
|
||||
case "SHA1":
|
||||
h = sha1.New
|
||||
case "SHA256":
|
||||
h = sha256.New
|
||||
case "SHA512":
|
||||
h = sha512.New
|
||||
default:
|
||||
panic("Unrecognized hash function, programmer error?")
|
||||
}
|
||||
|
||||
m := hmac.New(h, secret)
|
||||
m.Write(seed)
|
||||
|
||||
a := m.Sum(nil)
|
||||
|
||||
j := 0
|
||||
for j < len(result) {
|
||||
m.Reset()
|
||||
m.Write(a)
|
||||
m.Write(seed)
|
||||
b := m.Sum(nil)
|
||||
|
||||
todo := len(b)
|
||||
|
||||
if j+todo > len(result) {
|
||||
todo = len(result) - j
|
||||
}
|
||||
|
||||
copy(result[j:j+todo], b)
|
||||
|
||||
j += todo
|
||||
|
||||
m.Reset()
|
||||
m.Write(a)
|
||||
a = m.Sum(nil)
|
||||
}
|
||||
|
||||
half := len(result) / 2
|
||||
r1 := result[:half]
|
||||
r2 := result[half:]
|
||||
|
||||
var k1 StretchedKeys
|
||||
var k2 StretchedKeys
|
||||
|
||||
k1.IV = r1[0:ivSize]
|
||||
k1.CipherKey = r1[ivSize : ivSize+cipherKeySize]
|
||||
k1.MacKey = r1[ivSize+cipherKeySize:]
|
||||
|
||||
k2.IV = r2[0:ivSize]
|
||||
k2.CipherKey = r2[ivSize : ivSize+cipherKeySize]
|
||||
k2.MacKey = r2[ivSize+cipherKeySize:]
|
||||
|
||||
return k1, k2
|
||||
}
|
||||
|
||||
// UnmarshalPublicKey converts a protobuf serialized public key into its
|
||||
// representative object
|
||||
func UnmarshalPublicKey(data []byte) (PubKey, error) {
|
||||
pmes := new(pb.PublicKey)
|
||||
err := proto.Unmarshal(data, pmes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch pmes.GetType() {
|
||||
case pb.KeyType_RSA:
|
||||
return UnmarshalRsaPublicKey(pmes.GetData())
|
||||
default:
|
||||
return nil, ErrBadKeyType
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalPublicKey converts a public key object into a protobuf serialized
|
||||
// public key
|
||||
func MarshalPublicKey(k PubKey) ([]byte, error) {
|
||||
b, err := MarshalRsaPublicKey(k.(*RsaPublicKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pmes := new(pb.PublicKey)
|
||||
typ := pb.KeyType_RSA // for now only type.
|
||||
pmes.Type = &typ
|
||||
pmes.Data = b
|
||||
return proto.Marshal(pmes)
|
||||
}
|
||||
|
||||
// UnmarshalPrivateKey converts a protobuf serialized private key into its
|
||||
// representative object
|
||||
func UnmarshalPrivateKey(data []byte) (PrivKey, error) {
|
||||
pmes := new(pb.PrivateKey)
|
||||
err := proto.Unmarshal(data, pmes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch pmes.GetType() {
|
||||
case pb.KeyType_RSA:
|
||||
return UnmarshalRsaPrivateKey(pmes.GetData())
|
||||
default:
|
||||
return nil, ErrBadKeyType
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalPrivateKey converts a key object into its protobuf serialized form.
|
||||
func MarshalPrivateKey(k PrivKey) ([]byte, error) {
|
||||
b := MarshalRsaPrivateKey(k.(*RsaPrivateKey))
|
||||
pmes := new(pb.PrivateKey)
|
||||
typ := pb.KeyType_RSA // for now only type.
|
||||
pmes.Type = &typ
|
||||
pmes.Data = b
|
||||
return proto.Marshal(pmes)
|
||||
}
|
||||
|
||||
// ConfigDecodeKey decodes from b64 (for config file), and unmarshals.
|
||||
func ConfigDecodeKey(b string) ([]byte, error) {
|
||||
return base64.StdEncoding.DecodeString(b)
|
||||
}
|
||||
|
||||
// ConfigEncodeKey encodes to b64 (for config file), and marshals.
|
||||
func ConfigEncodeKey(b []byte) string {
|
||||
return base64.StdEncoding.EncodeToString(b)
|
||||
}
|
||||
|
||||
// KeyEqual checks whether two
|
||||
func KeyEqual(k1, k2 Key) bool {
|
||||
if k1 == k2 {
|
||||
return true
|
||||
}
|
||||
|
||||
b1, err1 := k1.Bytes()
|
||||
b2, err2 := k2.Bytes()
|
||||
return bytes.Equal(b1, b2) && err1 == err2
|
||||
}
|
||||
|
||||
// KeyHash hashes a key.
|
||||
func KeyHash(k Key) ([]byte, error) {
|
||||
kb, err := k.Bytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return u.Hash(kb), nil
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
package crypto_test
|
||||
|
||||
import (
|
||||
. "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
|
||||
"bytes"
|
||||
tu "github.com/ipfs/go-libp2p/testutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRsaKeys(t *testing.T) {
|
||||
sk, pk, err := tu.RandTestKeyPair(512)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testKeySignature(t, sk)
|
||||
testKeyEncoding(t, sk)
|
||||
testKeyEquals(t, sk)
|
||||
testKeyEquals(t, pk)
|
||||
}
|
||||
|
||||
func testKeySignature(t *testing.T, sk PrivKey) {
|
||||
pk := sk.GetPublic()
|
||||
|
||||
text := sk.GenSecret()
|
||||
sig, err := sk.Sign(text)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
valid, err := pk.Verify(text, sig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !valid {
|
||||
t.Fatal("Invalid signature.")
|
||||
}
|
||||
}
|
||||
|
||||
func testKeyEncoding(t *testing.T, sk PrivKey) {
|
||||
skbm, err := MarshalPrivateKey(sk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sk2, err := UnmarshalPrivateKey(skbm)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
skbm2, err := MarshalPrivateKey(sk2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(skbm, skbm2) {
|
||||
t.Error("skb -> marshal -> unmarshal -> skb failed.\n", skbm, "\n", skbm2)
|
||||
}
|
||||
|
||||
pk := sk.GetPublic()
|
||||
pkbm, err := MarshalPublicKey(pk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = UnmarshalPublicKey(pkbm)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pkbm2, err := MarshalPublicKey(pk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(pkbm, pkbm2) {
|
||||
t.Error("skb -> marshal -> unmarshal -> skb failed.\n", pkbm, "\n", pkbm2)
|
||||
}
|
||||
}
|
||||
|
||||
func testKeyEquals(t *testing.T, k Key) {
|
||||
kb, err := k.Bytes()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !KeyEqual(k, k) {
|
||||
t.Fatal("Key not equal to itself.")
|
||||
}
|
||||
|
||||
if !KeyEqual(k, testkey(kb)) {
|
||||
t.Fatal("Key not equal to key with same bytes.")
|
||||
}
|
||||
|
||||
sk, pk, err := tu.RandTestKeyPair(512)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if KeyEqual(k, sk) {
|
||||
t.Fatal("Keys should not equal.")
|
||||
}
|
||||
|
||||
if KeyEqual(k, pk) {
|
||||
t.Fatal("Keys should not equal.")
|
||||
}
|
||||
}
|
||||
|
||||
type testkey []byte
|
||||
|
||||
func (pk testkey) Bytes() ([]byte, error) {
|
||||
return pk, nil
|
||||
}
|
||||
|
||||
func (pk testkey) Equals(k Key) bool {
|
||||
return KeyEqual(pk, k)
|
||||
}
|
||||
|
||||
func (pk testkey) Hash() ([]byte, error) {
|
||||
return KeyHash(pk)
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
PB = $(wildcard *.proto)
|
||||
GO = $(PB:.proto=.pb.go)
|
||||
|
||||
all: $(GO)
|
||||
|
||||
%.pb.go: %.proto
|
||||
protoc --gogo_out=. $<
|
||||
|
||||
clean:
|
||||
rm *.pb.go
|
||||
@@ -1,104 +0,0 @@
|
||||
// Code generated by protoc-gen-gogo.
|
||||
// source: crypto.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package crypto_pb is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
crypto.proto
|
||||
|
||||
It has these top-level messages:
|
||||
PublicKey
|
||||
PrivateKey
|
||||
*/
|
||||
package crypto_pb
|
||||
|
||||
import proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
|
||||
import math "math"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = math.Inf
|
||||
|
||||
type KeyType int32
|
||||
|
||||
const (
|
||||
KeyType_RSA KeyType = 0
|
||||
)
|
||||
|
||||
var KeyType_name = map[int32]string{
|
||||
0: "RSA",
|
||||
}
|
||||
var KeyType_value = map[string]int32{
|
||||
"RSA": 0,
|
||||
}
|
||||
|
||||
func (x KeyType) Enum() *KeyType {
|
||||
p := new(KeyType)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
func (x KeyType) String() string {
|
||||
return proto.EnumName(KeyType_name, int32(x))
|
||||
}
|
||||
func (x *KeyType) UnmarshalJSON(data []byte) error {
|
||||
value, err := proto.UnmarshalJSONEnum(KeyType_value, data, "KeyType")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*x = KeyType(value)
|
||||
return nil
|
||||
}
|
||||
|
||||
type PublicKey struct {
|
||||
Type *KeyType `protobuf:"varint,1,req,enum=crypto.pb.KeyType" json:"Type,omitempty"`
|
||||
Data []byte `protobuf:"bytes,2,req" json:"Data,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *PublicKey) Reset() { *m = PublicKey{} }
|
||||
func (m *PublicKey) String() string { return proto.CompactTextString(m) }
|
||||
func (*PublicKey) ProtoMessage() {}
|
||||
|
||||
func (m *PublicKey) GetType() KeyType {
|
||||
if m != nil && m.Type != nil {
|
||||
return *m.Type
|
||||
}
|
||||
return KeyType_RSA
|
||||
}
|
||||
|
||||
func (m *PublicKey) GetData() []byte {
|
||||
if m != nil {
|
||||
return m.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PrivateKey struct {
|
||||
Type *KeyType `protobuf:"varint,1,req,enum=crypto.pb.KeyType" json:"Type,omitempty"`
|
||||
Data []byte `protobuf:"bytes,2,req" json:"Data,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *PrivateKey) Reset() { *m = PrivateKey{} }
|
||||
func (m *PrivateKey) String() string { return proto.CompactTextString(m) }
|
||||
func (*PrivateKey) ProtoMessage() {}
|
||||
|
||||
func (m *PrivateKey) GetType() KeyType {
|
||||
if m != nil && m.Type != nil {
|
||||
return *m.Type
|
||||
}
|
||||
return KeyType_RSA
|
||||
}
|
||||
|
||||
func (m *PrivateKey) GetData() []byte {
|
||||
if m != nil {
|
||||
return m.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterEnum("crypto.pb.KeyType", KeyType_name, KeyType_value)
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package crypto.pb;
|
||||
|
||||
enum KeyType {
|
||||
RSA = 0;
|
||||
}
|
||||
|
||||
message PublicKey {
|
||||
required KeyType Type = 1;
|
||||
required bytes Data = 2;
|
||||
}
|
||||
|
||||
message PrivateKey {
|
||||
required KeyType Type = 1;
|
||||
required bytes Data = 2;
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
|
||||
pb "github.com/ipfs/go-libp2p/p2p/crypto/pb"
|
||||
proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
|
||||
)
|
||||
|
||||
type RsaPrivateKey struct {
|
||||
sk *rsa.PrivateKey
|
||||
pk *rsa.PublicKey
|
||||
}
|
||||
|
||||
type RsaPublicKey struct {
|
||||
k *rsa.PublicKey
|
||||
}
|
||||
|
||||
func (pk *RsaPublicKey) Verify(data, sig []byte) (bool, error) {
|
||||
hashed := sha256.Sum256(data)
|
||||
err := rsa.VerifyPKCS1v15(pk.k, crypto.SHA256, hashed[:], sig)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (pk *RsaPublicKey) Bytes() ([]byte, error) {
|
||||
b, err := x509.MarshalPKIXPublicKey(pk.k)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pbmes := new(pb.PublicKey)
|
||||
typ := pb.KeyType_RSA
|
||||
pbmes.Type = &typ
|
||||
pbmes.Data = b
|
||||
return proto.Marshal(pbmes)
|
||||
}
|
||||
|
||||
func (pk *RsaPublicKey) Encrypt(b []byte) ([]byte, error) {
|
||||
return rsa.EncryptPKCS1v15(rand.Reader, pk.k, b)
|
||||
}
|
||||
|
||||
// Equals checks whether this key is equal to another
|
||||
func (pk *RsaPublicKey) Equals(k Key) bool {
|
||||
return KeyEqual(pk, k)
|
||||
}
|
||||
|
||||
func (pk *RsaPublicKey) Hash() ([]byte, error) {
|
||||
return KeyHash(pk)
|
||||
}
|
||||
|
||||
func (sk *RsaPrivateKey) GenSecret() []byte {
|
||||
buf := make([]byte, 16)
|
||||
rand.Read(buf)
|
||||
return buf
|
||||
}
|
||||
|
||||
func (sk *RsaPrivateKey) Sign(message []byte) ([]byte, error) {
|
||||
hashed := sha256.Sum256(message)
|
||||
return rsa.SignPKCS1v15(rand.Reader, sk.sk, crypto.SHA256, hashed[:])
|
||||
}
|
||||
|
||||
func (sk *RsaPrivateKey) GetPublic() PubKey {
|
||||
if sk.pk == nil {
|
||||
sk.pk = &sk.sk.PublicKey
|
||||
}
|
||||
return &RsaPublicKey{sk.pk}
|
||||
}
|
||||
|
||||
func (sk *RsaPrivateKey) Decrypt(b []byte) ([]byte, error) {
|
||||
return rsa.DecryptPKCS1v15(rand.Reader, sk.sk, b)
|
||||
}
|
||||
|
||||
func (sk *RsaPrivateKey) Bytes() ([]byte, error) {
|
||||
b := x509.MarshalPKCS1PrivateKey(sk.sk)
|
||||
pbmes := new(pb.PrivateKey)
|
||||
typ := pb.KeyType_RSA
|
||||
pbmes.Type = &typ
|
||||
pbmes.Data = b
|
||||
return proto.Marshal(pbmes)
|
||||
}
|
||||
|
||||
// Equals checks whether this key is equal to another
|
||||
func (sk *RsaPrivateKey) Equals(k Key) bool {
|
||||
return KeyEqual(sk, k)
|
||||
}
|
||||
|
||||
func (sk *RsaPrivateKey) Hash() ([]byte, error) {
|
||||
return KeyHash(sk)
|
||||
}
|
||||
|
||||
func UnmarshalRsaPrivateKey(b []byte) (*RsaPrivateKey, error) {
|
||||
sk, err := x509.ParsePKCS1PrivateKey(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &RsaPrivateKey{sk: sk}, nil
|
||||
}
|
||||
|
||||
func MarshalRsaPrivateKey(k *RsaPrivateKey) []byte {
|
||||
return x509.MarshalPKCS1PrivateKey(k.sk)
|
||||
}
|
||||
|
||||
func UnmarshalRsaPublicKey(b []byte) (*RsaPublicKey, error) {
|
||||
pub, err := x509.ParsePKIXPublicKey(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pk, ok := pub.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return nil, errors.New("Not actually an rsa public key.")
|
||||
}
|
||||
return &RsaPublicKey{pk}, nil
|
||||
}
|
||||
|
||||
func MarshalRsaPublicKey(k *RsaPublicKey) ([]byte, error) {
|
||||
return x509.MarshalPKIXPublicKey(k.k)
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
package secio
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/hmac"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"hash"
|
||||
|
||||
ci "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
bfish "gx/ipfs/Qme1boxspcQWR8FBzMxeppqug2fYgYc15diNWmqgDVnvn2/go-crypto/blowfish"
|
||||
)
|
||||
|
||||
// List of supported ECDH curves
|
||||
var SupportedExchanges = "P-256,P-384,P-521"
|
||||
|
||||
// List of supported Ciphers
|
||||
var SupportedCiphers = "AES-256,AES-128,Blowfish"
|
||||
|
||||
// List of supported Hashes
|
||||
var SupportedHashes = "SHA256,SHA512"
|
||||
|
||||
type HMAC struct {
|
||||
hash.Hash
|
||||
size int
|
||||
}
|
||||
|
||||
// encParams represent encryption parameters
|
||||
type encParams struct {
|
||||
// keys
|
||||
permanentPubKey ci.PubKey
|
||||
ephemeralPubKey []byte
|
||||
keys ci.StretchedKeys
|
||||
|
||||
// selections
|
||||
curveT string
|
||||
cipherT string
|
||||
hashT string
|
||||
|
||||
// cipher + mac
|
||||
cipher cipher.Stream
|
||||
mac HMAC
|
||||
}
|
||||
|
||||
func (e *encParams) makeMacAndCipher() error {
|
||||
m, err := newMac(e.hashT, e.keys.MacKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bc, err := newBlockCipher(e.cipherT, e.keys.CipherKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
e.cipher = cipher.NewCTR(bc, e.keys.IV)
|
||||
e.mac = m
|
||||
return nil
|
||||
}
|
||||
|
||||
func newMac(hashType string, key []byte) (HMAC, error) {
|
||||
switch hashType {
|
||||
case "SHA1":
|
||||
return HMAC{hmac.New(sha1.New, key), sha1.Size}, nil
|
||||
case "SHA512":
|
||||
return HMAC{hmac.New(sha512.New, key), sha512.Size}, nil
|
||||
case "SHA256":
|
||||
return HMAC{hmac.New(sha256.New, key), sha256.Size}, nil
|
||||
default:
|
||||
return HMAC{}, fmt.Errorf("Unrecognized hash type: %s", hashType)
|
||||
}
|
||||
}
|
||||
|
||||
func newBlockCipher(cipherT string, key []byte) (cipher.Block, error) {
|
||||
switch cipherT {
|
||||
case "AES-128", "AES-256":
|
||||
return aes.NewCipher(key)
|
||||
case "Blowfish":
|
||||
return bfish.NewCipher(key)
|
||||
default:
|
||||
return nil, fmt.Errorf("Unrecognized cipher type: %s", cipherT)
|
||||
}
|
||||
}
|
||||
|
||||
// Determines which algorithm to use. Note: f(a, b) = f(b, a)
|
||||
func selectBest(order int, p1, p2 string) (string, error) {
|
||||
var f, s []string
|
||||
switch {
|
||||
case order < 0:
|
||||
f = strings.Split(p2, ",")
|
||||
s = strings.Split(p1, ",")
|
||||
case order > 0:
|
||||
f = strings.Split(p1, ",")
|
||||
s = strings.Split(p2, ",")
|
||||
default: // Exact same preferences.
|
||||
p := strings.Split(p1, ",")
|
||||
return p[0], nil
|
||||
}
|
||||
|
||||
for _, fc := range f {
|
||||
for _, sc := range s {
|
||||
if fc == sc {
|
||||
return fc, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.New("No algorithms in common!")
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
// package secio handles establishing secure communication between two peers.
|
||||
package secio
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
ci "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
msgio "gx/ipfs/QmRQhVisS8dmPbjBUthVkenn81pBxrx1GxE281csJhm2vL/go-msgio"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
)
|
||||
|
||||
// SessionGenerator constructs secure communication sessions for a peer.
|
||||
type SessionGenerator struct {
|
||||
LocalID peer.ID
|
||||
PrivateKey ci.PrivKey
|
||||
}
|
||||
|
||||
// NewSession takes an insecure io.ReadWriter, sets up a TLS-like
|
||||
// handshake with the other side, and returns a secure session.
|
||||
// The handshake isn't run until the connection is read or written to.
|
||||
// See the source for the protocol details and security implementation.
|
||||
// The provided Context is only needed for the duration of this function.
|
||||
func (sg *SessionGenerator) NewSession(ctx context.Context, insecure io.ReadWriteCloser) (Session, error) {
|
||||
return newSecureSession(ctx, sg.LocalID, sg.PrivateKey, insecure)
|
||||
}
|
||||
|
||||
type Session interface {
|
||||
// ReadWriter returns the encrypted communication channel
|
||||
ReadWriter() msgio.ReadWriteCloser
|
||||
|
||||
// LocalPeer retrieves the local peer.
|
||||
LocalPeer() peer.ID
|
||||
|
||||
// LocalPrivateKey retrieves the local private key
|
||||
LocalPrivateKey() ci.PrivKey
|
||||
|
||||
// RemotePeer retrieves the remote peer.
|
||||
RemotePeer() peer.ID
|
||||
|
||||
// RemotePublicKey retrieves the remote's public key
|
||||
// which was received during the handshake.
|
||||
RemotePublicKey() ci.PubKey
|
||||
|
||||
// Close closes the secure session
|
||||
Close() error
|
||||
}
|
||||
|
||||
// SecureReadWriter returns the encrypted communication channel
|
||||
func (s *secureSession) ReadWriter() msgio.ReadWriteCloser {
|
||||
if err := s.Handshake(); err != nil {
|
||||
return &closedRW{err}
|
||||
}
|
||||
return s.secure
|
||||
}
|
||||
|
||||
// LocalPeer retrieves the local peer.
|
||||
func (s *secureSession) LocalPeer() peer.ID {
|
||||
return s.localPeer
|
||||
}
|
||||
|
||||
// LocalPrivateKey retrieves the local peer's PrivateKey
|
||||
func (s *secureSession) LocalPrivateKey() ci.PrivKey {
|
||||
return s.localKey
|
||||
}
|
||||
|
||||
// RemotePeer retrieves the remote peer.
|
||||
func (s *secureSession) RemotePeer() peer.ID {
|
||||
if err := s.Handshake(); err != nil {
|
||||
return ""
|
||||
}
|
||||
return s.remotePeer
|
||||
}
|
||||
|
||||
// RemotePeer retrieves the remote peer.
|
||||
func (s *secureSession) RemotePublicKey() ci.PubKey {
|
||||
if err := s.Handshake(); err != nil {
|
||||
return nil
|
||||
}
|
||||
return s.remote.permanentPubKey
|
||||
}
|
||||
|
||||
// Close closes the secure session
|
||||
func (s *secureSession) Close() error {
|
||||
s.cancel()
|
||||
s.handshakeMu.Lock()
|
||||
defer s.handshakeMu.Unlock()
|
||||
if s.secure == nil {
|
||||
return s.insecure.Close() // hadn't secured yet.
|
||||
}
|
||||
return s.secure.Close()
|
||||
}
|
||||
|
||||
// closedRW implements a stub msgio interface that's already
|
||||
// closed and errored.
|
||||
type closedRW struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (c *closedRW) Read(buf []byte) (int, error) {
|
||||
return 0, c.err
|
||||
}
|
||||
|
||||
func (c *closedRW) Write(buf []byte) (int, error) {
|
||||
return 0, c.err
|
||||
}
|
||||
|
||||
func (c *closedRW) NextMsgLen() (int, error) {
|
||||
return 0, c.err
|
||||
}
|
||||
|
||||
func (c *closedRW) ReadMsg() ([]byte, error) {
|
||||
return nil, c.err
|
||||
}
|
||||
|
||||
func (c *closedRW) WriteMsg(buf []byte) error {
|
||||
return c.err
|
||||
}
|
||||
|
||||
func (c *closedRW) Close() error {
|
||||
return c.err
|
||||
}
|
||||
|
||||
func (c *closedRW) ReleaseMsg(m []byte) {
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package secio
|
||||
@@ -1,10 +0,0 @@
|
||||
PB = $(wildcard *.proto)
|
||||
GO = $(PB:.proto=.pb.go)
|
||||
|
||||
all: $(GO)
|
||||
|
||||
%.pb.go: %.proto
|
||||
protoc --gogo_out=. --proto_path=../../../../../../:/usr/local/opt/protobuf/include:. $<
|
||||
|
||||
clean:
|
||||
rm *.pb.go
|
||||
@@ -1,97 +0,0 @@
|
||||
// Code generated by protoc-gen-gogo.
|
||||
// source: spipe.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package spipe_pb is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
spipe.proto
|
||||
|
||||
It has these top-level messages:
|
||||
Propose
|
||||
Exchange
|
||||
*/
|
||||
package spipe_pb
|
||||
|
||||
import proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
|
||||
import math "math"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = math.Inf
|
||||
|
||||
type Propose struct {
|
||||
Rand []byte `protobuf:"bytes,1,opt,name=rand" json:"rand,omitempty"`
|
||||
Pubkey []byte `protobuf:"bytes,2,opt,name=pubkey" json:"pubkey,omitempty"`
|
||||
Exchanges *string `protobuf:"bytes,3,opt,name=exchanges" json:"exchanges,omitempty"`
|
||||
Ciphers *string `protobuf:"bytes,4,opt,name=ciphers" json:"ciphers,omitempty"`
|
||||
Hashes *string `protobuf:"bytes,5,opt,name=hashes" json:"hashes,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Propose) Reset() { *m = Propose{} }
|
||||
func (m *Propose) String() string { return proto.CompactTextString(m) }
|
||||
func (*Propose) ProtoMessage() {}
|
||||
|
||||
func (m *Propose) GetRand() []byte {
|
||||
if m != nil {
|
||||
return m.Rand
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Propose) GetPubkey() []byte {
|
||||
if m != nil {
|
||||
return m.Pubkey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Propose) GetExchanges() string {
|
||||
if m != nil && m.Exchanges != nil {
|
||||
return *m.Exchanges
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Propose) GetCiphers() string {
|
||||
if m != nil && m.Ciphers != nil {
|
||||
return *m.Ciphers
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Propose) GetHashes() string {
|
||||
if m != nil && m.Hashes != nil {
|
||||
return *m.Hashes
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Exchange struct {
|
||||
Epubkey []byte `protobuf:"bytes,1,opt,name=epubkey" json:"epubkey,omitempty"`
|
||||
Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Exchange) Reset() { *m = Exchange{} }
|
||||
func (m *Exchange) String() string { return proto.CompactTextString(m) }
|
||||
func (*Exchange) ProtoMessage() {}
|
||||
|
||||
func (m *Exchange) GetEpubkey() []byte {
|
||||
if m != nil {
|
||||
return m.Epubkey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Exchange) GetSignature() []byte {
|
||||
if m != nil {
|
||||
return m.Signature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package spipe.pb;
|
||||
|
||||
message Propose {
|
||||
optional bytes rand = 1;
|
||||
optional bytes pubkey = 2;
|
||||
optional string exchanges = 3;
|
||||
optional string ciphers = 4;
|
||||
optional string hashes = 5;
|
||||
}
|
||||
|
||||
message Exchange {
|
||||
optional bytes epubkey = 1;
|
||||
optional bytes signature = 2;
|
||||
}
|
||||
@@ -1,341 +0,0 @@
|
||||
package secio
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
ci "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
pb "github.com/ipfs/go-libp2p/p2p/crypto/secio/pb"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
msgio "gx/ipfs/QmRQhVisS8dmPbjBUthVkenn81pBxrx1GxE281csJhm2vL/go-msgio"
|
||||
u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
|
||||
)
|
||||
|
||||
var log = logging.Logger("secio")
|
||||
|
||||
// ErrUnsupportedKeyType is returned when a private key cast/type switch fails.
|
||||
var ErrUnsupportedKeyType = errors.New("unsupported key type")
|
||||
|
||||
// ErrClosed signals the closing of a connection.
|
||||
var ErrClosed = errors.New("connection closed")
|
||||
|
||||
// ErrEcho is returned when we're attempting to handshake with the same keys and nonces.
|
||||
var ErrEcho = errors.New("same keys and nonces. one side talking to self.")
|
||||
|
||||
// HandshakeTimeout governs how long the handshake will be allowed to take place for.
|
||||
// Making this number large means there could be many bogus connections waiting to
|
||||
// timeout in flight. Typical handshakes take ~3RTTs, so it should be completed within
|
||||
// seconds across a typical planet in the solar system.
|
||||
var HandshakeTimeout = time.Second * 30
|
||||
|
||||
// nonceSize is the size of our nonces (in bytes)
|
||||
const nonceSize = 16
|
||||
|
||||
// secureSession encapsulates all the parameters needed for encrypting
|
||||
// and decrypting traffic from an insecure channel.
|
||||
type secureSession struct {
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
|
||||
secure msgio.ReadWriteCloser
|
||||
insecure io.ReadWriteCloser
|
||||
insecureM msgio.ReadWriter
|
||||
|
||||
localKey ci.PrivKey
|
||||
localPeer peer.ID
|
||||
remotePeer peer.ID
|
||||
|
||||
local encParams
|
||||
remote encParams
|
||||
|
||||
sharedSecret []byte
|
||||
|
||||
handshakeMu sync.Mutex // guards handshakeDone + handshakeErr
|
||||
handshakeDone bool
|
||||
handshakeErr error
|
||||
}
|
||||
|
||||
func (s *secureSession) Loggable() map[string]interface{} {
|
||||
m := make(map[string]interface{})
|
||||
m["localPeer"] = s.localPeer.Pretty()
|
||||
m["remotePeer"] = s.remotePeer.Pretty()
|
||||
m["established"] = (s.secure != nil)
|
||||
return m
|
||||
}
|
||||
|
||||
func newSecureSession(ctx context.Context, local peer.ID, key ci.PrivKey, insecure io.ReadWriteCloser) (*secureSession, error) {
|
||||
s := &secureSession{localPeer: local, localKey: key}
|
||||
s.ctx, s.cancel = context.WithCancel(ctx)
|
||||
|
||||
switch {
|
||||
case s.localPeer == "":
|
||||
return nil, errors.New("no local id provided")
|
||||
case s.localKey == nil:
|
||||
return nil, errors.New("no local private key provided")
|
||||
case !s.localPeer.MatchesPrivateKey(s.localKey):
|
||||
return nil, fmt.Errorf("peer.ID does not match PrivateKey")
|
||||
case insecure == nil:
|
||||
return nil, fmt.Errorf("insecure ReadWriter is nil")
|
||||
}
|
||||
|
||||
s.ctx = ctx
|
||||
s.insecure = insecure
|
||||
s.insecureM = msgio.NewReadWriter(insecure)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *secureSession) Handshake() error {
|
||||
s.handshakeMu.Lock()
|
||||
defer s.handshakeMu.Unlock()
|
||||
|
||||
if s.handshakeErr != nil {
|
||||
return s.handshakeErr
|
||||
}
|
||||
|
||||
if !s.handshakeDone {
|
||||
s.handshakeErr = s.runHandshake()
|
||||
s.handshakeDone = true
|
||||
}
|
||||
return s.handshakeErr
|
||||
}
|
||||
|
||||
// runHandshake performs initial communication over insecure channel to share
|
||||
// keys, IDs, and initiate communication, assigning all necessary params.
|
||||
// requires the duplex channel to be a msgio.ReadWriter (for framed messaging)
|
||||
func (s *secureSession) runHandshake() error {
|
||||
ctx, cancel := context.WithTimeout(s.ctx, HandshakeTimeout) // remove
|
||||
defer cancel()
|
||||
|
||||
// =============================================================================
|
||||
// step 1. Propose -- propose cipher suite + send pubkeys + nonce
|
||||
|
||||
// Generate and send Hello packet.
|
||||
// Hello = (rand, PublicKey, Supported)
|
||||
nonceOut := make([]byte, nonceSize)
|
||||
_, err := rand.Read(nonceOut)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer log.EventBegin(ctx, "secureHandshake", s).Done()
|
||||
|
||||
s.local.permanentPubKey = s.localKey.GetPublic()
|
||||
myPubKeyBytes, err := s.local.permanentPubKey.Bytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proposeOut := new(pb.Propose)
|
||||
proposeOut.Rand = nonceOut
|
||||
proposeOut.Pubkey = myPubKeyBytes
|
||||
proposeOut.Exchanges = &SupportedExchanges
|
||||
proposeOut.Ciphers = &SupportedCiphers
|
||||
proposeOut.Hashes = &SupportedHashes
|
||||
|
||||
// log.Debugf("1.0 Propose: nonce:%s exchanges:%s ciphers:%s hashes:%s",
|
||||
// nonceOut, SupportedExchanges, SupportedCiphers, SupportedHashes)
|
||||
|
||||
// Send Propose packet (respects ctx)
|
||||
proposeOutBytes, err := writeMsgCtx(ctx, s.insecureM, proposeOut)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Receive + Parse their Propose packet and generate an Exchange packet.
|
||||
proposeIn := new(pb.Propose)
|
||||
proposeInBytes, err := readMsgCtx(ctx, s.insecureM, proposeIn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// log.Debugf("1.0.1 Propose recv: nonce:%s exchanges:%s ciphers:%s hashes:%s",
|
||||
// proposeIn.GetRand(), proposeIn.GetExchanges(), proposeIn.GetCiphers(), proposeIn.GetHashes())
|
||||
|
||||
// =============================================================================
|
||||
// step 1.1 Identify -- get identity from their key
|
||||
|
||||
// get remote identity
|
||||
s.remote.permanentPubKey, err = ci.UnmarshalPublicKey(proposeIn.GetPubkey())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get peer id
|
||||
s.remotePeer, err = peer.IDFromPublicKey(s.remote.permanentPubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debugf("1.1 Identify: %s Remote Peer Identified as %s", s.localPeer, s.remotePeer)
|
||||
|
||||
// =============================================================================
|
||||
// step 1.2 Selection -- select/agree on best encryption parameters
|
||||
|
||||
// to determine order, use cmp(H(remote_pubkey||local_rand), H(local_pubkey||remote_rand)).
|
||||
oh1 := u.Hash(append(proposeIn.GetPubkey(), nonceOut...))
|
||||
oh2 := u.Hash(append(myPubKeyBytes, proposeIn.GetRand()...))
|
||||
order := bytes.Compare(oh1, oh2)
|
||||
if order == 0 {
|
||||
return ErrEcho // talking to self (same socket. must be reuseport + dialing self)
|
||||
}
|
||||
|
||||
s.local.curveT, err = selectBest(order, SupportedExchanges, proposeIn.GetExchanges())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.local.cipherT, err = selectBest(order, SupportedCiphers, proposeIn.GetCiphers())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.local.hashT, err = selectBest(order, SupportedHashes, proposeIn.GetHashes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// we use the same params for both directions (must choose same curve)
|
||||
// WARNING: if they dont SelectBest the same way, this won't work...
|
||||
s.remote.curveT = s.local.curveT
|
||||
s.remote.cipherT = s.local.cipherT
|
||||
s.remote.hashT = s.local.hashT
|
||||
|
||||
// log.Debugf("1.2 selection: exchange:%s cipher:%s hash:%s",
|
||||
// s.local.curveT, s.local.cipherT, s.local.hashT)
|
||||
|
||||
// =============================================================================
|
||||
// step 2. Exchange -- exchange (signed) ephemeral keys. verify signatures.
|
||||
|
||||
// Generate EphemeralPubKey
|
||||
var genSharedKey ci.GenSharedKey
|
||||
s.local.ephemeralPubKey, genSharedKey, err = ci.GenerateEKeyPair(s.local.curveT)
|
||||
|
||||
// Gather corpus to sign.
|
||||
selectionOut := new(bytes.Buffer)
|
||||
selectionOut.Write(proposeOutBytes)
|
||||
selectionOut.Write(proposeInBytes)
|
||||
selectionOut.Write(s.local.ephemeralPubKey)
|
||||
selectionOutBytes := selectionOut.Bytes()
|
||||
|
||||
// log.Debugf("2.0 exchange: %v", selectionOutBytes)
|
||||
exchangeOut := new(pb.Exchange)
|
||||
exchangeOut.Epubkey = s.local.ephemeralPubKey
|
||||
exchangeOut.Signature, err = s.localKey.Sign(selectionOutBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Send Propose packet (respects ctx)
|
||||
if _, err := writeMsgCtx(ctx, s.insecureM, exchangeOut); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Receive + Parse their Exchange packet.
|
||||
exchangeIn := new(pb.Exchange)
|
||||
if _, err := readMsgCtx(ctx, s.insecureM, exchangeIn); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// step 2.1. Verify -- verify their exchange packet is good.
|
||||
|
||||
// get their ephemeral pub key
|
||||
s.remote.ephemeralPubKey = exchangeIn.GetEpubkey()
|
||||
|
||||
selectionIn := new(bytes.Buffer)
|
||||
selectionIn.Write(proposeInBytes)
|
||||
selectionIn.Write(proposeOutBytes)
|
||||
selectionIn.Write(s.remote.ephemeralPubKey)
|
||||
selectionInBytes := selectionIn.Bytes()
|
||||
// log.Debugf("2.0.1 exchange recv: %v", selectionInBytes)
|
||||
|
||||
// u.POut("Remote Peer Identified as %s\n", s.remote)
|
||||
sigOK, err := s.remote.permanentPubKey.Verify(selectionInBytes, exchangeIn.GetSignature())
|
||||
if err != nil {
|
||||
// log.Error("2.1 Verify: failed: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if !sigOK {
|
||||
err := errors.New("Bad signature!")
|
||||
// log.Error("2.1 Verify: failed: %s", err)
|
||||
return err
|
||||
}
|
||||
// log.Debugf("2.1 Verify: signature verified.")
|
||||
|
||||
// =============================================================================
|
||||
// step 2.2. Keys -- generate keys for mac + encryption
|
||||
|
||||
// OK! seems like we're good to go.
|
||||
s.sharedSecret, err = genSharedKey(exchangeIn.GetEpubkey())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// generate two sets of keys (stretching)
|
||||
k1, k2 := ci.KeyStretcher(s.local.cipherT, s.local.hashT, s.sharedSecret)
|
||||
|
||||
// use random nonces to decide order.
|
||||
switch {
|
||||
case order > 0:
|
||||
// just break
|
||||
case order < 0:
|
||||
k1, k2 = k2, k1 // swap
|
||||
default:
|
||||
// we should've bailed before this. but if not, bail here.
|
||||
return ErrEcho
|
||||
}
|
||||
s.local.keys = k1
|
||||
s.remote.keys = k2
|
||||
|
||||
// log.Debug("2.2 keys:\n\tshared: %v\n\tk1: %v\n\tk2: %v",
|
||||
// s.sharedSecret, s.local.keys, s.remote.keys)
|
||||
|
||||
// =============================================================================
|
||||
// step 2.3. MAC + Cipher -- prepare MAC + cipher
|
||||
|
||||
if err := s.local.makeMacAndCipher(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.remote.makeMacAndCipher(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// log.Debug("2.3 mac + cipher.")
|
||||
|
||||
// =============================================================================
|
||||
// step 3. Finish -- send expected message to verify encryption works (send local nonce)
|
||||
|
||||
// setup ETM ReadWriter
|
||||
w := NewETMWriter(s.insecure, s.local.cipher, s.local.mac)
|
||||
r := NewETMReader(s.insecure, s.remote.cipher, s.remote.mac)
|
||||
s.secure = msgio.Combine(w, r).(msgio.ReadWriteCloser)
|
||||
|
||||
// log.Debug("3.0 finish. sending: %v", proposeIn.GetRand())
|
||||
// send their Nonce.
|
||||
if _, err := s.secure.Write(proposeIn.GetRand()); err != nil {
|
||||
return fmt.Errorf("Failed to write Finish nonce: %s", err)
|
||||
}
|
||||
|
||||
// read our Nonce
|
||||
nonceOut2 := make([]byte, len(nonceOut))
|
||||
if _, err := io.ReadFull(s.secure, nonceOut2); err != nil {
|
||||
return fmt.Errorf("Failed to read Finish nonce: %s", err)
|
||||
}
|
||||
|
||||
// log.Debug("3.0 finish.\n\texpect: %v\n\tactual: %v", nonceOut, nonceOut2)
|
||||
if !bytes.Equal(nonceOut, nonceOut2) {
|
||||
return fmt.Errorf("Failed to read our encrypted nonce: %s != %s", nonceOut2, nonceOut)
|
||||
}
|
||||
|
||||
// Whew! ok, that's all folks.
|
||||
return nil
|
||||
}
|
||||
@@ -1,297 +0,0 @@
|
||||
package secio
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"crypto/hmac"
|
||||
|
||||
msgio "gx/ipfs/QmRQhVisS8dmPbjBUthVkenn81pBxrx1GxE281csJhm2vL/go-msgio"
|
||||
mpool "gx/ipfs/QmRQhVisS8dmPbjBUthVkenn81pBxrx1GxE281csJhm2vL/go-msgio/mpool"
|
||||
proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
)
|
||||
|
||||
// ErrMACInvalid signals that a MAC verification failed
|
||||
var ErrMACInvalid = errors.New("MAC verification failed")
|
||||
|
||||
// bufPool is a ByteSlicePool for messages. we need buffers because (sadly)
|
||||
// we cannot encrypt in place-- the user needs their buffer back.
|
||||
var bufPool = mpool.ByteSlicePool
|
||||
|
||||
type etmWriter struct {
|
||||
// params
|
||||
pool mpool.Pool // for the buffers with encrypted data
|
||||
msg msgio.WriteCloser // msgio for knowing where boundaries lie
|
||||
str cipher.Stream // the stream cipher to encrypt with
|
||||
mac HMAC // the mac to authenticate data with
|
||||
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
// NewETMWriter Encrypt-Then-MAC
|
||||
func NewETMWriter(w io.Writer, s cipher.Stream, mac HMAC) msgio.WriteCloser {
|
||||
return &etmWriter{msg: msgio.NewWriter(w), str: s, mac: mac, pool: bufPool}
|
||||
}
|
||||
|
||||
// Write writes passed in buffer as a single message.
|
||||
func (w *etmWriter) Write(b []byte) (int, error) {
|
||||
if err := w.WriteMsg(b); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
// WriteMsg writes the msg in the passed in buffer.
|
||||
func (w *etmWriter) WriteMsg(b []byte) error {
|
||||
w.Lock()
|
||||
defer w.Unlock()
|
||||
|
||||
// encrypt.
|
||||
data := w.pool.Get(uint32(len(b))).([]byte)
|
||||
data = data[:len(b)] // the pool's buffer may be larger
|
||||
w.str.XORKeyStream(data, b)
|
||||
|
||||
// log.Debugf("ENC plaintext (%d): %s %v", len(b), b, b)
|
||||
// log.Debugf("ENC ciphertext (%d): %s %v", len(data), data, data)
|
||||
|
||||
// then, mac.
|
||||
if _, err := w.mac.Write(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Sum appends.
|
||||
data = w.mac.Sum(data)
|
||||
w.mac.Reset()
|
||||
// it's sad to append here. our buffers are -- hopefully -- coming from
|
||||
// a shared buffer pool, so the append may not actually cause allocation
|
||||
// one can only hope. i guess we'll see.
|
||||
|
||||
return w.msg.WriteMsg(data)
|
||||
}
|
||||
|
||||
func (w *etmWriter) Close() error {
|
||||
return w.msg.Close()
|
||||
}
|
||||
|
||||
type etmReader struct {
|
||||
msgio.Reader
|
||||
io.Closer
|
||||
|
||||
// internal buffer returned from the msgio
|
||||
buf []byte
|
||||
|
||||
// low and high watermark for the buffered data
|
||||
lowat int
|
||||
hiwat int
|
||||
|
||||
// params
|
||||
msg msgio.ReadCloser // msgio for knowing where boundaries lie
|
||||
str cipher.Stream // the stream cipher to encrypt with
|
||||
mac HMAC // the mac to authenticate data with
|
||||
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
// NewETMReader Encrypt-Then-MAC
|
||||
func NewETMReader(r io.Reader, s cipher.Stream, mac HMAC) msgio.ReadCloser {
|
||||
return &etmReader{msg: msgio.NewReader(r), str: s, mac: mac}
|
||||
}
|
||||
|
||||
func (r *etmReader) NextMsgLen() (int, error) {
|
||||
return r.msg.NextMsgLen()
|
||||
}
|
||||
|
||||
func (r *etmReader) drain(buf []byte) int {
|
||||
// Return zero if there is no data remaining in the internal buffer.
|
||||
if r.lowat == r.hiwat {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Copy data to the output buffer.
|
||||
n := copy(buf, r.buf[r.lowat:r.hiwat])
|
||||
|
||||
// Update the low watermark.
|
||||
r.lowat += n
|
||||
|
||||
// Release the buffer and reset the watermarks if it has been fully read.
|
||||
if r.lowat == r.hiwat {
|
||||
r.msg.ReleaseMsg(r.buf)
|
||||
r.buf = nil
|
||||
r.lowat = 0
|
||||
r.hiwat = 0
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
func (r *etmReader) fill() error {
|
||||
// Read a message from the underlying msgio.
|
||||
msg, err := r.msg.ReadMsg()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check the MAC.
|
||||
n, err := r.macCheckThenDecrypt(msg)
|
||||
if err != nil {
|
||||
r.msg.ReleaseMsg(msg)
|
||||
return err
|
||||
}
|
||||
|
||||
// Retain the buffer so it can be drained from and later released.
|
||||
r.buf = msg
|
||||
r.lowat = 0
|
||||
r.hiwat = n
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *etmReader) Read(buf []byte) (int, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
// Return buffered data without reading more, if possible.
|
||||
copied := r.drain(buf)
|
||||
if copied > 0 {
|
||||
return copied, nil
|
||||
}
|
||||
|
||||
// Check the length of the next message.
|
||||
fullLen, err := r.msg.NextMsgLen()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// If the destination buffer is too short, fill an internal buffer and then
|
||||
// drain as much of that into the output buffer as will fit.
|
||||
if cap(buf) < fullLen {
|
||||
err := r.fill()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
copied := r.drain(buf)
|
||||
return copied, nil
|
||||
}
|
||||
|
||||
// Otherwise, read directly into the destination buffer.
|
||||
n, err := io.ReadFull(r.msg, buf[:fullLen])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
m, err := r.macCheckThenDecrypt(buf[:n])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (r *etmReader) ReadMsg() ([]byte, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
msg, err := r.msg.ReadMsg()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, err := r.macCheckThenDecrypt(msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg[:n], nil
|
||||
}
|
||||
|
||||
func (r *etmReader) macCheckThenDecrypt(m []byte) (int, error) {
|
||||
l := len(m)
|
||||
if l < r.mac.size {
|
||||
return 0, fmt.Errorf("buffer (%d) shorter than MAC size (%d)", l, r.mac.size)
|
||||
}
|
||||
|
||||
mark := l - r.mac.size
|
||||
data := m[:mark]
|
||||
macd := m[mark:]
|
||||
|
||||
r.mac.Write(data)
|
||||
expected := r.mac.Sum(nil)
|
||||
r.mac.Reset()
|
||||
|
||||
// check mac. if failed, return error.
|
||||
if !hmac.Equal(macd, expected) {
|
||||
log.Debug("MAC Invalid:", expected, "!=", macd)
|
||||
return 0, ErrMACInvalid
|
||||
}
|
||||
|
||||
// ok seems good. decrypt. (can decrypt in place, yay!)
|
||||
// log.Debugf("DEC ciphertext (%d): %s %v", len(data), data, data)
|
||||
r.str.XORKeyStream(data, data)
|
||||
// log.Debugf("DEC plaintext (%d): %s %v", len(data), data, data)
|
||||
|
||||
return mark, nil
|
||||
}
|
||||
|
||||
func (w *etmReader) Close() error {
|
||||
return w.msg.Close()
|
||||
}
|
||||
|
||||
// ReleaseMsg signals a buffer can be reused.
|
||||
func (r *etmReader) ReleaseMsg(b []byte) {
|
||||
r.msg.ReleaseMsg(b)
|
||||
}
|
||||
|
||||
// writeMsgCtx is used by the
|
||||
func writeMsgCtx(ctx context.Context, w msgio.Writer, msg proto.Message) ([]byte, error) {
|
||||
enc, err := proto.Marshal(msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// write in a goroutine so we can exit when our context is cancelled.
|
||||
done := make(chan error)
|
||||
go func(m []byte) {
|
||||
err := w.WriteMsg(m)
|
||||
select {
|
||||
case done <- err:
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}(enc)
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case e := <-done:
|
||||
return enc, e
|
||||
}
|
||||
}
|
||||
|
||||
func readMsgCtx(ctx context.Context, r msgio.Reader, p proto.Message) ([]byte, error) {
|
||||
var msg []byte
|
||||
|
||||
// read in a goroutine so we can exit when our context is cancelled.
|
||||
done := make(chan error)
|
||||
go func() {
|
||||
var err error
|
||||
msg, err = r.ReadMsg()
|
||||
select {
|
||||
case done <- err:
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case e := <-done:
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
}
|
||||
|
||||
return msg, proto.Unmarshal(msg, p)
|
||||
}
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-libp2p/p2p/host"
|
||||
"github.com/ipfs/go-libp2p/p2p/peer"
|
||||
"gx/ipfs/QmSscYPCcE1H3UQr2tnsJ2a9dK9LsHTBGgP71VW6fz67e5/mdns"
|
||||
"gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
manet "gx/ipfs/QmYVqhVfbK4BKvbW88Lhm26b3ud14sTBvcm1H7uWUx1Fkp/go-multiaddr-net"
|
||||
logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
|
||||
@@ -6,11 +6,11 @@ import (
|
||||
metrics "github.com/ipfs/go-libp2p/p2p/metrics"
|
||||
mstream "github.com/ipfs/go-libp2p/p2p/metrics/stream"
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
protocol "github.com/ipfs/go-libp2p/p2p/protocol"
|
||||
identify "github.com/ipfs/go-libp2p/p2p/protocol/identify"
|
||||
relay "github.com/ipfs/go-libp2p/p2p/protocol/relay"
|
||||
goprocess "gx/ipfs/QmQopLATEYMNg7dVqZRNDfeE2S1yKy8zrRh5xnYiuqeZBn/goprocess"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
|
||||
@@ -3,10 +3,10 @@ package basichost
|
||||
import (
|
||||
"sync"
|
||||
|
||||
lgbl "github.com/ipfs/go-libp2p/loggables"
|
||||
inat "github.com/ipfs/go-libp2p/p2p/nat"
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
goprocess "gx/ipfs/QmQopLATEYMNg7dVqZRNDfeE2S1yKy8zrRh5xnYiuqeZBn/goprocess"
|
||||
lgbl "gx/ipfs/QmSyBhZt2upyQ3NJmTpab1pX6hesA59vcYTGmgoDorZZbw/go-libp2p-loggables"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
@@ -3,9 +3,9 @@ package host
|
||||
import (
|
||||
metrics "github.com/ipfs/go-libp2p/p2p/metrics"
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
protocol "github.com/ipfs/go-libp2p/p2p/protocol"
|
||||
msmux "gx/ipfs/QmUeEcYJrzAEKdQXjzTxCgNZgc9sRuwharsvzzm5Gd2oGB/go-multistream"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
|
||||
@@ -4,12 +4,12 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
lgbl "github.com/ipfs/go-libp2p/loggables"
|
||||
host "github.com/ipfs/go-libp2p/p2p/host"
|
||||
metrics "github.com/ipfs/go-libp2p/p2p/metrics"
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
protocol "github.com/ipfs/go-libp2p/p2p/protocol"
|
||||
lgbl "gx/ipfs/QmSyBhZt2upyQ3NJmTpab1pX6hesA59vcYTGmgoDorZZbw/go-libp2p-loggables"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
gm "gx/ipfs/QmeYJHEk8UjVVZ4XCRTZe6dFQrb8pGWD81LYCgeLp8CvMB/go-metrics"
|
||||
"sync"
|
||||
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
protocol "github.com/ipfs/go-libp2p/p2p/protocol"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
)
|
||||
|
||||
type Stats struct {
|
||||
|
||||
@@ -2,7 +2,7 @@ package meterconn
|
||||
|
||||
import (
|
||||
metrics "github.com/ipfs/go-libp2p/p2p/metrics"
|
||||
transport "github.com/ipfs/go-libp2p/p2p/net/transport"
|
||||
transport "gx/ipfs/QmR4HhZm1fL8epXz8661Ru8ks5Y1Uk2u51quAWaCTD1zHg/go-libp2p-transport"
|
||||
)
|
||||
|
||||
type MeteredConn struct {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
protocol "github.com/ipfs/go-libp2p/p2p/protocol"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
)
|
||||
|
||||
type StreamMeterCallback func(int64, protocol.ID, peer.ID)
|
||||
|
||||
@@ -3,8 +3,8 @@ package meterstream
|
||||
import (
|
||||
metrics "github.com/ipfs/go-libp2p/p2p/metrics"
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
protocol "github.com/ipfs/go-libp2p/p2p/protocol"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
)
|
||||
|
||||
type meteredStream struct {
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"testing"
|
||||
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
protocol "github.com/ipfs/go-libp2p/p2p/protocol"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
randbo "gx/ipfs/QmYvsG72GsfLgUeSojXArjnU6L4Wmwk7wuAxtNLuyXcc1T/randbo"
|
||||
)
|
||||
|
||||
|
||||
@@ -6,13 +6,13 @@ import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
lgbl "github.com/ipfs/go-libp2p/loggables"
|
||||
ic "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
mpool "gx/ipfs/QmRQhVisS8dmPbjBUthVkenn81pBxrx1GxE281csJhm2vL/go-msgio/mpool"
|
||||
lgbl "gx/ipfs/QmSyBhZt2upyQ3NJmTpab1pX6hesA59vcYTGmgoDorZZbw/go-libp2p-loggables"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
manet "gx/ipfs/QmYVqhVfbK4BKvbW88Lhm26b3ud14sTBvcm1H7uWUx1Fkp/go-multiaddr-net"
|
||||
u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ic "gx/ipfs/QmaP38GJApheTr84f8R89vsT7oJLQw1AeCz4HqrQgv2njB/go-libp2p-crypto"
|
||||
logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
@@ -5,14 +5,14 @@ import (
|
||||
"math/rand"
|
||||
"strings"
|
||||
|
||||
lgbl "github.com/ipfs/go-libp2p/loggables"
|
||||
ci "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
addrutil "github.com/ipfs/go-libp2p/p2p/net/swarm/addr"
|
||||
transport "github.com/ipfs/go-libp2p/p2p/net/transport"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
transport "gx/ipfs/QmR4HhZm1fL8epXz8661Ru8ks5Y1Uk2u51quAWaCTD1zHg/go-libp2p-transport"
|
||||
lgbl "gx/ipfs/QmSyBhZt2upyQ3NJmTpab1pX6hesA59vcYTGmgoDorZZbw/go-libp2p-loggables"
|
||||
msmux "gx/ipfs/QmUeEcYJrzAEKdQXjzTxCgNZgc9sRuwharsvzzm5Gd2oGB/go-multistream"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
manet "gx/ipfs/QmYVqhVfbK4BKvbW88Lhm26b3ud14sTBvcm1H7uWUx1Fkp/go-multiaddr-net"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ci "gx/ipfs/QmaP38GJApheTr84f8R89vsT7oJLQw1AeCz4HqrQgv2njB/go-libp2p-crypto"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
ic "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
transport "github.com/ipfs/go-libp2p/p2p/net/transport"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
tu "github.com/ipfs/go-libp2p/testutil"
|
||||
transport "gx/ipfs/QmR4HhZm1fL8epXz8661Ru8ks5Y1Uk2u51quAWaCTD1zHg/go-libp2p-transport"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
ic "gx/ipfs/QmaP38GJApheTr84f8R89vsT7oJLQw1AeCz4HqrQgv2njB/go-libp2p-crypto"
|
||||
|
||||
grc "gx/ipfs/QmTd4Jgb4nbJq5uR55KJgGLyHWmM3dovS21D1HcwRneSLu/gorocheck"
|
||||
msmux "gx/ipfs/QmUeEcYJrzAEKdQXjzTxCgNZgc9sRuwharsvzzm5Gd2oGB/go-multistream"
|
||||
|
||||
@@ -5,11 +5,10 @@ import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
ic "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
filter "github.com/ipfs/go-libp2p/p2p/net/filter"
|
||||
transport "github.com/ipfs/go-libp2p/p2p/net/transport"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
|
||||
transport "gx/ipfs/QmR4HhZm1fL8epXz8661Ru8ks5Y1Uk2u51quAWaCTD1zHg/go-libp2p-transport"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
ic "gx/ipfs/QmaP38GJApheTr84f8R89vsT7oJLQw1AeCz4HqrQgv2njB/go-libp2p-crypto"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
|
||||
@@ -7,15 +7,15 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
ic "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
filter "github.com/ipfs/go-libp2p/p2p/net/filter"
|
||||
transport "github.com/ipfs/go-libp2p/p2p/net/transport"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
"gx/ipfs/QmQopLATEYMNg7dVqZRNDfeE2S1yKy8zrRh5xnYiuqeZBn/goprocess"
|
||||
goprocessctx "gx/ipfs/QmQopLATEYMNg7dVqZRNDfeE2S1yKy8zrRh5xnYiuqeZBn/goprocess/context"
|
||||
transport "gx/ipfs/QmR4HhZm1fL8epXz8661Ru8ks5Y1Uk2u51quAWaCTD1zHg/go-libp2p-transport"
|
||||
msmux "gx/ipfs/QmUeEcYJrzAEKdQXjzTxCgNZgc9sRuwharsvzzm5Gd2oGB/go-multistream"
|
||||
tec "gx/ipfs/QmWHgLqrghM9zw77nF6gdvT9ExQ2RB9pLxkd8sDHZf1rWb/go-temp-err-catcher"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ic "gx/ipfs/QmaP38GJApheTr84f8R89vsT7oJLQw1AeCz4HqrQgv2njB/go-libp2p-crypto"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
ic "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
secio "github.com/ipfs/go-libp2p/p2p/crypto/secio"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ic "gx/ipfs/QmaP38GJApheTr84f8R89vsT7oJLQw1AeCz4HqrQgv2njB/go-libp2p-crypto"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
secio "gx/ipfs/QmeBhrdD3K5aMCubZMwhAbcCuHbWjTvVbhQX73kFx2qQfs/go-libp2p-secio"
|
||||
)
|
||||
|
||||
// secureConn wraps another Conn object with an encrypted channel.
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
ic "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
travis "github.com/ipfs/go-libp2p/testutil/ci/travis"
|
||||
ic "gx/ipfs/QmaP38GJApheTr84f8R89vsT7oJLQw1AeCz4HqrQgv2njB/go-libp2p-crypto"
|
||||
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
)
|
||||
|
||||
@@ -4,9 +4,8 @@ import (
|
||||
"io"
|
||||
|
||||
conn "github.com/ipfs/go-libp2p/p2p/net/conn"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
|
||||
"gx/ipfs/QmQopLATEYMNg7dVqZRNDfeE2S1yKy8zrRh5xnYiuqeZBn/goprocess"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
package mocknet
|
||||
|
||||
import (
|
||||
ic "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
host "github.com/ipfs/go-libp2p/p2p/host"
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
ic "gx/ipfs/QmaP38GJApheTr84f8R89vsT7oJLQw1AeCz4HqrQgv2njB/go-libp2p-crypto"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
|
||||
@@ -4,11 +4,10 @@ import (
|
||||
"container/list"
|
||||
"sync"
|
||||
|
||||
ic "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
|
||||
process "gx/ipfs/QmQopLATEYMNg7dVqZRNDfeE2S1yKy8zrRh5xnYiuqeZBn/goprocess"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
ic "gx/ipfs/QmaP38GJApheTr84f8R89vsT7oJLQw1AeCz4HqrQgv2njB/go-libp2p-crypto"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
)
|
||||
|
||||
// link implements mocknet.Link
|
||||
|
||||
@@ -5,13 +5,13 @@ import (
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
ic "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
host "github.com/ipfs/go-libp2p/p2p/host"
|
||||
bhost "github.com/ipfs/go-libp2p/p2p/host/basic"
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
p2putil "github.com/ipfs/go-libp2p/p2p/test/util"
|
||||
testutil "github.com/ipfs/go-libp2p/testutil"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
ic "gx/ipfs/QmaP38GJApheTr84f8R89vsT7oJLQw1AeCz4HqrQgv2njB/go-libp2p-crypto"
|
||||
|
||||
"gx/ipfs/QmQopLATEYMNg7dVqZRNDfeE2S1yKy8zrRh5xnYiuqeZBn/goprocess"
|
||||
goprocessctx "gx/ipfs/QmQopLATEYMNg7dVqZRNDfeE2S1yKy8zrRh5xnYiuqeZBn/goprocess/context"
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
@@ -6,10 +6,9 @@ import (
|
||||
"sync"
|
||||
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
|
||||
"gx/ipfs/QmQopLATEYMNg7dVqZRNDfeE2S1yKy8zrRh5xnYiuqeZBn/goprocess"
|
||||
goprocessctx "gx/ipfs/QmQopLATEYMNg7dVqZRNDfeE2S1yKy8zrRh5xnYiuqeZBn/goprocess/context"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"io"
|
||||
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
)
|
||||
|
||||
// separate object so our interfaces are separate :)
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
"time"
|
||||
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
protocol "github.com/ipfs/go-libp2p/p2p/protocol"
|
||||
testutil "github.com/ipfs/go-libp2p/testutil"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
|
||||
detectrace "gx/ipfs/QmQHGMVmrsgmqUG8ih3puNXUJneSpi13dkcZpzLKkskUkH/go-detect-race"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
|
||||
@@ -8,10 +8,9 @@ import (
|
||||
"time"
|
||||
|
||||
addrutil "github.com/ipfs/go-libp2p/p2p/net/swarm/addr"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
|
||||
testutil "github.com/ipfs/go-libp2p/testutil"
|
||||
ci "github.com/ipfs/go-libp2p/testutil/ci"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
|
||||
manet "gx/ipfs/QmYVqhVfbK4BKvbW88Lhm26b3ud14sTBvcm1H7uWUx1Fkp/go-multiaddr-net"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
|
||||
@@ -3,8 +3,7 @@ package swarm
|
||||
import (
|
||||
"testing"
|
||||
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
ci "github.com/ipfs/go-libp2p/testutil/ci"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
|
||||
@@ -14,16 +14,15 @@ import (
|
||||
conn "github.com/ipfs/go-libp2p/p2p/net/conn"
|
||||
filter "github.com/ipfs/go-libp2p/p2p/net/filter"
|
||||
addrutil "github.com/ipfs/go-libp2p/p2p/net/swarm/addr"
|
||||
transport "github.com/ipfs/go-libp2p/p2p/net/transport"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
|
||||
mafilter "gx/ipfs/QmPwfFAHUmvWDucLHRS9Xz2Kb1TNX2cY4LJ7pQjg9kVcae/multiaddr-filter"
|
||||
"gx/ipfs/QmQopLATEYMNg7dVqZRNDfeE2S1yKy8zrRh5xnYiuqeZBn/goprocess"
|
||||
goprocessctx "gx/ipfs/QmQopLATEYMNg7dVqZRNDfeE2S1yKy8zrRh5xnYiuqeZBn/goprocess/context"
|
||||
transport "gx/ipfs/QmR4HhZm1fL8epXz8661Ru8ks5Y1Uk2u51quAWaCTD1zHg/go-libp2p-transport"
|
||||
pst "gx/ipfs/QmWSJzRkCMJFHYUQZxKwPX8WA7XipaPtfiwMPARP51ymfn/go-stream-muxer"
|
||||
psmss "gx/ipfs/QmWSJzRkCMJFHYUQZxKwPX8WA7XipaPtfiwMPARP51ymfn/go-stream-muxer/multistream"
|
||||
spdy "gx/ipfs/QmWSJzRkCMJFHYUQZxKwPX8WA7XipaPtfiwMPARP51ymfn/go-stream-muxer/spdystream"
|
||||
yamux "gx/ipfs/QmWSJzRkCMJFHYUQZxKwPX8WA7XipaPtfiwMPARP51ymfn/go-stream-muxer/yamux"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
ps "gx/ipfs/QmZK81vcgMhpb2t7GNbozk7qzt6Rj4zFqitpvsWT9mduW8/go-peerstream"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
|
||||
metrics "github.com/ipfs/go-libp2p/p2p/metrics"
|
||||
addrutil "github.com/ipfs/go-libp2p/p2p/net/swarm/addr"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
testutil "github.com/ipfs/go-libp2p/testutil"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
|
||||
@@ -3,13 +3,13 @@ package swarm
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
ic "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
conn "github.com/ipfs/go-libp2p/p2p/net/conn"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
ps "gx/ipfs/QmZK81vcgMhpb2t7GNbozk7qzt6Rj4zFqitpvsWT9mduW8/go-peerstream"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ic "gx/ipfs/QmaP38GJApheTr84f8R89vsT7oJLQw1AeCz4HqrQgv2njB/go-libp2p-crypto"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
|
||||
@@ -8,10 +8,10 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
lgbl "github.com/ipfs/go-libp2p/loggables"
|
||||
conn "github.com/ipfs/go-libp2p/p2p/net/conn"
|
||||
addrutil "github.com/ipfs/go-libp2p/p2p/net/swarm/addr"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
lgbl "gx/ipfs/QmSyBhZt2upyQ3NJmTpab1pX6hesA59vcYTGmgoDorZZbw/go-libp2p-loggables"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
"gx/ipfs/QmYVqhVfbK4BKvbW88Lhm26b3ud14sTBvcm1H7uWUx1Fkp/go-multiaddr-net"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
|
||||
@@ -3,12 +3,11 @@ package swarm
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
lgbl "github.com/ipfs/go-libp2p/loggables"
|
||||
mconn "github.com/ipfs/go-libp2p/p2p/metrics/conn"
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
conn "github.com/ipfs/go-libp2p/p2p/net/conn"
|
||||
transport "github.com/ipfs/go-libp2p/p2p/net/transport"
|
||||
|
||||
transport "gx/ipfs/QmR4HhZm1fL8epXz8661Ru8ks5Y1Uk2u51quAWaCTD1zHg/go-libp2p-transport"
|
||||
lgbl "gx/ipfs/QmSyBhZt2upyQ3NJmTpab1pX6hesA59vcYTGmgoDorZZbw/go-libp2p-loggables"
|
||||
ps "gx/ipfs/QmZK81vcgMhpb2t7GNbozk7qzt6Rj4zFqitpvsWT9mduW8/go-peerstream"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
|
||||
@@ -3,10 +3,9 @@ package swarm
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
|
||||
metrics "github.com/ipfs/go-libp2p/p2p/metrics"
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
|
||||
"gx/ipfs/QmQopLATEYMNg7dVqZRNDfeE2S1yKy8zrRh5xnYiuqeZBn/goprocess"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
|
||||
metrics "github.com/ipfs/go-libp2p/p2p/metrics"
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
testutil "github.com/ipfs/go-libp2p/testutil"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
mafmt "gx/ipfs/QmWLfU4tstw2aNcTykDm44xbSTCYJ9pUJwfhQCKGwckcHx/mafmt"
|
||||
manet "gx/ipfs/QmYVqhVfbK4BKvbW88Lhm26b3ud14sTBvcm1H7uWUx1Fkp/go-multiaddr-net"
|
||||
mautp "gx/ipfs/QmYVqhVfbK4BKvbW88Lhm26b3ud14sTBvcm1H7uWUx1Fkp/go-multiaddr-net/utp"
|
||||
utp "gx/ipfs/QmadkZhaLw1AhXKyBiPmydRuTexhj6WkiZPpo5Uks6WUVq/utp"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
type FallbackDialer struct {
|
||||
madialer manet.Dialer
|
||||
}
|
||||
|
||||
func (fbd *FallbackDialer) Matches(a ma.Multiaddr) bool {
|
||||
return mafmt.TCP.Matches(a) || mafmt.UTP.Matches(a)
|
||||
}
|
||||
|
||||
func (fbd *FallbackDialer) Dial(a ma.Multiaddr) (Conn, error) {
|
||||
if mafmt.TCP.Matches(a) {
|
||||
return fbd.tcpDial(a)
|
||||
}
|
||||
if mafmt.UTP.Matches(a) {
|
||||
return fbd.tcpDial(a)
|
||||
}
|
||||
return nil, fmt.Errorf("cannot dial %s with fallback dialer", a)
|
||||
}
|
||||
|
||||
func (fbd *FallbackDialer) tcpDial(raddr ma.Multiaddr) (Conn, error) {
|
||||
var c manet.Conn
|
||||
var err error
|
||||
c, err = fbd.madialer.Dial(raddr)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &connWrap{
|
||||
Conn: c,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (fbd *FallbackDialer) utpDial(raddr ma.Multiaddr) (Conn, error) {
|
||||
_, addr, err := manet.DialArgs(raddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
con, err := utp.Dial(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mnc, err := manet.WrapNetConn(&mautp.Conn{Conn: con})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &connWrap{
|
||||
Conn: mnc,
|
||||
}, nil
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
reuseport "gx/ipfs/QmaaC9QMYTQHCbMq3Ebr3uMaAR2ev4AVqMmsJpgQijAZbJ/go-reuseport"
|
||||
)
|
||||
|
||||
// envReuseport is the env variable name used to turn off reuse port.
|
||||
// It default to true.
|
||||
const envReuseport = "IPFS_REUSEPORT"
|
||||
|
||||
// envReuseportVal stores the value of envReuseport. defaults to true.
|
||||
var envReuseportVal = true
|
||||
|
||||
func init() {
|
||||
v := strings.ToLower(os.Getenv(envReuseport))
|
||||
if v == "false" || v == "f" || v == "0" {
|
||||
envReuseportVal = false
|
||||
log.Infof("REUSEPORT disabled (IPFS_REUSEPORT=%s)", v)
|
||||
}
|
||||
}
|
||||
|
||||
// reuseportIsAvailable returns whether reuseport is available to be used. This
|
||||
// is here because we want to be able to turn reuseport on and off selectively.
|
||||
// For now we use an ENV variable, as this handles our pressing need:
|
||||
//
|
||||
// IPFS_REUSEPORT=false ipfs daemon
|
||||
//
|
||||
// If this becomes a sought after feature, we could add this to the config.
|
||||
// In the end, reuseport is a stop-gap.
|
||||
func ReuseportIsAvailable() bool {
|
||||
return envReuseportVal && reuseport.Available()
|
||||
}
|
||||
|
||||
// ReuseErrShouldRetry diagnoses whether to retry after a reuse error.
|
||||
// if we failed to bind, we should retry. if bind worked and this is a
|
||||
// real dial error (remote end didnt answer) then we should not retry.
|
||||
func ReuseErrShouldRetry(err error) bool {
|
||||
if err == nil {
|
||||
return false // hey, it worked! no need to retry.
|
||||
}
|
||||
|
||||
// if it's a network timeout error, it's a legitimate failure.
|
||||
if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
|
||||
return false
|
||||
}
|
||||
|
||||
errno, ok := err.(syscall.Errno)
|
||||
if !ok { // not an errno? who knows what this is. retry.
|
||||
return true
|
||||
}
|
||||
|
||||
switch errno {
|
||||
case syscall.EADDRINUSE, syscall.EADDRNOTAVAIL:
|
||||
return true // failure to bind. retry.
|
||||
case syscall.ECONNREFUSED:
|
||||
return false // real dial error
|
||||
default:
|
||||
return true // optimistically default to retry.
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
lgbl "github.com/ipfs/go-libp2p/loggables"
|
||||
mafmt "gx/ipfs/QmWLfU4tstw2aNcTykDm44xbSTCYJ9pUJwfhQCKGwckcHx/mafmt"
|
||||
manet "gx/ipfs/QmYVqhVfbK4BKvbW88Lhm26b3ud14sTBvcm1H7uWUx1Fkp/go-multiaddr-net"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
reuseport "gx/ipfs/QmaaC9QMYTQHCbMq3Ebr3uMaAR2ev4AVqMmsJpgQijAZbJ/go-reuseport"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
type TcpTransport struct {
|
||||
dlock sync.Mutex
|
||||
dialers map[string]Dialer
|
||||
|
||||
llock sync.Mutex
|
||||
listeners map[string]Listener
|
||||
}
|
||||
|
||||
func NewTCPTransport() *TcpTransport {
|
||||
return &TcpTransport{
|
||||
dialers: make(map[string]Dialer),
|
||||
listeners: make(map[string]Listener),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TcpTransport) Dialer(laddr ma.Multiaddr, opts ...DialOpt) (Dialer, error) {
|
||||
t.dlock.Lock()
|
||||
defer t.dlock.Unlock()
|
||||
s := laddr.String()
|
||||
d, found := t.dialers[s]
|
||||
if found {
|
||||
return d, nil
|
||||
}
|
||||
var base manet.Dialer
|
||||
|
||||
var doReuse bool
|
||||
for _, o := range opts {
|
||||
switch o := o.(type) {
|
||||
case TimeoutOpt:
|
||||
base.Timeout = time.Duration(o)
|
||||
case ReuseportOpt:
|
||||
doReuse = bool(o)
|
||||
default:
|
||||
return nil, fmt.Errorf("unrecognized option: %#v", o)
|
||||
}
|
||||
}
|
||||
|
||||
tcpd, err := t.newTcpDialer(base, laddr, doReuse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t.dialers[s] = tcpd
|
||||
return tcpd, nil
|
||||
}
|
||||
|
||||
func (t *TcpTransport) Listen(laddr ma.Multiaddr) (Listener, error) {
|
||||
t.llock.Lock()
|
||||
defer t.llock.Unlock()
|
||||
s := laddr.String()
|
||||
l, found := t.listeners[s]
|
||||
if found {
|
||||
return l, nil
|
||||
}
|
||||
|
||||
list, err := manetListen(laddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tlist := &tcpListener{
|
||||
list: list,
|
||||
transport: t,
|
||||
}
|
||||
|
||||
t.listeners[s] = tlist
|
||||
return tlist, nil
|
||||
}
|
||||
|
||||
func manetListen(addr ma.Multiaddr) (manet.Listener, error) {
|
||||
network, naddr, err := manet.DialArgs(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ReuseportIsAvailable() {
|
||||
nl, err := reuseport.Listen(network, naddr)
|
||||
if err == nil {
|
||||
// hey, it worked!
|
||||
return manet.WrapNetListener(nl)
|
||||
}
|
||||
// reuseport is available, but we failed to listen. log debug, and retry normally.
|
||||
log.Debugf("reuseport available, but failed to listen: %s %s, %s", network, naddr, err)
|
||||
}
|
||||
|
||||
// either reuseport not available, or it failed. try normally.
|
||||
return manet.Listen(addr)
|
||||
}
|
||||
|
||||
func (t *TcpTransport) Matches(a ma.Multiaddr) bool {
|
||||
return mafmt.TCP.Matches(a)
|
||||
}
|
||||
|
||||
type tcpDialer struct {
|
||||
laddr ma.Multiaddr
|
||||
|
||||
doReuse bool
|
||||
|
||||
rd reuseport.Dialer
|
||||
madialer manet.Dialer
|
||||
|
||||
transport Transport
|
||||
}
|
||||
|
||||
func (t *TcpTransport) newTcpDialer(base manet.Dialer, laddr ma.Multiaddr, doReuse bool) (*tcpDialer, error) {
|
||||
// get the local net.Addr manually
|
||||
la, err := manet.ToNetAddr(laddr)
|
||||
if err != nil {
|
||||
return nil, err // something wrong with laddr.
|
||||
}
|
||||
|
||||
if doReuse && ReuseportIsAvailable() {
|
||||
rd := reuseport.Dialer{
|
||||
D: net.Dialer{
|
||||
LocalAddr: la,
|
||||
Timeout: base.Timeout,
|
||||
},
|
||||
}
|
||||
|
||||
return &tcpDialer{
|
||||
doReuse: true,
|
||||
laddr: laddr,
|
||||
rd: rd,
|
||||
madialer: base,
|
||||
transport: t,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &tcpDialer{
|
||||
doReuse: false,
|
||||
laddr: laddr,
|
||||
madialer: base,
|
||||
transport: t,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *tcpDialer) Dial(raddr ma.Multiaddr) (Conn, error) {
|
||||
var c manet.Conn
|
||||
var err error
|
||||
if d.doReuse {
|
||||
c, err = d.reuseDial(raddr)
|
||||
} else {
|
||||
c, err = d.madialer.Dial(raddr)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &connWrap{
|
||||
Conn: c,
|
||||
transport: d.transport,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *tcpDialer) reuseDial(raddr ma.Multiaddr) (manet.Conn, error) {
|
||||
logdial := lgbl.Dial("conn", "", "", d.laddr, raddr)
|
||||
rpev := log.EventBegin(context.TODO(), "tptDialReusePort", logdial)
|
||||
|
||||
network, netraddr, err := manet.DialArgs(raddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
con, err := d.rd.Dial(network, netraddr)
|
||||
if err == nil {
|
||||
logdial["reuseport"] = "success"
|
||||
rpev.Done()
|
||||
return manet.WrapNetConn(con)
|
||||
}
|
||||
|
||||
if !ReuseErrShouldRetry(err) {
|
||||
logdial["reuseport"] = "failure"
|
||||
logdial["error"] = err
|
||||
rpev.Done()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logdial["reuseport"] = "retry"
|
||||
logdial["error"] = err
|
||||
rpev.Done()
|
||||
|
||||
return d.madialer.Dial(raddr)
|
||||
}
|
||||
|
||||
func (d *tcpDialer) Matches(a ma.Multiaddr) bool {
|
||||
return mafmt.TCP.Matches(a)
|
||||
}
|
||||
|
||||
type tcpListener struct {
|
||||
list manet.Listener
|
||||
transport Transport
|
||||
}
|
||||
|
||||
func (d *tcpListener) Accept() (Conn, error) {
|
||||
c, err := d.list.Accept()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &connWrap{
|
||||
Conn: c,
|
||||
transport: d.transport,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *tcpListener) Addr() net.Addr {
|
||||
return d.list.Addr()
|
||||
}
|
||||
|
||||
func (t *tcpListener) Multiaddr() ma.Multiaddr {
|
||||
return t.list.Multiaddr()
|
||||
}
|
||||
|
||||
func (t *tcpListener) NetListener() net.Listener {
|
||||
return t.list.NetListener()
|
||||
}
|
||||
|
||||
func (d *tcpListener) Close() error {
|
||||
return d.list.Close()
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
manet "gx/ipfs/QmYVqhVfbK4BKvbW88Lhm26b3ud14sTBvcm1H7uWUx1Fkp/go-multiaddr-net"
|
||||
logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
var log = logging.Logger("transport")
|
||||
|
||||
type Conn interface {
|
||||
manet.Conn
|
||||
|
||||
Transport() Transport
|
||||
}
|
||||
|
||||
type Transport interface {
|
||||
Dialer(laddr ma.Multiaddr, opts ...DialOpt) (Dialer, error)
|
||||
Listen(laddr ma.Multiaddr) (Listener, error)
|
||||
Matches(ma.Multiaddr) bool
|
||||
}
|
||||
|
||||
type Dialer interface {
|
||||
Dial(raddr ma.Multiaddr) (Conn, error)
|
||||
Matches(ma.Multiaddr) bool
|
||||
}
|
||||
|
||||
type Listener interface {
|
||||
Accept() (Conn, error)
|
||||
Close() error
|
||||
Addr() net.Addr
|
||||
Multiaddr() ma.Multiaddr
|
||||
}
|
||||
|
||||
type connWrap struct {
|
||||
manet.Conn
|
||||
transport Transport
|
||||
}
|
||||
|
||||
func (cw *connWrap) Transport() Transport {
|
||||
return cw.transport
|
||||
}
|
||||
|
||||
type DialOpt interface{}
|
||||
type TimeoutOpt time.Duration
|
||||
type ReuseportOpt bool
|
||||
|
||||
var ReusePorts ReuseportOpt = true
|
||||
@@ -1,135 +0,0 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
func TestTcpTransport(t *testing.T) {
|
||||
ta := NewTCPTransport()
|
||||
tb := NewTCPTransport()
|
||||
|
||||
zero := "/ip4/127.0.0.1/tcp/0"
|
||||
subtestTransport(t, ta, tb, zero)
|
||||
}
|
||||
|
||||
func TestUtpTransport(t *testing.T) {
|
||||
ta := NewUtpTransport()
|
||||
tb := NewUtpTransport()
|
||||
|
||||
zero := "/ip4/127.0.0.1/udp/0/utp"
|
||||
subtestTransport(t, ta, tb, zero)
|
||||
}
|
||||
|
||||
func subtestTransport(t *testing.T, ta, tb Transport, addr string) {
|
||||
maddr, err := ma.NewMultiaddr(addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
list, err := ta.Listen(maddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dialer, err := tb.Dialer(maddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
accepted := make(chan Conn, 1)
|
||||
errs := make(chan error, 1)
|
||||
go func() {
|
||||
b, err := list.Accept()
|
||||
if err != nil {
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
|
||||
accepted <- b
|
||||
}()
|
||||
|
||||
a, err := dialer.Dial(list.Multiaddr())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var b Conn
|
||||
select {
|
||||
case b = <-accepted:
|
||||
case err := <-errs:
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer a.Close()
|
||||
defer b.Close()
|
||||
|
||||
err = checkDataTransfer(a, b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func checkDataTransfer(a, b io.ReadWriter) error {
|
||||
errs := make(chan error, 2)
|
||||
data := []byte("this is some test data")
|
||||
|
||||
go func() {
|
||||
n, err := a.Write(data)
|
||||
if err != nil {
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
|
||||
if n != len(data) {
|
||||
errs <- fmt.Errorf("failed to write enough data (a->b)")
|
||||
return
|
||||
}
|
||||
|
||||
buf := make([]byte, len(data))
|
||||
_, err = io.ReadFull(a, buf)
|
||||
if err != nil {
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
|
||||
errs <- nil
|
||||
}()
|
||||
|
||||
go func() {
|
||||
buf := make([]byte, len(data))
|
||||
_, err := io.ReadFull(b, buf)
|
||||
if err != nil {
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
|
||||
n, err := b.Write(data)
|
||||
if err != nil {
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
|
||||
if n != len(data) {
|
||||
errs <- fmt.Errorf("failed to write enough data (b->a)")
|
||||
return
|
||||
}
|
||||
|
||||
errs <- nil
|
||||
}()
|
||||
|
||||
err := <-errs
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = <-errs
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
mafmt "gx/ipfs/QmWLfU4tstw2aNcTykDm44xbSTCYJ9pUJwfhQCKGwckcHx/mafmt"
|
||||
manet "gx/ipfs/QmYVqhVfbK4BKvbW88Lhm26b3ud14sTBvcm1H7uWUx1Fkp/go-multiaddr-net"
|
||||
mautp "gx/ipfs/QmYVqhVfbK4BKvbW88Lhm26b3ud14sTBvcm1H7uWUx1Fkp/go-multiaddr-net/utp"
|
||||
utp "gx/ipfs/QmadkZhaLw1AhXKyBiPmydRuTexhj6WkiZPpo5Uks6WUVq/utp"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
type UtpTransport struct {
|
||||
sockLock sync.Mutex
|
||||
sockets map[string]*UtpSocket
|
||||
}
|
||||
|
||||
func NewUtpTransport() *UtpTransport {
|
||||
return &UtpTransport{
|
||||
sockets: make(map[string]*UtpSocket),
|
||||
}
|
||||
}
|
||||
|
||||
func (d *UtpTransport) Matches(a ma.Multiaddr) bool {
|
||||
return mafmt.UTP.Matches(a)
|
||||
}
|
||||
|
||||
type UtpSocket struct {
|
||||
s *utp.Socket
|
||||
laddr ma.Multiaddr
|
||||
transport Transport
|
||||
}
|
||||
|
||||
func (t *UtpTransport) Listen(laddr ma.Multiaddr) (Listener, error) {
|
||||
t.sockLock.Lock()
|
||||
defer t.sockLock.Unlock()
|
||||
s, ok := t.sockets[laddr.String()]
|
||||
if ok {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
ns, err := t.newConn(laddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t.sockets[laddr.String()] = ns
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
func (t *UtpTransport) Dialer(laddr ma.Multiaddr, opts ...DialOpt) (Dialer, error) {
|
||||
t.sockLock.Lock()
|
||||
defer t.sockLock.Unlock()
|
||||
s, ok := t.sockets[laddr.String()]
|
||||
if ok {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
ns, err := t.newConn(laddr, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t.sockets[laddr.String()] = ns
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
func (t *UtpTransport) newConn(addr ma.Multiaddr, opts ...DialOpt) (*UtpSocket, error) {
|
||||
network, netaddr, err := manet.DialArgs(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s, err := utp.NewSocket("udp"+network[3:], netaddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
laddr, err := manet.FromNetAddr(mautp.MakeAddr(s.LocalAddr()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &UtpSocket{
|
||||
s: s,
|
||||
laddr: laddr,
|
||||
transport: t,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *UtpSocket) Dial(raddr ma.Multiaddr) (Conn, error) {
|
||||
_, addr, err := manet.DialArgs(raddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
con, err := s.s.Dial(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mnc, err := manet.WrapNetConn(&mautp.Conn{Conn: con})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &connWrap{
|
||||
Conn: mnc,
|
||||
transport: s.transport,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *UtpSocket) Accept() (Conn, error) {
|
||||
c, err := s.s.Accept()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mnc, err := manet.WrapNetConn(&mautp.Conn{Conn: c})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &connWrap{
|
||||
Conn: mnc,
|
||||
transport: s.transport,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *UtpSocket) Matches(a ma.Multiaddr) bool {
|
||||
return mafmt.UTP.Matches(a)
|
||||
}
|
||||
|
||||
func (t *UtpSocket) Close() error {
|
||||
return t.s.Close()
|
||||
}
|
||||
|
||||
func (t *UtpSocket) Addr() net.Addr {
|
||||
return t.s.Addr()
|
||||
}
|
||||
|
||||
func (t *UtpSocket) Multiaddr() ma.Multiaddr {
|
||||
return t.laddr
|
||||
}
|
||||
|
||||
var _ Transport = (*UtpTransport)(nil)
|
||||
@@ -1,70 +0,0 @@
|
||||
// Package addr provides utility functions to handle peer addresses.
|
||||
package addr
|
||||
|
||||
import (
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
// AddrSource is a source of addresses. It allows clients to retrieve
|
||||
// a set of addresses at a last possible moment in time. It is used
|
||||
// to query a set of addresses that may change over time, as a result
|
||||
// of the network changing interfaces or mappings.
|
||||
type Source interface {
|
||||
Addrs() []ma.Multiaddr
|
||||
}
|
||||
|
||||
// CombineSources returns a new AddrSource which is the
|
||||
// concatenation of all input AddrSources:
|
||||
//
|
||||
// combined := CombinedSources(a, b)
|
||||
// combined.Addrs() // append(a.Addrs(), b.Addrs()...)
|
||||
//
|
||||
func CombineSources(srcs ...Source) Source {
|
||||
return combinedAS(srcs)
|
||||
}
|
||||
|
||||
type combinedAS []Source
|
||||
|
||||
func (cas combinedAS) Addrs() []ma.Multiaddr {
|
||||
var addrs []ma.Multiaddr
|
||||
for _, s := range cas {
|
||||
addrs = append(addrs, s.Addrs()...)
|
||||
}
|
||||
return addrs
|
||||
}
|
||||
|
||||
// UniqueSource returns a new AddrSource which omits duplicate
|
||||
// addresses from the inputs:
|
||||
//
|
||||
// unique := UniqueSource(a, b)
|
||||
// unique.Addrs() // append(a.Addrs(), b.Addrs()...)
|
||||
// // but only adds each addr once.
|
||||
//
|
||||
func UniqueSource(srcs ...Source) Source {
|
||||
return uniqueAS(srcs)
|
||||
}
|
||||
|
||||
type uniqueAS []Source
|
||||
|
||||
func (uas uniqueAS) Addrs() []ma.Multiaddr {
|
||||
seen := make(map[string]struct{})
|
||||
var addrs []ma.Multiaddr
|
||||
for _, s := range uas {
|
||||
for _, a := range s.Addrs() {
|
||||
s := a.String()
|
||||
if _, found := seen[s]; !found {
|
||||
addrs = append(addrs, a)
|
||||
seen[s] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
return addrs
|
||||
}
|
||||
|
||||
// Slice is a simple slice of addresses that implements
|
||||
// the AddrSource interface.
|
||||
type Slice []ma.Multiaddr
|
||||
|
||||
func (as Slice) Addrs() []ma.Multiaddr {
|
||||
return as
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package addr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
func newAddrOrFatal(t *testing.T, s string) ma.Multiaddr {
|
||||
a, err := ma.NewMultiaddr(s)
|
||||
if err != nil {
|
||||
t.Fatal("error parsing multiaddr", err)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func newAddrs(t *testing.T, n int) []ma.Multiaddr {
|
||||
addrs := make([]ma.Multiaddr, n)
|
||||
for i := 0; i < n; i++ {
|
||||
s := fmt.Sprintf("/ip4/1.2.3.4/tcp/%d", i)
|
||||
addrs[i] = newAddrOrFatal(t, s)
|
||||
}
|
||||
return addrs
|
||||
}
|
||||
|
||||
func addrSetsSame(a, b []ma.Multiaddr) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, aa := range a {
|
||||
bb := b[i]
|
||||
if !aa.Equal(bb) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func addrSourcesSame(a, b Source) bool {
|
||||
return addrSetsSame(a.Addrs(), b.Addrs())
|
||||
}
|
||||
|
||||
func TestAddrCombine(t *testing.T) {
|
||||
addrs := newAddrs(t, 30)
|
||||
a := Slice(addrs[0:10])
|
||||
b := Slice(addrs[10:20])
|
||||
c := Slice(addrs[20:30])
|
||||
d := CombineSources(a, b, c)
|
||||
if !addrSetsSame(addrs, d.Addrs()) {
|
||||
t.Error("addrs differ")
|
||||
}
|
||||
if !addrSourcesSame(Slice(addrs), d) {
|
||||
t.Error("addrs differ")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddrUnique(t *testing.T) {
|
||||
|
||||
addrs := newAddrs(t, 40)
|
||||
a := Slice(addrs[0:20])
|
||||
b := Slice(addrs[10:30])
|
||||
c := Slice(addrs[20:40])
|
||||
d := CombineSources(a, b, c)
|
||||
e := UniqueSource(a, b, c)
|
||||
if addrSetsSame(addrs, d.Addrs()) {
|
||||
t.Error("addrs same")
|
||||
}
|
||||
if addrSourcesSame(Slice(addrs), d) {
|
||||
t.Error("addrs same")
|
||||
}
|
||||
if !addrSetsSame(addrs, e.Addrs()) {
|
||||
t.Error("addrs differ", addrs, "\n\n", e.Addrs(), "\n\n")
|
||||
}
|
||||
if !addrSourcesSame(Slice(addrs), e) {
|
||||
t.Error("addrs differ", addrs, "\n\n", e.Addrs(), "\n\n")
|
||||
}
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
// TempAddrTTL is the ttl used for a short lived address
|
||||
TempAddrTTL = time.Second * 10
|
||||
|
||||
// ProviderAddrTTL is the TTL of an address we've received from a provider.
|
||||
// This is also a temporary address, but lasts longer. After this expires,
|
||||
// the records we return will require an extra lookup.
|
||||
ProviderAddrTTL = time.Minute * 10
|
||||
|
||||
// RecentlyConnectedAddrTTL is used when we recently connected to a peer.
|
||||
// It means that we are reasonably certain of the peer's address.
|
||||
RecentlyConnectedAddrTTL = time.Minute * 10
|
||||
|
||||
// OwnObservedAddrTTL is used for our own external addresses observed by peers.
|
||||
OwnObservedAddrTTL = time.Minute * 10
|
||||
|
||||
// PermanentAddrTTL is the ttl for a "permanent address" (e.g. bootstrap nodes)
|
||||
// if we haven't shipped you an update to ipfs in 356 days
|
||||
// we probably arent running the same bootstrap nodes...
|
||||
PermanentAddrTTL = time.Hour * 24 * 356
|
||||
|
||||
// ConnectedAddrTTL is the ttl used for the addresses of a peer to whom
|
||||
// we're connected directly. This is basically permanent, as we will
|
||||
// clear them + re-add under a TempAddrTTL after disconnecting.
|
||||
ConnectedAddrTTL = PermanentAddrTTL
|
||||
)
|
||||
|
||||
type expiringAddr struct {
|
||||
Addr ma.Multiaddr
|
||||
TTL time.Time
|
||||
}
|
||||
|
||||
func (e *expiringAddr) ExpiredBy(t time.Time) bool {
|
||||
return t.After(e.TTL)
|
||||
}
|
||||
|
||||
type addrSet map[string]expiringAddr
|
||||
|
||||
// AddrManager manages addresses.
|
||||
// The zero-value is ready to be used.
|
||||
type AddrManager struct {
|
||||
addrmu sync.Mutex // guards addrs
|
||||
addrs map[ID]addrSet
|
||||
}
|
||||
|
||||
// ensures the AddrManager is initialized.
|
||||
// So we can use the zero value.
|
||||
func (mgr *AddrManager) init() {
|
||||
if mgr.addrs == nil {
|
||||
mgr.addrs = make(map[ID]addrSet)
|
||||
}
|
||||
}
|
||||
|
||||
func (mgr *AddrManager) Peers() []ID {
|
||||
mgr.addrmu.Lock()
|
||||
defer mgr.addrmu.Unlock()
|
||||
if mgr.addrs == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
pids := make([]ID, 0, len(mgr.addrs))
|
||||
for pid := range mgr.addrs {
|
||||
pids = append(pids, pid)
|
||||
}
|
||||
return pids
|
||||
}
|
||||
|
||||
// AddAddr calls AddAddrs(p, []ma.Multiaddr{addr}, ttl)
|
||||
func (mgr *AddrManager) AddAddr(p ID, addr ma.Multiaddr, ttl time.Duration) {
|
||||
mgr.AddAddrs(p, []ma.Multiaddr{addr}, ttl)
|
||||
}
|
||||
|
||||
// AddAddrs gives AddrManager addresses to use, with a given ttl
|
||||
// (time-to-live), after which the address is no longer valid.
|
||||
// If the manager has a longer TTL, the operation is a no-op for that address
|
||||
func (mgr *AddrManager) AddAddrs(p ID, addrs []ma.Multiaddr, ttl time.Duration) {
|
||||
mgr.addrmu.Lock()
|
||||
defer mgr.addrmu.Unlock()
|
||||
|
||||
// if ttl is zero, exit. nothing to do.
|
||||
if ttl <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// so zero value can be used
|
||||
mgr.init()
|
||||
|
||||
amap, found := mgr.addrs[p]
|
||||
if !found {
|
||||
amap = make(addrSet)
|
||||
mgr.addrs[p] = amap
|
||||
}
|
||||
|
||||
// only expand ttls
|
||||
exp := time.Now().Add(ttl)
|
||||
for _, addr := range addrs {
|
||||
addrstr := addr.String()
|
||||
a, found := amap[addrstr]
|
||||
if !found || exp.After(a.TTL) {
|
||||
amap[addrstr] = expiringAddr{Addr: addr, TTL: exp}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetAddr calls mgr.SetAddrs(p, addr, ttl)
|
||||
func (mgr *AddrManager) SetAddr(p ID, addr ma.Multiaddr, ttl time.Duration) {
|
||||
mgr.SetAddrs(p, []ma.Multiaddr{addr}, ttl)
|
||||
}
|
||||
|
||||
// SetAddrs sets the ttl on addresses. This clears any TTL there previously.
|
||||
// This is used when we receive the best estimate of the validity of an address.
|
||||
func (mgr *AddrManager) SetAddrs(p ID, addrs []ma.Multiaddr, ttl time.Duration) {
|
||||
mgr.addrmu.Lock()
|
||||
defer mgr.addrmu.Unlock()
|
||||
|
||||
// so zero value can be used
|
||||
mgr.init()
|
||||
|
||||
amap, found := mgr.addrs[p]
|
||||
if !found {
|
||||
amap = make(addrSet)
|
||||
mgr.addrs[p] = amap
|
||||
}
|
||||
|
||||
exp := time.Now().Add(ttl)
|
||||
for _, addr := range addrs {
|
||||
// re-set all of them for new ttl.
|
||||
addrs := addr.String()
|
||||
|
||||
if ttl > 0 {
|
||||
amap[addrs] = expiringAddr{Addr: addr, TTL: exp}
|
||||
} else {
|
||||
delete(amap, addrs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Addresses returns all known (and valid) addresses for a given
|
||||
func (mgr *AddrManager) Addrs(p ID) []ma.Multiaddr {
|
||||
mgr.addrmu.Lock()
|
||||
defer mgr.addrmu.Unlock()
|
||||
|
||||
// not initialized? nothing to give.
|
||||
if mgr.addrs == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
maddrs, found := mgr.addrs[p]
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
good := make([]ma.Multiaddr, 0, len(maddrs))
|
||||
var expired []string
|
||||
for s, m := range maddrs {
|
||||
if m.ExpiredBy(now) {
|
||||
expired = append(expired, s)
|
||||
} else {
|
||||
good = append(good, m.Addr)
|
||||
}
|
||||
}
|
||||
|
||||
// clean up the expired ones.
|
||||
for _, s := range expired {
|
||||
delete(maddrs, s)
|
||||
}
|
||||
return good
|
||||
}
|
||||
|
||||
// ClearAddresses removes all previously stored addresses
|
||||
func (mgr *AddrManager) ClearAddrs(p ID) {
|
||||
mgr.addrmu.Lock()
|
||||
defer mgr.addrmu.Unlock()
|
||||
mgr.init()
|
||||
|
||||
mgr.addrs[p] = make(addrSet) // clear what was there before
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
func IDS(t *testing.T, ids string) ID {
|
||||
id, err := IDB58Decode(ids)
|
||||
if err != nil {
|
||||
t.Fatalf("id %q is bad: %s", ids, err)
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
func MA(t *testing.T, m string) ma.Multiaddr {
|
||||
maddr, err := ma.NewMultiaddr(m)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return maddr
|
||||
}
|
||||
|
||||
func testHas(t *testing.T, exp, act []ma.Multiaddr) {
|
||||
if len(exp) != len(act) {
|
||||
t.Fatal("lengths not the same")
|
||||
}
|
||||
|
||||
for _, a := range exp {
|
||||
found := false
|
||||
|
||||
for _, b := range act {
|
||||
if a.Equal(b) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Fatal("expected address %s not found", a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddresses(t *testing.T) {
|
||||
|
||||
id1 := IDS(t, "QmcNstKuwBBoVTpSCSDrwzjgrRcaYXK833Psuz2EMHwyQN")
|
||||
id2 := IDS(t, "QmRmPL3FDZKE3Qiwv1RosLdwdvbvg17b2hB39QPScgWKKZ")
|
||||
id3 := IDS(t, "QmPhi7vBsChP7sjRoZGgg7bcKqF6MmCcQwvRbDte8aJ6Kn")
|
||||
id4 := IDS(t, "QmPhi7vBsChP7sjRoZGgg7bcKqF6MmCcQwvRbDte8aJ5Kn")
|
||||
id5 := IDS(t, "QmPhi7vBsChP7sjRoZGgg7bcKqF6MmCcQwvRbDte8aJ5Km")
|
||||
|
||||
ma11 := MA(t, "/ip4/1.2.3.1/tcp/1111")
|
||||
ma21 := MA(t, "/ip4/2.2.3.2/tcp/1111")
|
||||
ma22 := MA(t, "/ip4/2.2.3.2/tcp/2222")
|
||||
ma31 := MA(t, "/ip4/3.2.3.3/tcp/1111")
|
||||
ma32 := MA(t, "/ip4/3.2.3.3/tcp/2222")
|
||||
ma33 := MA(t, "/ip4/3.2.3.3/tcp/3333")
|
||||
ma41 := MA(t, "/ip4/4.2.3.3/tcp/1111")
|
||||
ma42 := MA(t, "/ip4/4.2.3.3/tcp/2222")
|
||||
ma43 := MA(t, "/ip4/4.2.3.3/tcp/3333")
|
||||
ma44 := MA(t, "/ip4/4.2.3.3/tcp/4444")
|
||||
ma51 := MA(t, "/ip4/5.2.3.3/tcp/1111")
|
||||
ma52 := MA(t, "/ip4/5.2.3.3/tcp/2222")
|
||||
ma53 := MA(t, "/ip4/5.2.3.3/tcp/3333")
|
||||
ma54 := MA(t, "/ip4/5.2.3.3/tcp/4444")
|
||||
ma55 := MA(t, "/ip4/5.2.3.3/tcp/5555")
|
||||
|
||||
ttl := time.Hour
|
||||
m := AddrManager{}
|
||||
m.AddAddr(id1, ma11, ttl)
|
||||
|
||||
m.AddAddrs(id2, []ma.Multiaddr{ma21, ma22}, ttl)
|
||||
m.AddAddrs(id2, []ma.Multiaddr{ma21, ma22}, ttl) // idempotency
|
||||
|
||||
m.AddAddr(id3, ma31, ttl)
|
||||
m.AddAddr(id3, ma32, ttl)
|
||||
m.AddAddr(id3, ma33, ttl)
|
||||
m.AddAddr(id3, ma33, ttl) // idempotency
|
||||
m.AddAddr(id3, ma33, ttl)
|
||||
|
||||
m.AddAddrs(id4, []ma.Multiaddr{ma41, ma42, ma43, ma44}, ttl) // multiple
|
||||
|
||||
m.AddAddrs(id5, []ma.Multiaddr{ma21, ma22}, ttl) // clearing
|
||||
m.AddAddrs(id5, []ma.Multiaddr{ma41, ma42, ma43, ma44}, ttl) // clearing
|
||||
m.ClearAddrs(id5)
|
||||
m.AddAddrs(id5, []ma.Multiaddr{ma51, ma52, ma53, ma54, ma55}, ttl) // clearing
|
||||
|
||||
// test the Addresses return value
|
||||
testHas(t, []ma.Multiaddr{ma11}, m.Addrs(id1))
|
||||
testHas(t, []ma.Multiaddr{ma21, ma22}, m.Addrs(id2))
|
||||
testHas(t, []ma.Multiaddr{ma31, ma32, ma33}, m.Addrs(id3))
|
||||
testHas(t, []ma.Multiaddr{ma41, ma42, ma43, ma44}, m.Addrs(id4))
|
||||
testHas(t, []ma.Multiaddr{ma51, ma52, ma53, ma54, ma55}, m.Addrs(id5))
|
||||
|
||||
}
|
||||
|
||||
func TestAddressesExpire(t *testing.T) {
|
||||
|
||||
id1 := IDS(t, "QmcNstKuwBBoVTpSCSDrwzjgrRcaYXK833Psuz2EMHwyQN")
|
||||
id2 := IDS(t, "QmcNstKuwBBoVTpSCSDrwzjgrRcaYXK833Psuz2EMHwyQM")
|
||||
ma11 := MA(t, "/ip4/1.2.3.1/tcp/1111")
|
||||
ma12 := MA(t, "/ip4/2.2.3.2/tcp/2222")
|
||||
ma13 := MA(t, "/ip4/3.2.3.3/tcp/3333")
|
||||
ma24 := MA(t, "/ip4/4.2.3.3/tcp/4444")
|
||||
ma25 := MA(t, "/ip4/5.2.3.3/tcp/5555")
|
||||
|
||||
m := AddrManager{}
|
||||
m.AddAddr(id1, ma11, time.Hour)
|
||||
m.AddAddr(id1, ma12, time.Hour)
|
||||
m.AddAddr(id1, ma13, time.Hour)
|
||||
m.AddAddr(id2, ma24, time.Hour)
|
||||
m.AddAddr(id2, ma25, time.Hour)
|
||||
|
||||
testHas(t, []ma.Multiaddr{ma11, ma12, ma13}, m.Addrs(id1))
|
||||
testHas(t, []ma.Multiaddr{ma24, ma25}, m.Addrs(id2))
|
||||
|
||||
m.SetAddr(id1, ma11, 2*time.Hour)
|
||||
m.SetAddr(id1, ma12, 2*time.Hour)
|
||||
m.SetAddr(id1, ma13, 2*time.Hour)
|
||||
m.SetAddr(id2, ma24, 2*time.Hour)
|
||||
m.SetAddr(id2, ma25, 2*time.Hour)
|
||||
|
||||
testHas(t, []ma.Multiaddr{ma11, ma12, ma13}, m.Addrs(id1))
|
||||
testHas(t, []ma.Multiaddr{ma24, ma25}, m.Addrs(id2))
|
||||
|
||||
m.SetAddr(id1, ma11, time.Millisecond)
|
||||
<-time.After(time.Millisecond)
|
||||
testHas(t, []ma.Multiaddr{ma12, ma13}, m.Addrs(id1))
|
||||
testHas(t, []ma.Multiaddr{ma24, ma25}, m.Addrs(id2))
|
||||
|
||||
m.SetAddr(id1, ma13, time.Millisecond)
|
||||
<-time.After(time.Millisecond)
|
||||
testHas(t, []ma.Multiaddr{ma12}, m.Addrs(id1))
|
||||
testHas(t, []ma.Multiaddr{ma24, ma25}, m.Addrs(id2))
|
||||
|
||||
m.SetAddr(id2, ma24, time.Millisecond)
|
||||
<-time.After(time.Millisecond)
|
||||
testHas(t, []ma.Multiaddr{ma12}, m.Addrs(id1))
|
||||
testHas(t, []ma.Multiaddr{ma25}, m.Addrs(id2))
|
||||
|
||||
m.SetAddr(id2, ma25, time.Millisecond)
|
||||
<-time.After(time.Millisecond)
|
||||
testHas(t, []ma.Multiaddr{ma12}, m.Addrs(id1))
|
||||
testHas(t, nil, m.Addrs(id2))
|
||||
|
||||
m.SetAddr(id1, ma12, time.Millisecond)
|
||||
<-time.After(time.Millisecond)
|
||||
testHas(t, nil, m.Addrs(id1))
|
||||
testHas(t, nil, m.Addrs(id2))
|
||||
}
|
||||
|
||||
func TestClearWorks(t *testing.T) {
|
||||
|
||||
id1 := IDS(t, "QmcNstKuwBBoVTpSCSDrwzjgrRcaYXK833Psuz2EMHwyQN")
|
||||
id2 := IDS(t, "QmcNstKuwBBoVTpSCSDrwzjgrRcaYXK833Psuz2EMHwyQM")
|
||||
ma11 := MA(t, "/ip4/1.2.3.1/tcp/1111")
|
||||
ma12 := MA(t, "/ip4/2.2.3.2/tcp/2222")
|
||||
ma13 := MA(t, "/ip4/3.2.3.3/tcp/3333")
|
||||
ma24 := MA(t, "/ip4/4.2.3.3/tcp/4444")
|
||||
ma25 := MA(t, "/ip4/5.2.3.3/tcp/5555")
|
||||
|
||||
m := AddrManager{}
|
||||
m.AddAddr(id1, ma11, time.Hour)
|
||||
m.AddAddr(id1, ma12, time.Hour)
|
||||
m.AddAddr(id1, ma13, time.Hour)
|
||||
m.AddAddr(id2, ma24, time.Hour)
|
||||
m.AddAddr(id2, ma25, time.Hour)
|
||||
|
||||
testHas(t, []ma.Multiaddr{ma11, ma12, ma13}, m.Addrs(id1))
|
||||
testHas(t, []ma.Multiaddr{ma24, ma25}, m.Addrs(id2))
|
||||
|
||||
m.ClearAddrs(id1)
|
||||
m.ClearAddrs(id2)
|
||||
|
||||
testHas(t, nil, m.Addrs(id1))
|
||||
testHas(t, nil, m.Addrs(id2))
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// LatencyEWMASmooting governs the decay of the EWMA (the speed
|
||||
// at which it changes). This must be a normalized (0-1) value.
|
||||
// 1 is 100% change, 0 is no change.
|
||||
var LatencyEWMASmoothing = 0.1
|
||||
|
||||
// Metrics is just an object that tracks metrics
|
||||
// across a set of peers.
|
||||
type Metrics interface {
|
||||
|
||||
// RecordLatency records a new latency measurement
|
||||
RecordLatency(ID, time.Duration)
|
||||
|
||||
// LatencyEWMA returns an exponentially-weighted moving avg.
|
||||
// of all measurements of a peer's latency.
|
||||
LatencyEWMA(ID) time.Duration
|
||||
}
|
||||
|
||||
type metrics struct {
|
||||
latmap map[ID]time.Duration
|
||||
latmu sync.RWMutex
|
||||
}
|
||||
|
||||
func NewMetrics() Metrics {
|
||||
return &metrics{
|
||||
latmap: make(map[ID]time.Duration),
|
||||
}
|
||||
}
|
||||
|
||||
// RecordLatency records a new latency measurement
|
||||
func (m *metrics) RecordLatency(p ID, next time.Duration) {
|
||||
nextf := float64(next)
|
||||
s := LatencyEWMASmoothing
|
||||
if s > 1 || s < 0 {
|
||||
s = 0.1 // ignore the knob. it's broken. look, it jiggles.
|
||||
}
|
||||
|
||||
m.latmu.Lock()
|
||||
ewma, found := m.latmap[p]
|
||||
ewmaf := float64(ewma)
|
||||
if !found {
|
||||
m.latmap[p] = next // when no data, just take it as the mean.
|
||||
} else {
|
||||
nextf = ((1.0 - s) * ewmaf) + (s * nextf)
|
||||
m.latmap[p] = time.Duration(nextf)
|
||||
}
|
||||
m.latmu.Unlock()
|
||||
}
|
||||
|
||||
// LatencyEWMA returns an exponentially-weighted moving avg.
|
||||
// of all measurements of a peer's latency.
|
||||
func (m *metrics) LatencyEWMA(p ID) time.Duration {
|
||||
m.latmu.RLock()
|
||||
lat := m.latmap[p]
|
||||
m.latmu.RUnlock()
|
||||
return time.Duration(lat)
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package peer_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
testutil "github.com/ipfs/go-libp2p/testutil"
|
||||
)
|
||||
|
||||
func TestLatencyEWMAFun(t *testing.T) {
|
||||
t.Skip("run it for fun")
|
||||
|
||||
m := peer.NewMetrics()
|
||||
id, err := testutil.RandPeerID()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mu := 100.0
|
||||
sig := 10.0
|
||||
next := func() time.Duration {
|
||||
mu = (rand.NormFloat64() * sig) + mu
|
||||
return time.Duration(mu)
|
||||
}
|
||||
|
||||
print := func() {
|
||||
fmt.Printf("%3.f %3.f --> %d\n", sig, mu, m.LatencyEWMA(id))
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-time.After(200 * time.Millisecond):
|
||||
m.RecordLatency(id, next())
|
||||
print()
|
||||
}
|
||||
}
|
||||
}
|
||||
185
p2p/peer/peer.go
185
p2p/peer/peer.go
@@ -1,185 +0,0 @@
|
||||
// package peer implements an object used to represent peers in the ipfs network.
|
||||
package peer
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
ic "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
b58 "gx/ipfs/QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf/go-base58"
|
||||
mh "gx/ipfs/QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku/go-multihash"
|
||||
u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
|
||||
logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" // ID represents the identity of a peer.
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
var log = logging.Logger("peer")
|
||||
|
||||
type ID string
|
||||
|
||||
// Pretty returns a b58-encoded string of the ID
|
||||
func (id ID) Pretty() string {
|
||||
return IDB58Encode(id)
|
||||
}
|
||||
|
||||
func (id ID) Loggable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"peerID": id.Pretty(),
|
||||
}
|
||||
}
|
||||
|
||||
// String prints out the peer.
|
||||
//
|
||||
// TODO(brian): ensure correctness at ID generation and
|
||||
// enforce this by only exposing functions that generate
|
||||
// IDs safely. Then any peer.ID type found in the
|
||||
// codebase is known to be correct.
|
||||
func (id ID) String() string {
|
||||
pid := id.Pretty()
|
||||
|
||||
//All sha256 nodes start with Qm
|
||||
//We can skip the Qm to make the peer.ID more useful
|
||||
if strings.HasPrefix(pid, "Qm") {
|
||||
pid = pid[2:]
|
||||
}
|
||||
|
||||
maxRunes := 6
|
||||
if len(pid) < maxRunes {
|
||||
maxRunes = len(pid)
|
||||
}
|
||||
return fmt.Sprintf("<peer.ID %s>", pid[:maxRunes])
|
||||
}
|
||||
|
||||
// MatchesPrivateKey tests whether this ID was derived from sk
|
||||
func (id ID) MatchesPrivateKey(sk ic.PrivKey) bool {
|
||||
return id.MatchesPublicKey(sk.GetPublic())
|
||||
}
|
||||
|
||||
// MatchesPublicKey tests whether this ID was derived from pk
|
||||
func (id ID) MatchesPublicKey(pk ic.PubKey) bool {
|
||||
oid, err := IDFromPublicKey(pk)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return oid == id
|
||||
}
|
||||
|
||||
// IDFromString cast a string to ID type, and validate
|
||||
// the id to make sure it is a multihash.
|
||||
func IDFromString(s string) (ID, error) {
|
||||
if _, err := mh.Cast([]byte(s)); err != nil {
|
||||
return ID(""), err
|
||||
}
|
||||
return ID(s), nil
|
||||
}
|
||||
|
||||
// IDFromBytes cast a string to ID type, and validate
|
||||
// the id to make sure it is a multihash.
|
||||
func IDFromBytes(b []byte) (ID, error) {
|
||||
if _, err := mh.Cast(b); err != nil {
|
||||
return ID(""), err
|
||||
}
|
||||
return ID(b), nil
|
||||
}
|
||||
|
||||
// IDB58Decode returns a b58-decoded Peer
|
||||
func IDB58Decode(s string) (ID, error) {
|
||||
m, err := mh.FromB58String(s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ID(m), err
|
||||
}
|
||||
|
||||
// IDB58Encode returns b58-encoded string
|
||||
func IDB58Encode(id ID) string {
|
||||
return b58.Encode([]byte(id))
|
||||
}
|
||||
|
||||
// IDHexDecode returns a b58-decoded Peer
|
||||
func IDHexDecode(s string) (ID, error) {
|
||||
m, err := mh.FromHexString(s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ID(m), err
|
||||
}
|
||||
|
||||
// IDHexEncode returns b58-encoded string
|
||||
func IDHexEncode(id ID) string {
|
||||
return hex.EncodeToString([]byte(id))
|
||||
}
|
||||
|
||||
// IDFromPublicKey returns the Peer ID corresponding to pk
|
||||
func IDFromPublicKey(pk ic.PubKey) (ID, error) {
|
||||
b, err := pk.Bytes()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
hash := u.Hash(b)
|
||||
return ID(hash), nil
|
||||
}
|
||||
|
||||
// IDFromPrivateKey returns the Peer ID corresponding to sk
|
||||
func IDFromPrivateKey(sk ic.PrivKey) (ID, error) {
|
||||
return IDFromPublicKey(sk.GetPublic())
|
||||
}
|
||||
|
||||
// Map maps a Peer ID to a struct.
|
||||
type Set map[ID]struct{}
|
||||
|
||||
// PeerInfo is a small struct used to pass around a peer with
|
||||
// a set of addresses (and later, 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.
|
||||
type PeerInfo struct {
|
||||
ID ID
|
||||
Addrs []ma.Multiaddr
|
||||
}
|
||||
|
||||
func (pi *PeerInfo) Loggable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"peerID": pi.ID.Pretty(),
|
||||
"addrs": pi.Addrs,
|
||||
}
|
||||
}
|
||||
|
||||
func (pi *PeerInfo) MarshalJSON() ([]byte, error) {
|
||||
out := make(map[string]interface{})
|
||||
out["ID"] = IDB58Encode(pi.ID)
|
||||
var addrs []string
|
||||
for _, a := range pi.Addrs {
|
||||
addrs = append(addrs, a.String())
|
||||
}
|
||||
out["Addrs"] = addrs
|
||||
return json.Marshal(out)
|
||||
}
|
||||
|
||||
func (pi *PeerInfo) UnmarshalJSON(b []byte) error {
|
||||
var data map[string]interface{}
|
||||
err := json.Unmarshal(b, &data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pid, err := IDB58Decode(data["ID"].(string))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pi.ID = pid
|
||||
addrs, ok := data["Addrs"].([]interface{})
|
||||
if ok {
|
||||
for _, a := range addrs {
|
||||
pi.Addrs = append(pi.Addrs, ma.StringCast(a.(string)))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IDSlice for sorting peers
|
||||
type IDSlice []ID
|
||||
|
||||
func (es IDSlice) Len() int { return len(es) }
|
||||
func (es IDSlice) Swap(i, j int) { es[i], es[j] = es[j], es[i] }
|
||||
func (es IDSlice) Less(i, j int) bool { return string(es[i]) < string(es[j]) }
|
||||
@@ -1,163 +0,0 @@
|
||||
package peer_test
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
ic "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
. "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
tu "github.com/ipfs/go-libp2p/testutil"
|
||||
u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
|
||||
|
||||
b58 "gx/ipfs/QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf/go-base58"
|
||||
)
|
||||
|
||||
var gen1 keyset // generated
|
||||
var gen2 keyset // generated
|
||||
var man keyset // manual
|
||||
|
||||
func init() {
|
||||
if err := gen1.generate(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := gen2.generate(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
skManBytes = strings.Replace(skManBytes, "\n", "", -1)
|
||||
if err := man.load(hpkpMan, skManBytes); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
type keyset struct {
|
||||
sk ic.PrivKey
|
||||
pk ic.PubKey
|
||||
hpk string
|
||||
hpkp string
|
||||
}
|
||||
|
||||
func (ks *keyset) generate() error {
|
||||
var err error
|
||||
ks.sk, ks.pk, err = tu.RandTestKeyPair(512)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bpk, err := ks.pk.Bytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ks.hpk = string(u.Hash(bpk))
|
||||
ks.hpkp = b58.Encode([]byte(ks.hpk))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ks *keyset) load(hpkp, skBytesStr string) error {
|
||||
skBytes, err := base64.StdEncoding.DecodeString(skBytesStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ks.sk, err = ic.UnmarshalPrivateKey(skBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ks.pk = ks.sk.GetPublic()
|
||||
bpk, err := ks.pk.Bytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ks.hpk = string(u.Hash(bpk))
|
||||
ks.hpkp = b58.Encode([]byte(ks.hpk))
|
||||
if ks.hpkp != hpkp {
|
||||
return fmt.Errorf("hpkp doesn't match key. %s", hpkp)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestIDMatchesPublicKey(t *testing.T) {
|
||||
|
||||
test := func(ks keyset) {
|
||||
p1, err := IDB58Decode(ks.hpkp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ks.hpk != string(p1) {
|
||||
t.Error("p1 and hpk differ")
|
||||
}
|
||||
|
||||
if !p1.MatchesPublicKey(ks.pk) {
|
||||
t.Fatal("p1 does not match pk")
|
||||
}
|
||||
|
||||
p2, err := IDFromPublicKey(ks.pk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if p1 != p2 {
|
||||
t.Error("p1 and p2 differ", p1.Pretty(), p2.Pretty())
|
||||
}
|
||||
|
||||
if p2.Pretty() != ks.hpkp {
|
||||
t.Error("hpkp and p2.Pretty differ", ks.hpkp, p2.Pretty())
|
||||
}
|
||||
}
|
||||
|
||||
test(gen1)
|
||||
test(gen2)
|
||||
test(man)
|
||||
}
|
||||
|
||||
func TestIDMatchesPrivateKey(t *testing.T) {
|
||||
|
||||
test := func(ks keyset) {
|
||||
p1, err := IDB58Decode(ks.hpkp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ks.hpk != string(p1) {
|
||||
t.Error("p1 and hpk differ")
|
||||
}
|
||||
|
||||
if !p1.MatchesPrivateKey(ks.sk) {
|
||||
t.Fatal("p1 does not match sk")
|
||||
}
|
||||
|
||||
p2, err := IDFromPrivateKey(ks.sk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if p1 != p2 {
|
||||
t.Error("p1 and p2 differ", p1.Pretty(), p2.Pretty())
|
||||
}
|
||||
}
|
||||
|
||||
test(gen1)
|
||||
test(gen2)
|
||||
test(man)
|
||||
}
|
||||
|
||||
var hpkpMan = `QmRK3JgmVEGiewxWbhpXLJyjWuGuLeSTMTndA1coMHEy5o`
|
||||
var skManBytes = `
|
||||
CAAS4AQwggJcAgEAAoGBAL7w+Wc4VhZhCdM/+Hccg5Nrf4q9NXWwJylbSrXz/unFS24wyk6pEk0zi3W
|
||||
7li+vSNVO+NtJQw9qGNAMtQKjVTP+3Vt/jfQRnQM3s6awojtjueEWuLYVt62z7mofOhCtj+VwIdZNBo
|
||||
/EkLZ0ETfcvN5LVtLYa8JkXybnOPsLvK+PAgMBAAECgYBdk09HDM7zzL657uHfzfOVrdslrTCj6p5mo
|
||||
DzvCxLkkjIzYGnlPuqfNyGjozkpSWgSUc+X+EGLLl3WqEOVdWJtbM61fewEHlRTM5JzScvwrJ39t7o6
|
||||
CCAjKA0cBWBd6UWgbN/t53RoWvh9HrA2AW5YrT0ZiAgKe9y7EMUaENVJ8QJBAPhpdmb4ZL4Fkm4OKia
|
||||
NEcjzn6mGTlZtef7K/0oRC9+2JkQnCuf6HBpaRhJoCJYg7DW8ZY+AV6xClKrgjBOfERMCQQDExhnzu2
|
||||
dsQ9k8QChBlpHO0TRbZBiQfC70oU31kM1AeLseZRmrxv9Yxzdl8D693NNWS2JbKOXl0kMHHcuGQLMVA
|
||||
kBZ7WvkmPV3aPL6jnwp2pXepntdVnaTiSxJ1dkXShZ/VSSDNZMYKY306EtHrIu3NZHtXhdyHKcggDXr
|
||||
qkBrdgErAkAlpGPojUwemOggr4FD8sLX1ot2hDJyyV7OK2FXfajWEYJyMRL1Gm9Uk1+Un53RAkJneqp
|
||||
JGAzKpyttXBTIDO51AkEA98KTiROMnnU8Y6Mgcvr68/SMIsvCYMt9/mtwSBGgl80VaTQ5Hpaktl6Xbh
|
||||
VUt5Wv0tRxlXZiViCGCD1EtrrwTw==
|
||||
`
|
||||
@@ -1,232 +0,0 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
ic "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
|
||||
//ds "github.com/jbenet/go-datastore"
|
||||
//dssync "github.com/jbenet/go-datastore/sync"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
const (
|
||||
// AddressTTL is the expiration time of addresses.
|
||||
AddressTTL = time.Hour
|
||||
)
|
||||
|
||||
// Peerstore provides a threadsafe store of Peer related
|
||||
// information.
|
||||
type Peerstore interface {
|
||||
AddrBook
|
||||
KeyBook
|
||||
Metrics
|
||||
|
||||
// Peers returns a list of all peer.IDs in this Peerstore
|
||||
Peers() []ID
|
||||
|
||||
// PeerInfo returns a peer.PeerInfo struct for given peer.ID.
|
||||
// This is a small slice of the information Peerstore has on
|
||||
// that peer, useful to other services.
|
||||
PeerInfo(ID) PeerInfo
|
||||
|
||||
// Get/Put is a simple registry for other peer-related key/value pairs.
|
||||
// if we find something we use often, it should become its own set of
|
||||
// methods. this is a last resort.
|
||||
Get(id ID, key string) (interface{}, error)
|
||||
Put(id ID, key string, val interface{}) error
|
||||
}
|
||||
|
||||
// AddrBook is an interface that fits the new AddrManager. I'm patching
|
||||
// it up in here to avoid changing a ton of the codebase.
|
||||
type AddrBook interface {
|
||||
|
||||
// AddAddr calls AddAddrs(p, []ma.Multiaddr{addr}, ttl)
|
||||
AddAddr(p ID, addr ma.Multiaddr, ttl time.Duration)
|
||||
|
||||
// AddAddrs gives AddrManager addresses to use, with a given ttl
|
||||
// (time-to-live), after which the address is no longer valid.
|
||||
// If the manager has a longer TTL, the operation is a no-op for that address
|
||||
AddAddrs(p ID, addrs []ma.Multiaddr, ttl time.Duration)
|
||||
|
||||
// SetAddr calls mgr.SetAddrs(p, addr, ttl)
|
||||
SetAddr(p ID, addr ma.Multiaddr, ttl time.Duration)
|
||||
|
||||
// SetAddrs sets the ttl on addresses. This clears any TTL there previously.
|
||||
// This is used when we receive the best estimate of the validity of an address.
|
||||
SetAddrs(p ID, addrs []ma.Multiaddr, ttl time.Duration)
|
||||
|
||||
// Addresses returns all known (and valid) addresses for a given
|
||||
Addrs(p ID) []ma.Multiaddr
|
||||
|
||||
// ClearAddresses removes all previously stored addresses
|
||||
ClearAddrs(p ID)
|
||||
}
|
||||
|
||||
// KeyBook tracks the Public keys of Peers.
|
||||
type KeyBook interface {
|
||||
PubKey(ID) ic.PubKey
|
||||
AddPubKey(ID, ic.PubKey) error
|
||||
|
||||
PrivKey(ID) ic.PrivKey
|
||||
AddPrivKey(ID, ic.PrivKey) error
|
||||
}
|
||||
|
||||
type keybook struct {
|
||||
pks map[ID]ic.PubKey
|
||||
sks map[ID]ic.PrivKey
|
||||
|
||||
sync.RWMutex // same lock. wont happen a ton.
|
||||
}
|
||||
|
||||
func newKeybook() *keybook {
|
||||
return &keybook{
|
||||
pks: map[ID]ic.PubKey{},
|
||||
sks: map[ID]ic.PrivKey{},
|
||||
}
|
||||
}
|
||||
|
||||
func (kb *keybook) Peers() []ID {
|
||||
kb.RLock()
|
||||
ps := make([]ID, 0, len(kb.pks)+len(kb.sks))
|
||||
for p := range kb.pks {
|
||||
ps = append(ps, p)
|
||||
}
|
||||
for p := range kb.sks {
|
||||
if _, found := kb.pks[p]; !found {
|
||||
ps = append(ps, p)
|
||||
}
|
||||
}
|
||||
kb.RUnlock()
|
||||
return ps
|
||||
}
|
||||
|
||||
func (kb *keybook) PubKey(p ID) ic.PubKey {
|
||||
kb.RLock()
|
||||
pk := kb.pks[p]
|
||||
kb.RUnlock()
|
||||
return pk
|
||||
}
|
||||
|
||||
func (kb *keybook) AddPubKey(p ID, pk ic.PubKey) error {
|
||||
|
||||
// check it's correct first
|
||||
if !p.MatchesPublicKey(pk) {
|
||||
return errors.New("ID does not match PublicKey")
|
||||
}
|
||||
|
||||
kb.Lock()
|
||||
kb.pks[p] = pk
|
||||
kb.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (kb *keybook) PrivKey(p ID) ic.PrivKey {
|
||||
kb.RLock()
|
||||
sk := kb.sks[p]
|
||||
kb.RUnlock()
|
||||
return sk
|
||||
}
|
||||
|
||||
func (kb *keybook) AddPrivKey(p ID, sk ic.PrivKey) error {
|
||||
|
||||
if sk == nil {
|
||||
return errors.New("sk is nil (PrivKey)")
|
||||
}
|
||||
|
||||
// check it's correct first
|
||||
if !p.MatchesPrivateKey(sk) {
|
||||
return errors.New("ID does not match PrivateKey")
|
||||
}
|
||||
|
||||
kb.Lock()
|
||||
kb.sks[p] = sk
|
||||
kb.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
type peerstore struct {
|
||||
keybook
|
||||
metrics
|
||||
AddrManager
|
||||
|
||||
// store other data, like versions
|
||||
//ds ds.ThreadSafeDatastore
|
||||
// TODO: use a datastore for this
|
||||
ds map[string]interface{}
|
||||
dslock sync.Mutex
|
||||
}
|
||||
|
||||
// NewPeerstore creates a threadsafe collection of peers.
|
||||
func NewPeerstore() Peerstore {
|
||||
return &peerstore{
|
||||
keybook: *newKeybook(),
|
||||
metrics: *(NewMetrics()).(*metrics),
|
||||
AddrManager: AddrManager{},
|
||||
//ds: dssync.MutexWrap(ds.NewMapDatastore()),
|
||||
ds: make(map[string]interface{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (ps *peerstore) Put(p ID, key string, val interface{}) error {
|
||||
//dsk := ds.NewKey(string(p) + "/" + key)
|
||||
//return ps.ds.Put(dsk, val)
|
||||
ps.dslock.Lock()
|
||||
defer ps.dslock.Unlock()
|
||||
ps.ds[string(p)+"/"+key] = val
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ps *peerstore) Get(p ID, key string) (interface{}, error) {
|
||||
//dsk := ds.NewKey(string(p) + "/" + key)
|
||||
//return ps.ds.Get(dsk)
|
||||
|
||||
ps.dslock.Lock()
|
||||
defer ps.dslock.Unlock()
|
||||
i, ok := ps.ds[string(p)+"/"+key]
|
||||
if !ok {
|
||||
return nil, errors.New("item not found")
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (ps *peerstore) Peers() []ID {
|
||||
set := map[ID]struct{}{}
|
||||
for _, p := range ps.keybook.Peers() {
|
||||
set[p] = struct{}{}
|
||||
}
|
||||
for _, p := range ps.AddrManager.Peers() {
|
||||
set[p] = struct{}{}
|
||||
}
|
||||
|
||||
pps := make([]ID, 0, len(set))
|
||||
for p := range set {
|
||||
pps = append(pps, p)
|
||||
}
|
||||
return pps
|
||||
}
|
||||
|
||||
func (ps *peerstore) PeerInfo(p ID) PeerInfo {
|
||||
return PeerInfo{
|
||||
ID: p,
|
||||
Addrs: ps.AddrManager.Addrs(p),
|
||||
}
|
||||
}
|
||||
|
||||
func PeerInfos(ps Peerstore, peers []ID) []PeerInfo {
|
||||
pi := make([]PeerInfo, len(peers))
|
||||
for i, p := range peers {
|
||||
pi[i] = ps.PeerInfo(p)
|
||||
}
|
||||
return pi
|
||||
}
|
||||
|
||||
func PeerInfoIDs(pis []PeerInfo) []ID {
|
||||
ps := make([]ID, len(pis))
|
||||
for i, pi := range pis {
|
||||
ps[i] = pi.ID
|
||||
}
|
||||
return ps
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
package queue
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
ks "gx/ipfs/QmUusaX99BZoELh7dmPgirqRQ1FAmMnmnBn3oiqDFGBUSc/go-keyspace"
|
||||
)
|
||||
|
||||
// peerMetric tracks a peer and its distance to something else.
|
||||
type peerMetric struct {
|
||||
// the peer
|
||||
peer peer.ID
|
||||
|
||||
// big.Int for XOR metric
|
||||
metric *big.Int
|
||||
}
|
||||
|
||||
// peerMetricHeap implements a heap of peerDistances
|
||||
type peerMetricHeap []*peerMetric
|
||||
|
||||
func (ph peerMetricHeap) Len() int {
|
||||
return len(ph)
|
||||
}
|
||||
|
||||
func (ph peerMetricHeap) Less(i, j int) bool {
|
||||
return -1 == ph[i].metric.Cmp(ph[j].metric)
|
||||
}
|
||||
|
||||
func (ph peerMetricHeap) Swap(i, j int) {
|
||||
ph[i], ph[j] = ph[j], ph[i]
|
||||
}
|
||||
|
||||
func (ph *peerMetricHeap) Push(x interface{}) {
|
||||
item := x.(*peerMetric)
|
||||
*ph = append(*ph, item)
|
||||
}
|
||||
|
||||
func (ph *peerMetricHeap) Pop() interface{} {
|
||||
old := *ph
|
||||
n := len(old)
|
||||
item := old[n-1]
|
||||
*ph = old[0 : n-1]
|
||||
return item
|
||||
}
|
||||
|
||||
// distancePQ implements heap.Interface and PeerQueue
|
||||
type distancePQ struct {
|
||||
// from is the Key this PQ measures against
|
||||
from ks.Key
|
||||
|
||||
// heap is a heap of peerDistance items
|
||||
heap peerMetricHeap
|
||||
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func (pq *distancePQ) Len() int {
|
||||
pq.Lock()
|
||||
defer pq.Unlock()
|
||||
return len(pq.heap)
|
||||
}
|
||||
|
||||
func (pq *distancePQ) Enqueue(p peer.ID) {
|
||||
pq.Lock()
|
||||
defer pq.Unlock()
|
||||
|
||||
distance := ks.XORKeySpace.Key([]byte(p)).Distance(pq.from)
|
||||
|
||||
heap.Push(&pq.heap, &peerMetric{
|
||||
peer: p,
|
||||
metric: distance,
|
||||
})
|
||||
}
|
||||
|
||||
func (pq *distancePQ) Dequeue() peer.ID {
|
||||
pq.Lock()
|
||||
defer pq.Unlock()
|
||||
|
||||
if len(pq.heap) < 1 {
|
||||
panic("called Dequeue on an empty PeerQueue")
|
||||
// will panic internally anyway, but we can help debug here
|
||||
}
|
||||
|
||||
o := heap.Pop(&pq.heap)
|
||||
p := o.(*peerMetric)
|
||||
return p.peer
|
||||
}
|
||||
|
||||
// NewXORDistancePQ returns a PeerQueue which maintains its peers sorted
|
||||
// in terms of their distances to each other in an XORKeySpace (i.e. using
|
||||
// XOR as a metric of distance).
|
||||
func NewXORDistancePQ(from string) PeerQueue {
|
||||
return &distancePQ{
|
||||
from: ks.XORKeySpace.Key([]byte(from)),
|
||||
heap: peerMetricHeap{},
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package queue
|
||||
|
||||
import peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
|
||||
// PeerQueue maintains a set of peers ordered according to a metric.
|
||||
// Implementations of PeerQueue could order peers based on distances along
|
||||
// a KeySpace, latency measurements, trustworthiness, reputation, etc.
|
||||
type PeerQueue interface {
|
||||
|
||||
// Len returns the number of items in PeerQueue
|
||||
Len() int
|
||||
|
||||
// Enqueue adds this node to the queue.
|
||||
Enqueue(peer.ID)
|
||||
|
||||
// Dequeue retrieves the highest (smallest int) priority node
|
||||
Dequeue() peer.ID
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
package queue
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
|
||||
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
)
|
||||
|
||||
func TestQueue(t *testing.T) {
|
||||
|
||||
p1 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31") // these aren't valid, because need to hex-decode.
|
||||
p2 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a32") // these aren't valid, because need to hex-decode.
|
||||
p3 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33") // these aren't valid, because need to hex-decode.
|
||||
p4 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a34") // these aren't valid, because need to hex-decode.
|
||||
p5 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31") // these aren't valid, because need to hex-decode.
|
||||
// but they work.
|
||||
|
||||
// these are the peer.IDs' XORKeySpace Key values:
|
||||
// [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]
|
||||
// [26 249 85 75 54 49 25 30 21 86 117 62 85 145 48 175 155 194 210 216 58 14 241 143 28 209 129 144 122 28 163 6]
|
||||
// [78 135 26 216 178 181 224 181 234 117 2 248 152 115 255 103 244 34 4 152 193 88 9 225 8 127 216 158 226 8 236 246]
|
||||
// [125 135 124 6 226 160 101 94 192 57 39 12 18 79 121 140 190 154 147 55 44 83 101 151 63 255 94 179 51 203 241 51]
|
||||
|
||||
pq := NewXORDistancePQ("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31")
|
||||
pq.Enqueue(p3)
|
||||
pq.Enqueue(p1)
|
||||
pq.Enqueue(p2)
|
||||
pq.Enqueue(p4)
|
||||
pq.Enqueue(p5)
|
||||
pq.Enqueue(p1)
|
||||
|
||||
// should come out as: p1, p4, p3, p2
|
||||
|
||||
if d := pq.Dequeue(); d != p1 && d != p5 {
|
||||
t.Error("ordering failed")
|
||||
}
|
||||
|
||||
if d := pq.Dequeue(); d != p1 && d != p5 {
|
||||
t.Error("ordering failed")
|
||||
}
|
||||
|
||||
if d := pq.Dequeue(); d != p1 && d != p5 {
|
||||
t.Error("ordering failed")
|
||||
}
|
||||
|
||||
if pq.Dequeue() != p4 {
|
||||
t.Error("ordering failed")
|
||||
}
|
||||
|
||||
if pq.Dequeue() != p3 {
|
||||
t.Error("ordering failed")
|
||||
}
|
||||
|
||||
if pq.Dequeue() != p2 {
|
||||
t.Error("ordering failed")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func newPeerTime(t time.Time) peer.ID {
|
||||
s := fmt.Sprintf("hmmm time: %v", t)
|
||||
h := u.Hash([]byte(s))
|
||||
return peer.ID(h)
|
||||
}
|
||||
|
||||
func TestSyncQueue(t *testing.T) {
|
||||
tickT := time.Microsecond * 50
|
||||
max := 5000
|
||||
consumerN := 10
|
||||
countsIn := make([]int, consumerN*2)
|
||||
countsOut := make([]int, consumerN)
|
||||
|
||||
if testing.Short() {
|
||||
max = 1000
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
pq := NewXORDistancePQ("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31")
|
||||
cq := NewChanQueue(ctx, pq)
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
produce := func(p int) {
|
||||
defer wg.Done()
|
||||
|
||||
tick := time.Tick(tickT)
|
||||
for i := 0; i < max; i++ {
|
||||
select {
|
||||
case tim := <-tick:
|
||||
countsIn[p]++
|
||||
cq.EnqChan <- newPeerTime(tim)
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
consume := func(c int) {
|
||||
defer wg.Done()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-cq.DeqChan:
|
||||
countsOut[c]++
|
||||
if countsOut[c] >= max*2 {
|
||||
return
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make n * 2 producers and n consumers
|
||||
for i := 0; i < consumerN; i++ {
|
||||
wg.Add(3)
|
||||
go produce(i)
|
||||
go produce(consumerN + i)
|
||||
go consume(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
sum := func(ns []int) int {
|
||||
total := 0
|
||||
for _, n := range ns {
|
||||
total += n
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
if sum(countsIn) != sum(countsOut) {
|
||||
t.Errorf("didnt get all of them out: %d/%d", sum(countsOut), sum(countsIn))
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
package queue
|
||||
|
||||
import (
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
|
||||
)
|
||||
|
||||
var log = logging.Logger("peerqueue")
|
||||
|
||||
// ChanQueue makes any PeerQueue synchronizable through channels.
|
||||
type ChanQueue struct {
|
||||
Queue PeerQueue
|
||||
EnqChan chan<- peer.ID
|
||||
DeqChan <-chan peer.ID
|
||||
}
|
||||
|
||||
// NewChanQueue creates a ChanQueue by wrapping pq.
|
||||
func NewChanQueue(ctx context.Context, pq PeerQueue) *ChanQueue {
|
||||
cq := &ChanQueue{Queue: pq}
|
||||
cq.process(ctx)
|
||||
return cq
|
||||
}
|
||||
|
||||
func (cq *ChanQueue) process(ctx context.Context) {
|
||||
// construct the channels here to be able to use them bidirectionally
|
||||
enqChan := make(chan peer.ID)
|
||||
deqChan := make(chan peer.ID)
|
||||
|
||||
cq.EnqChan = enqChan
|
||||
cq.DeqChan = deqChan
|
||||
|
||||
go func() {
|
||||
log.Debug("processing")
|
||||
defer log.Debug("closed")
|
||||
defer close(deqChan)
|
||||
|
||||
var next peer.ID
|
||||
var item peer.ID
|
||||
var more bool
|
||||
|
||||
for {
|
||||
if cq.Queue.Len() == 0 {
|
||||
// log.Debug("wait for enqueue")
|
||||
select {
|
||||
case next, more = <-enqChan:
|
||||
if !more {
|
||||
return
|
||||
}
|
||||
// log.Debug("got", next)
|
||||
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
next = cq.Queue.Dequeue()
|
||||
// log.Debug("peek", next)
|
||||
}
|
||||
|
||||
select {
|
||||
case item, more = <-enqChan:
|
||||
if !more {
|
||||
if cq.Queue.Len() > 0 {
|
||||
return // we're done done.
|
||||
}
|
||||
enqChan = nil // closed, so no use.
|
||||
}
|
||||
// log.Debug("got", item)
|
||||
cq.Queue.Enqueue(item)
|
||||
cq.Queue.Enqueue(next) // order may have changed.
|
||||
next = ""
|
||||
|
||||
case deqChan <- next:
|
||||
// log.Debug("dequeued", next)
|
||||
next = ""
|
||||
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}()
|
||||
}
|
||||
@@ -7,15 +7,15 @@ import (
|
||||
host "github.com/ipfs/go-libp2p/p2p/host"
|
||||
mstream "github.com/ipfs/go-libp2p/p2p/metrics/stream"
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
pb "github.com/ipfs/go-libp2p/p2p/protocol/identify/pb"
|
||||
msmux "gx/ipfs/QmUeEcYJrzAEKdQXjzTxCgNZgc9sRuwharsvzzm5Gd2oGB/go-multistream"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
ggio "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/io"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
semver "gx/ipfs/QmcrrEpx3VMUbrbgVroH3YiYyUS5c4YAykzyPJWKspUYLa/go-semver/semver"
|
||||
|
||||
lgbl "github.com/ipfs/go-libp2p/loggables"
|
||||
lgbl "gx/ipfs/QmSyBhZt2upyQ3NJmTpab1pX6hesA59vcYTGmgoDorZZbw/go-libp2p-loggables"
|
||||
logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
|
||||
)
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
"time"
|
||||
|
||||
host "github.com/ipfs/go-libp2p/p2p/host"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
identify "github.com/ipfs/go-libp2p/p2p/protocol/identify"
|
||||
testutil "github.com/ipfs/go-libp2p/p2p/test/util"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
|
||||
@@ -4,8 +4,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
host "github.com/ipfs/go-libp2p/p2p/host"
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
netutil "github.com/ipfs/go-libp2p/p2p/test/util"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
)
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
|
||||
host "github.com/ipfs/go-libp2p/p2p/host"
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
protocol "github.com/ipfs/go-libp2p/p2p/protocol"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
mh "gx/ipfs/QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku/go-multihash"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
|
||||
host "github.com/ipfs/go-libp2p/p2p/host"
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
protocol "github.com/ipfs/go-libp2p/p2p/protocol"
|
||||
testutil "github.com/ipfs/go-libp2p/p2p/test/util"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
|
||||
|
||||
@@ -5,10 +5,10 @@ import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
ic "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
testutil "github.com/ipfs/go-libp2p/testutil"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
|
||||
ic "gx/ipfs/QmaP38GJApheTr84f8R89vsT7oJLQw1AeCz4HqrQgv2njB/go-libp2p-crypto"
|
||||
logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
|
||||
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
metrics "github.com/ipfs/go-libp2p/p2p/metrics"
|
||||
inet "github.com/ipfs/go-libp2p/p2p/net"
|
||||
swarm "github.com/ipfs/go-libp2p/p2p/net/swarm"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
tu "github.com/ipfs/go-libp2p/testutil"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
|
||||
83
package.json
83
package.json
@@ -1,153 +1,162 @@
|
||||
{
|
||||
"name": "go-libp2p",
|
||||
"author": "whyrusleeping",
|
||||
"bugs": {},
|
||||
"gx": {
|
||||
"dvcsimport": "github.com/ipfs/go-libp2p"
|
||||
},
|
||||
"version": "2.0.1",
|
||||
"gxDependencies": [
|
||||
{
|
||||
"hash": "QmcrrEpx3VMUbrbgVroH3YiYyUS5c4YAykzyPJWKspUYLa",
|
||||
"name": "go-semver",
|
||||
"hash": "QmcrrEpx3VMUbrbgVroH3YiYyUS5c4YAykzyPJWKspUYLa",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmSscYPCcE1H3UQr2tnsJ2a9dK9LsHTBGgP71VW6fz67e5",
|
||||
"name": "mdns",
|
||||
"hash": "QmSscYPCcE1H3UQr2tnsJ2a9dK9LsHTBGgP71VW6fz67e5",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmRQhVisS8dmPbjBUthVkenn81pBxrx1GxE281csJhm2vL",
|
||||
"name": "go-msgio",
|
||||
"hash": "QmRQhVisS8dmPbjBUthVkenn81pBxrx1GxE281csJhm2vL",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1",
|
||||
"name": "go-ipfs-util",
|
||||
"hash": "QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmUusaX99BZoELh7dmPgirqRQ1FAmMnmnBn3oiqDFGBUSc",
|
||||
"name": "go-keyspace",
|
||||
"hash": "QmUusaX99BZoELh7dmPgirqRQ1FAmMnmnBn3oiqDFGBUSc",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmUeEcYJrzAEKdQXjzTxCgNZgc9sRuwharsvzzm5Gd2oGB",
|
||||
"name": "go-multistream",
|
||||
"hash": "QmUeEcYJrzAEKdQXjzTxCgNZgc9sRuwharsvzzm5Gd2oGB",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmNLvkCDV6ZjUJsEwGNporYBuZdhWT6q7TBVYQwwRv12HT",
|
||||
"name": "go-nat",
|
||||
"hash": "QmNLvkCDV6ZjUJsEwGNporYBuZdhWT6q7TBVYQwwRv12HT",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmQHGMVmrsgmqUG8ih3puNXUJneSpi13dkcZpzLKkskUkH",
|
||||
"name": "go-detect-race",
|
||||
"hash": "QmQHGMVmrsgmqUG8ih3puNXUJneSpi13dkcZpzLKkskUkH",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmQopLATEYMNg7dVqZRNDfeE2S1yKy8zrRh5xnYiuqeZBn",
|
||||
"name": "goprocess",
|
||||
"hash": "QmQopLATEYMNg7dVqZRNDfeE2S1yKy8zrRh5xnYiuqeZBn",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH",
|
||||
"name": "go-log",
|
||||
"hash": "Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmYVqhVfbK4BKvbW88Lhm26b3ud14sTBvcm1H7uWUx1Fkp",
|
||||
"name": "go-multiaddr-net",
|
||||
"hash": "QmYVqhVfbK4BKvbW88Lhm26b3ud14sTBvcm1H7uWUx1Fkp",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku",
|
||||
"name": "go-multihash",
|
||||
"hash": "QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmPwfFAHUmvWDucLHRS9Xz2Kb1TNX2cY4LJ7pQjg9kVcae",
|
||||
"name": "multiaddr-filter",
|
||||
"hash": "QmPwfFAHUmvWDucLHRS9Xz2Kb1TNX2cY4LJ7pQjg9kVcae",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf",
|
||||
"name": "go-base58",
|
||||
"hash": "QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "Qme1boxspcQWR8FBzMxeppqug2fYgYc15diNWmqgDVnvn2",
|
||||
"name": "go-crypto",
|
||||
"hash": "Qme1boxspcQWR8FBzMxeppqug2fYgYc15diNWmqgDVnvn2",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV",
|
||||
"name": "gogo-protobuf",
|
||||
"hash": "QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz",
|
||||
"name": "go-multiaddr",
|
||||
"hash": "QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmeYJHEk8UjVVZ4XCRTZe6dFQrb8pGWD81LYCgeLp8CvMB",
|
||||
"name": "go-metrics",
|
||||
"hash": "QmeYJHEk8UjVVZ4XCRTZe6dFQrb8pGWD81LYCgeLp8CvMB",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmYvsG72GsfLgUeSojXArjnU6L4Wmwk7wuAxtNLuyXcc1T",
|
||||
"name": "randbo",
|
||||
"hash": "QmYvsG72GsfLgUeSojXArjnU6L4Wmwk7wuAxtNLuyXcc1T",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt",
|
||||
"name": "go-net",
|
||||
"hash": "QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmWSJzRkCMJFHYUQZxKwPX8WA7XipaPtfiwMPARP51ymfn",
|
||||
"name": "go-stream-muxer",
|
||||
"hash": "QmWSJzRkCMJFHYUQZxKwPX8WA7XipaPtfiwMPARP51ymfn",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmaaC9QMYTQHCbMq3Ebr3uMaAR2ev4AVqMmsJpgQijAZbJ",
|
||||
"name": "go-reuseport",
|
||||
"hash": "QmaaC9QMYTQHCbMq3Ebr3uMaAR2ev4AVqMmsJpgQijAZbJ",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmbcS9XrwZkF1rZj8bBwwzoYhVuA2PCnPhFUL1pyWGgt2A",
|
||||
"name": "go-notifier",
|
||||
"hash": "QmbcS9XrwZkF1rZj8bBwwzoYhVuA2PCnPhFUL1pyWGgt2A",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmWHgLqrghM9zw77nF6gdvT9ExQ2RB9pLxkd8sDHZf1rWb",
|
||||
"name": "go-temp-err-catcher",
|
||||
"hash": "QmWHgLqrghM9zw77nF6gdvT9ExQ2RB9pLxkd8sDHZf1rWb",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"hash": "QmZK81vcgMhpb2t7GNbozk7qzt6Rj4zFqitpvsWT9mduW8",
|
||||
"name": "go-peerstream",
|
||||
"hash": "QmZK81vcgMhpb2t7GNbozk7qzt6Rj4zFqitpvsWT9mduW8",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"author": "whyrusleeping",
|
||||
"hash": "QmWLfU4tstw2aNcTykDm44xbSTCYJ9pUJwfhQCKGwckcHx",
|
||||
"name": "mafmt",
|
||||
"hash": "QmWLfU4tstw2aNcTykDm44xbSTCYJ9pUJwfhQCKGwckcHx",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"author": "whyrusleeping",
|
||||
"hash": "QmTd4Jgb4nbJq5uR55KJgGLyHWmM3dovS21D1HcwRneSLu",
|
||||
"name": "gorocheck",
|
||||
"hash": "QmTd4Jgb4nbJq5uR55KJgGLyHWmM3dovS21D1HcwRneSLu",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"author": "whyrusleeping",
|
||||
"name": "go-libp2p-secio",
|
||||
"hash": "QmeBhrdD3K5aMCubZMwhAbcCuHbWjTvVbhQX73kFx2qQfs",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"author": "whyrusleeping",
|
||||
"name": "go-libp2p-transport",
|
||||
"hash": "QmR4HhZm1fL8epXz8661Ru8ks5Y1Uk2u51quAWaCTD1zHg",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
],
|
||||
"gxVersion": "0.4.0",
|
||||
"gx_version": "0.4.0",
|
||||
"issues_url": "",
|
||||
"language": "go",
|
||||
"license": "",
|
||||
"name": "go-libp2p",
|
||||
"version": "2.0.1"
|
||||
"issues_url": "",
|
||||
"gx_version": "0.4.0",
|
||||
"gx": {
|
||||
"dvcsimport": "github.com/ipfs/go-libp2p"
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
ci "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
|
||||
ci "gx/ipfs/QmaP38GJApheTr84f8R89vsT7oJLQw1AeCz4HqrQgv2njB/go-libp2p-crypto"
|
||||
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
@@ -3,8 +3,8 @@ package testutil
|
||||
import (
|
||||
"testing"
|
||||
|
||||
ci "github.com/ipfs/go-libp2p/p2p/crypto"
|
||||
peer "github.com/ipfs/go-libp2p/p2p/peer"
|
||||
peer "gx/ipfs/QmY1xNhBfF9xA1pmD8yejyQAyd77K68qNN6JPM1CN2eiRu/go-libp2p-peer"
|
||||
ci "gx/ipfs/QmaP38GJApheTr84f8R89vsT7oJLQw1AeCz4HqrQgv2njB/go-libp2p-crypto"
|
||||
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user