From 41c683485015bca19626138f18fa0027b5a8243d Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 9 Mar 2018 17:56:02 -0800 Subject: [PATCH] refactor for transport changes Also, make the libp2p constructor fully useful. There should now be no need to manually construct a swarm/host. --- config/config.go | 176 +++++++++++++ config/constructor_types.go | 62 +++++ config/muxer.go | 62 +++++ config/muxer_test.go | 54 ++++ config/reflection_magic.go | 126 +++++++++ config/reflection_magic_test.go | 142 ++++++++++ config/security.go | 76 ++++++ config/transport.go | 66 +++++ defaults.go | 109 ++++++++ error_util.go | 17 ++ examples/chat/chat.go | 30 +-- examples/echo/main.go | 2 +- examples/http-proxy/proxy.go | 24 +- examples/multipro/main.go | 17 +- .../main.go | 22 +- libp2p.go | 241 ++--------------- libp2p_test.go | 29 ++- options.go | 243 ++++++++++++++++++ p2p/discovery/mdns_test.go | 6 +- p2p/host/basic/basic_host.go | 66 +---- p2p/host/basic/basic_host_test.go | 20 +- p2p/net/mock/mock_conn.go | 4 +- p2p/protocol/identify/id.go | 24 +- p2p/protocol/identify/id_test.go | 8 +- p2p/protocol/ping/ping_test.go | 6 +- p2p/test/backpressure/backpressure_test.go | 10 +- p2p/test/reconnects/reconnect_test.go | 33 +-- package.json | 171 +++++------- 28 files changed, 1335 insertions(+), 511 deletions(-) create mode 100644 config/config.go create mode 100644 config/constructor_types.go create mode 100644 config/muxer.go create mode 100644 config/muxer_test.go create mode 100644 config/reflection_magic.go create mode 100644 config/reflection_magic_test.go create mode 100644 config/security.go create mode 100644 config/transport.go create mode 100644 defaults.go create mode 100644 error_util.go create mode 100644 options.go diff --git a/config/config.go b/config/config.go new file mode 100644 index 000000000..b017fea60 --- /dev/null +++ b/config/config.go @@ -0,0 +1,176 @@ +package config + +import ( + "context" + "fmt" + + bhost "github.com/libp2p/go-libp2p/p2p/host/basic" + + logging "github.com/ipfs/go-log" + circuit "github.com/libp2p/go-libp2p-circuit" + crypto "github.com/libp2p/go-libp2p-crypto" + host "github.com/libp2p/go-libp2p-host" + ifconnmgr "github.com/libp2p/go-libp2p-interface-connmgr" + pnet "github.com/libp2p/go-libp2p-interface-pnet" + metrics "github.com/libp2p/go-libp2p-metrics" + inet "github.com/libp2p/go-libp2p-net" + peer "github.com/libp2p/go-libp2p-peer" + pstore "github.com/libp2p/go-libp2p-peerstore" + swarm "github.com/libp2p/go-libp2p-swarm" + tptu "github.com/libp2p/go-libp2p-transport-upgrader" + filter "github.com/libp2p/go-maddr-filter" + ma "github.com/multiformats/go-multiaddr" +) + +var log = logging.Logger("p2p-config") + +// AddrsFactory is a function that takes a set of multiaddrs we're listening on and +// returns the set of multiaddrs we should advertise to the network. +type AddrsFactory = bhost.AddrsFactory + +// NATManagerC is a NATManager constructor. +type NATManagerC func(inet.Network) bhost.NATManager + +// Config describes a set of settings for a libp2p node +// +// This is *not* a stable interface. Use the options defined in the root +// package. +type Config struct { + PeerKey crypto.PrivKey + + Transports []TptC + Muxers []MsMuxC + SecurityTransports []MsSecC + Insecure bool + Protector pnet.Protector + + Relay bool + RelayOpts []circuit.RelayOpt + + ListenAddrs []ma.Multiaddr + AddrsFactory bhost.AddrsFactory + Filters *filter.Filters + + ConnManager ifconnmgr.ConnManager + NATManager NATManagerC + Peerstore pstore.Peerstore + Reporter metrics.Reporter +} + +// NewNode constructs a new libp2p Host from the Config. +// +// This function consumes the config. Do not reuse it (really!). +func (cfg *Config) NewNode(ctx context.Context) (host.Host, error) { + // Check this early. Prevents us from even *starting* without verifying this. + if pnet.ForcePrivateNetwork && cfg.Protector == nil { + log.Error("tried to create a libp2p node with no Private" + + " Network Protector but usage of Private Networks" + + " is forced by the enviroment") + // Note: This is *also* checked the upgrader itself so it'll be + // enforced even *if* you don't use the libp2p constructor. + return nil, pnet.ErrNotInPrivateNetwork + } + + if cfg.PeerKey == nil { + return nil, fmt.Errorf("no peer key specified") + } + + // Obtain Peer ID from public key + pid, err := peer.IDFromPublicKey(cfg.PeerKey.GetPublic()) + if err != nil { + return nil, err + } + + if cfg.Peerstore == nil { + return nil, fmt.Errorf("no peerstore specified") + } + + if !cfg.Insecure { + cfg.Peerstore.AddPrivKey(pid, cfg.PeerKey) + cfg.Peerstore.AddPubKey(pid, cfg.PeerKey.GetPublic()) + } + + // TODO: Make the swarm implementation configurable. + swrm := swarm.NewSwarm(ctx, pid, cfg.Peerstore, cfg.Reporter) + if cfg.Filters != nil { + swrm.Filters = cfg.Filters + } + + // TODO: make host implementation configurable. + h, err := bhost.NewHost(ctx, swrm, &bhost.HostOpts{ + ConnManager: cfg.ConnManager, + AddrsFactory: cfg.AddrsFactory, + NATManager: cfg.NATManager, + }) + if err != nil { + swrm.Close() + return nil, err + } + + upgrader := new(tptu.Upgrader) + upgrader.Protector = cfg.Protector + upgrader.Filters = swrm.Filters + if cfg.Insecure { + upgrader.Secure = makeInsecureTransport(pid) + } else { + upgrader.Secure, err = makeSecurityTransport(h, cfg.SecurityTransports) + if err != nil { + h.Close() + return nil, err + } + } + + upgrader.Muxer, err = makeMuxer(h, cfg.Muxers) + if err != nil { + h.Close() + return nil, err + } + + tpts, err := makeTransports(h, upgrader, cfg.Transports) + if err != nil { + h.Close() + return nil, err + } + for _, t := range tpts { + err = swrm.AddTransport(t) + if err != nil { + h.Close() + return nil, err + } + } + + if cfg.Relay { + err := circuit.AddRelayTransport(swrm.Context(), h, upgrader, cfg.RelayOpts...) + if err != nil { + h.Close() + return nil, err + } + } + + // TODO: This method succeeds if listening on one address succeeds. We + // should probably fail if listening on *any* addr fails. + if err := h.Network().Listen(cfg.ListenAddrs...); err != nil { + h.Close() + return nil, err + } + + // TODO: Configure routing (it's a pain to setup). + // TODO: Bootstrapping. + + return h, nil +} + +// Option is a libp2p config option that can be given to the libp2p constructor +// (`libp2p.New`). +type Option func(cfg *Config) error + +// Apply applies the given options to the config, returning the first error +// encountered (if any). +func (cfg *Config) Apply(opts ...Option) error { + for _, opt := range opts { + if err := opt(cfg); err != nil { + return err + } + } + return nil +} diff --git a/config/constructor_types.go b/config/constructor_types.go new file mode 100644 index 000000000..0cf4163fc --- /dev/null +++ b/config/constructor_types.go @@ -0,0 +1,62 @@ +package config + +import ( + "fmt" + "reflect" + + security "github.com/libp2p/go-conn-security" + crypto "github.com/libp2p/go-libp2p-crypto" + host "github.com/libp2p/go-libp2p-host" + pnet "github.com/libp2p/go-libp2p-interface-pnet" + inet "github.com/libp2p/go-libp2p-net" + peer "github.com/libp2p/go-libp2p-peer" + pstore "github.com/libp2p/go-libp2p-peerstore" + transport "github.com/libp2p/go-libp2p-transport" + tptu "github.com/libp2p/go-libp2p-transport-upgrader" + filter "github.com/libp2p/go-maddr-filter" + mux "github.com/libp2p/go-stream-muxer" +) + +var ( + // interfaces + hostType = reflect.TypeOf((*host.Host)(nil)).Elem() + networkType = reflect.TypeOf((*inet.Network)(nil)).Elem() + transportType = reflect.TypeOf((*transport.Transport)(nil)).Elem() + muxType = reflect.TypeOf((*mux.Transport)(nil)).Elem() + securityType = reflect.TypeOf((*security.Transport)(nil)).Elem() + protectorType = reflect.TypeOf((*pnet.Protector)(nil)).Elem() + privKeyType = reflect.TypeOf((*crypto.PrivKey)(nil)).Elem() + pubKeyType = reflect.TypeOf((*crypto.PubKey)(nil)).Elem() + pstoreType = reflect.TypeOf((*pstore.Peerstore)(nil)).Elem() + + // concrete types + peerIDType = reflect.TypeOf((peer.ID)("")) + filtersType = reflect.TypeOf((*filter.Filters)(nil)) + upgraderType = reflect.TypeOf((*tptu.Upgrader)(nil)) +) + +var argTypes = map[reflect.Type]constructor{ + upgraderType: func(h host.Host, u *tptu.Upgrader) interface{} { return u }, + hostType: func(h host.Host, u *tptu.Upgrader) interface{} { return h }, + networkType: func(h host.Host, u *tptu.Upgrader) interface{} { return h.Network() }, + muxType: func(h host.Host, u *tptu.Upgrader) interface{} { return u.Muxer }, + securityType: func(h host.Host, u *tptu.Upgrader) interface{} { return u.Secure }, + protectorType: func(h host.Host, u *tptu.Upgrader) interface{} { return u.Protector }, + filtersType: func(h host.Host, u *tptu.Upgrader) interface{} { return u.Filters }, + peerIDType: func(h host.Host, u *tptu.Upgrader) interface{} { return h.ID() }, + privKeyType: func(h host.Host, u *tptu.Upgrader) interface{} { return h.Peerstore().PrivKey(h.ID()) }, + pubKeyType: func(h host.Host, u *tptu.Upgrader) interface{} { return h.Peerstore().PubKey(h.ID()) }, + pstoreType: func(h host.Host, u *tptu.Upgrader) interface{} { return h.Peerstore() }, +} + +func newArgTypeSet(types ...reflect.Type) map[reflect.Type]constructor { + result := make(map[reflect.Type]constructor, len(types)) + for _, ty := range types { + c, ok := argTypes[ty] + if !ok { + panic(fmt.Sprintf("missing constructor for type %s", ty)) + } + result[ty] = c + } + return result +} diff --git a/config/muxer.go b/config/muxer.go new file mode 100644 index 000000000..6a48cb3bd --- /dev/null +++ b/config/muxer.go @@ -0,0 +1,62 @@ +package config + +import ( + "fmt" + + host "github.com/libp2p/go-libp2p-host" + mux "github.com/libp2p/go-stream-muxer" + msmux "github.com/whyrusleeping/go-smux-multistream" +) + +// MuxC is a stream multiplex transport constructor +type MuxC func(h host.Host) (mux.Transport, error) + +// MsMuxC is a tuple containing a multiplex transport constructor and a protocol +// ID. +type MsMuxC struct { + MuxC + ID string +} + +var muxArgTypes = newArgTypeSet(hostType, networkType, peerIDType, pstoreType) + +// MuxerConstructor creates a multiplex constructor from the passed parameter +// using reflection. +func MuxerConstructor(m interface{}) (MuxC, error) { + // Already constructed? + if t, ok := m.(mux.Transport); ok { + return func(_ host.Host) (mux.Transport, error) { + return t, nil + }, nil + } + + ctor, err := makeConstructor(m, muxType, muxArgTypes) + if err != nil { + return nil, err + } + return func(h host.Host) (mux.Transport, error) { + t, err := ctor(h, nil) + if err != nil { + return nil, err + } + return t.(mux.Transport), nil + }, nil +} + +func makeMuxer(h host.Host, tpts []MsMuxC) (mux.Transport, error) { + muxMuxer := msmux.NewBlankTransport() + transportSet := make(map[string]struct{}, len(tpts)) + for _, tptC := range tpts { + if _, ok := transportSet[tptC.ID]; ok { + return nil, fmt.Errorf("duplicate muxer transport: %s", tptC.ID) + } + } + for _, tptC := range tpts { + tpt, err := tptC.MuxC(h) + if err != nil { + return nil, err + } + muxMuxer.AddTransport(tptC.ID, tpt) + } + return muxMuxer, nil +} diff --git a/config/muxer_test.go b/config/muxer_test.go new file mode 100644 index 000000000..5e7bab41f --- /dev/null +++ b/config/muxer_test.go @@ -0,0 +1,54 @@ +package config + +import ( + "testing" + + peer "github.com/libp2p/go-libp2p-peer" + mux "github.com/libp2p/go-stream-muxer" + yamux "github.com/whyrusleeping/go-smux-yamux" +) + +func TestMuxerSimple(t *testing.T) { + // single + _, err := MuxerConstructor(func(_ peer.ID) mux.Transport { return nil }) + if err != nil { + t.Fatal(err) + } +} + +func TestMuxerByValue(t *testing.T) { + _, err := MuxerConstructor(yamux.DefaultTransport) + if err != nil { + t.Fatal(err) + } +} +func TestMuxerDuplicate(t *testing.T) { + _, err := MuxerConstructor(func(_ peer.ID, _ peer.ID) mux.Transport { return nil }) + if err != nil { + t.Fatal(err) + } +} + +func TestMuxerError(t *testing.T) { + _, err := MuxerConstructor(func() (mux.Transport, error) { return nil, nil }) + if err != nil { + t.Fatal(err) + } +} + +func TestMuxerBadTypes(t *testing.T) { + for i, f := range []interface{}{ + func() error { return nil }, + func() string { return "" }, + func() {}, + func(string) mux.Transport { return nil }, + func(string) (mux.Transport, error) { return nil, nil }, + nil, + "testing", + } { + + if _, err := MuxerConstructor(f); err == nil { + t.Fatalf("constructor %d with type %T should have failed", i, f) + } + } +} diff --git a/config/reflection_magic.go b/config/reflection_magic.go new file mode 100644 index 000000000..c23658e9c --- /dev/null +++ b/config/reflection_magic.go @@ -0,0 +1,126 @@ +package config + +import ( + "fmt" + "reflect" + "runtime" + + host "github.com/libp2p/go-libp2p-host" + tptu "github.com/libp2p/go-libp2p-transport-upgrader" +) + +var errorType = reflect.TypeOf((*error)(nil)).Elem() + +// checks if a function returns either the specified type or the specified type +// and an error. +func checkReturnType(fnType, tptType reflect.Type) error { + switch fnType.NumOut() { + case 2: + if fnType.Out(1) != errorType { + return fmt.Errorf("expected (optional) second return value from transport constructor to be an error") + } + + fallthrough + case 1: + if !fnType.Out(0).Implements(tptType) { + return fmt.Errorf("expected first return value from transport constructor to be a transport") + } + default: + return fmt.Errorf("expected transport constructor to return a transport and, optionally, an error") + } + return nil +} + +// Handles return values with optional errors. That is, return values of the +// form `(something, error)` or just `something`. +// +// Panics if the return value isn't of the correct form. +func handleReturnValue(out []reflect.Value) (interface{}, error) { + switch len(out) { + case 2: + err := out[1] + if err != (reflect.Value{}) && !err.IsNil() { + return nil, err.Interface().(error) + } + fallthrough + case 1: + tpt := out[0] + + // Check for nil value and nil error. + if tpt == (reflect.Value{}) { + return nil, fmt.Errorf("unspecified error") + } + switch tpt.Kind() { + case reflect.Ptr, reflect.Interface, reflect.Func: + if tpt.IsNil() { + return nil, fmt.Errorf("unspecified error") + } + } + + return tpt.Interface(), nil + default: + panic("expected 1 or 2 return values from transport constructor") + } +} + +// calls the transport constructor and annotates the error with the name of the constructor. +func callConstructor(c reflect.Value, args []reflect.Value) (interface{}, error) { + val, err := handleReturnValue(c.Call(args)) + if err != nil { + name := runtime.FuncForPC(c.Pointer()).Name() + if name != "" { + // makes debugging easier + return nil, fmt.Errorf("transport constructor %s failed: %s", name, err) + } + } + return val, err +} + +type constructor func(h host.Host, u *tptu.Upgrader) interface{} + +func makeArgumentConstructors(fnType reflect.Type, argTypes map[reflect.Type]constructor) ([]constructor, error) { + out := make([]constructor, fnType.NumIn()) + for i := range out { + argType := fnType.In(i) + c, ok := argTypes[argType] + if !ok { + return nil, fmt.Errorf("argument %d has an unexpected type %s", i, argType.Name()) + } + out[i] = c + } + return out, nil +} + +// makes a transport constructor. +func makeConstructor( + tpt interface{}, + tptType reflect.Type, + argTypes map[reflect.Type]constructor, +) (func(host.Host, *tptu.Upgrader) (interface{}, error), error) { + v := reflect.ValueOf(tpt) + // avoid panicing on nil/zero value. + if v == (reflect.Value{}) { + return nil, fmt.Errorf("expected a transport or transport constructor, got a %T", tpt) + } + t := v.Type() + if t.Kind() != reflect.Func { + return nil, fmt.Errorf("expected a transport or transport constructor, got a %T", tpt) + } + + if err := checkReturnType(t, tptType); err != nil { + return nil, err + } + + argConstructors, err := makeArgumentConstructors(t, argTypes) + if err != nil { + return nil, err + } + + return func(h host.Host, u *tptu.Upgrader) (interface{}, error) { + arguments := make([]reflect.Value, len(argConstructors)) + for i, makeArg := range argConstructors { + arguments[i] = reflect.ValueOf(makeArg(h, u)) + } + return callConstructor(v, arguments) + }, nil +} diff --git a/config/reflection_magic_test.go b/config/reflection_magic_test.go new file mode 100644 index 000000000..ce9f3986f --- /dev/null +++ b/config/reflection_magic_test.go @@ -0,0 +1,142 @@ +package config + +import ( + "errors" + "reflect" + "strings" + "testing" +) + +func TestHandleReturnValue(t *testing.T) { + // one value + v, err := handleReturnValue([]reflect.Value{reflect.ValueOf(1)}) + if v.(int) != 1 { + t.Fatal("expected value") + } + if err != nil { + t.Fatal(err) + } + + // Nil value + v, err = handleReturnValue([]reflect.Value{reflect.ValueOf(nil)}) + if v != nil { + t.Fatal("expected no value") + } + if err == nil { + t.Fatal("expected an error") + } + + // Nil value, nil err + v, err = handleReturnValue([]reflect.Value{reflect.ValueOf(nil), reflect.ValueOf(nil)}) + if v != nil { + t.Fatal("expected no value") + } + if err == nil { + t.Fatal("expected an error") + } + + // two values + v, err = handleReturnValue([]reflect.Value{reflect.ValueOf(1), reflect.ValueOf(nil)}) + if v, ok := v.(int); !ok || v != 1 { + t.Fatalf("expected value of 1, got %v", v) + } + if err != nil { + t.Fatal("expected no error") + } + + // an error + myError := errors.New("my error") + _, err = handleReturnValue([]reflect.Value{reflect.ValueOf(1), reflect.ValueOf(myError)}) + if err != myError { + t.Fatal(err) + } + + for _, vals := range [][]reflect.Value{ + {reflect.ValueOf(1), reflect.ValueOf("not an error")}, + {}, + {reflect.ValueOf(1), reflect.ValueOf(myError), reflect.ValueOf(myError)}, + } { + func() { + defer func() { recover() }() + handleReturnValue(vals) + t.Fatal("expected a panic") + }() + } +} + +type foo interface { + foo() foo +} + +var fooType = reflect.TypeOf((*foo)(nil)).Elem() + +func TestCheckReturnType(t *testing.T) { + for i, fn := range []interface{}{ + func() { panic("") }, + func() error { panic("") }, + func() (error, error) { panic("") }, + func() (foo, error, error) { panic("") }, + func() (foo, foo) { panic("") }, + } { + if checkReturnType(reflect.TypeOf(fn), fooType) == nil { + t.Errorf("expected falure for case %d (type %T)", i, fn) + } + } + + for i, fn := range []interface{}{ + func() foo { panic("") }, + func() (foo, error) { panic("") }, + } { + if err := checkReturnType(reflect.TypeOf(fn), fooType); err != nil { + t.Errorf("expected success for case %d (type %T), got: %s", i, fn, err) + } + } +} + +func constructFoo() foo { + return nil +} + +type fooImpl struct{} + +func (f *fooImpl) foo() foo { return nil } + +func TestCallConstructor(t *testing.T) { + _, err := callConstructor(reflect.ValueOf(constructFoo), nil) + if err == nil { + t.Fatal("expected constructor to fail") + } + + if !strings.Contains(err.Error(), "constructFoo") { + t.Errorf("expected error to contain the constructor name: %s", err) + } + + v, err := callConstructor(reflect.ValueOf(func() foo { return &fooImpl{} }), nil) + if err != nil { + t.Fatal(err) + } + if _, ok := v.(*fooImpl); !ok { + t.Fatal("expected a fooImpl") + } + + v, err = callConstructor(reflect.ValueOf(func() *fooImpl { return new(fooImpl) }), nil) + if err != nil { + t.Fatal(err) + } + if _, ok := v.(*fooImpl); !ok { + t.Fatal("expected a fooImpl") + } + + _, err = callConstructor(reflect.ValueOf(func() (*fooImpl, error) { return nil, nil }), nil) + if err == nil { + t.Fatal("expected error") + } + + v, err = callConstructor(reflect.ValueOf(func() (*fooImpl, error) { return new(fooImpl), nil }), nil) + if err != nil { + t.Fatal(err) + } + if _, ok := v.(*fooImpl); !ok { + t.Fatal("expected a fooImpl") + } +} diff --git a/config/security.go b/config/security.go new file mode 100644 index 000000000..c3639728f --- /dev/null +++ b/config/security.go @@ -0,0 +1,76 @@ +package config + +import ( + "fmt" + + security "github.com/libp2p/go-conn-security" + csms "github.com/libp2p/go-conn-security-multistream" + insecure "github.com/libp2p/go-conn-security/insecure" + host "github.com/libp2p/go-libp2p-host" + peer "github.com/libp2p/go-libp2p-peer" +) + +// SecC is a security transport constructor +type SecC func(h host.Host) (security.Transport, error) + +// MsSecC is a tuple containing a security transport constructor and a protocol +// ID. +type MsSecC struct { + SecC + ID string +} + +var securityArgTypes = newArgTypeSet( + hostType, networkType, peerIDType, + privKeyType, pubKeyType, pstoreType, +) + +// SecurityConstructor creates a security constructor from the passed parameter +// using reflection. +func SecurityConstructor(sec interface{}) (SecC, error) { + // Already constructed? + if t, ok := sec.(security.Transport); ok { + return func(_ host.Host) (security.Transport, error) { + return t, nil + }, nil + } + + ctor, err := makeConstructor(sec, securityType, securityArgTypes) + if err != nil { + return nil, err + } + return func(h host.Host) (security.Transport, error) { + t, err := ctor(h, nil) + if err != nil { + return nil, err + } + return t.(security.Transport), nil + }, nil +} + +func makeInsecureTransport(id peer.ID) security.Transport { + secMuxer := new(csms.SSMuxer) + secMuxer.AddTransport(insecure.ID, insecure.New(id)) + return secMuxer +} + +func makeSecurityTransport(h host.Host, tpts []MsSecC) (security.Transport, error) { + secMuxer := new(csms.SSMuxer) + transportSet := make(map[string]struct{}, len(tpts)) + for _, tptC := range tpts { + if _, ok := transportSet[tptC.ID]; ok { + return nil, fmt.Errorf("duplicate security transport: %s", tptC.ID) + } + } + for _, tptC := range tpts { + tpt, err := tptC.SecC(h) + if err != nil { + return nil, err + } + if _, ok := tpt.(*insecure.Transport); ok { + return nil, fmt.Errorf("cannot construct libp2p with an insecure transport, set the Insecure config option instead") + } + secMuxer.AddTransport(tptC.ID, tpt) + } + return secMuxer, nil +} diff --git a/config/transport.go b/config/transport.go new file mode 100644 index 000000000..d9b4414d3 --- /dev/null +++ b/config/transport.go @@ -0,0 +1,66 @@ +package config + +import ( + host "github.com/libp2p/go-libp2p-host" + transport "github.com/libp2p/go-libp2p-transport" + tptu "github.com/libp2p/go-libp2p-transport-upgrader" +) + +// TptC is the type for libp2p transport constructors. You probably won't ever +// implement this function interface directly. Instead, pass your transport +// constructor to TransportConstructor. +type TptC func(h host.Host, u *tptu.Upgrader) (transport.Transport, error) + +var transportArgTypes = argTypes + +// TransportConstructor uses reflection to turn a function that constructs a +// transport into a TptC. +// +// You can pass either a constructed transport (something that implements +// `transport.Transport`) or a function that takes any of: +// +// * The local peer ID. +// * A transport connection upgrader. +// * A private key. +// * A public key. +// * A Host. +// * A Network. +// * A Peerstore. +// * An address filter. +// * A security transport. +// * A stream multiplexer transport. +// * A private network protector. +// +// And returns a type implementing transport.Transport and, optionally, an error +// (as the second argument). +func TransportConstructor(tpt interface{}) (TptC, error) { + // Already constructed? + if t, ok := tpt.(transport.Transport); ok { + return func(_ host.Host, _ *tptu.Upgrader) (transport.Transport, error) { + return t, nil + }, nil + } + ctor, err := makeConstructor(tpt, transportType, transportArgTypes) + if err != nil { + return nil, err + } + return func(h host.Host, u *tptu.Upgrader) (transport.Transport, error) { + t, err := ctor(h, u) + if err != nil { + return nil, err + } + return t.(transport.Transport), nil + }, nil +} + +func makeTransports(h host.Host, u *tptu.Upgrader, tpts []TptC) ([]transport.Transport, error) { + transports := make([]transport.Transport, len(tpts)) + for i, tC := range tpts { + t, err := tC(h, u) + if err != nil { + return nil, err + } + transports[i] = t + } + return transports, nil +} diff --git a/defaults.go b/defaults.go new file mode 100644 index 000000000..d3fa618d6 --- /dev/null +++ b/defaults.go @@ -0,0 +1,109 @@ +package libp2p + +// This file contains all the default configuration options. + +import ( + "crypto/rand" + + crypto "github.com/libp2p/go-libp2p-crypto" + pstore "github.com/libp2p/go-libp2p-peerstore" + secio "github.com/libp2p/go-libp2p-secio" + tcp "github.com/libp2p/go-tcp-transport" + ws "github.com/libp2p/go-ws-transport" + mplex "github.com/whyrusleeping/go-smux-multiplex" + yamux "github.com/whyrusleeping/go-smux-yamux" +) + +// DefaultSecurity is the default security option. +// +// Useful when you want to extend, but not replace, the supported transport +// security protocols. +var DefaultSecurity = Security(secio.ID, secio.New) + +// DefaultMuxer configures libp2p to use the stream connection multiplexers. +// +// Use this option when you want to *extend* the set of multiplexers used by +// libp2p instead of replacing them. +var DefaultMuxers = ChainOptions( + Muxer("/yamux/1.0.0", yamux.DefaultTransport), + Muxer("/mplex/6.3.0", mplex.DefaultTransport), +) + +// DefaultTransports are the default libp2p transports. +// +// Use this option when you want to *extend* the set of multiplexers used by +// libp2p instead of replacing them. +var DefaultTransports = ChainOptions( + Transport(tcp.NewTCPTransport), + Transport(ws.New), +) + +// DefaultPeerstore configures libp2p to use the default peerstore. +var DefaultPeerstore Option = func(cfg *Config) error { + return cfg.Apply(Peerstore(pstore.NewPeerstore())) +} + +// RandomIdentity generates a random identity (default behaviour) +var RandomIdentity = func(cfg *Config) error { + priv, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, rand.Reader) + if err != nil { + return err + } + return cfg.Apply(Identity(priv)) +} + +// Complete list of default options and when to fallback on them. +// +// Please *DON'T* specify default options any other way. Putting this all here +// makes tracking defaults *much* easier. +var defaults = []struct { + fallback func(cfg *Config) bool + opt Option +}{ + { + fallback: func(cfg *Config) bool { return cfg.Transports == nil }, + opt: DefaultTransports, + }, + { + fallback: func(cfg *Config) bool { return cfg.Muxers == nil }, + opt: DefaultMuxers, + }, + { + fallback: func(cfg *Config) bool { return !cfg.Insecure && cfg.SecurityTransports == nil }, + opt: DefaultSecurity, + }, + { + fallback: func(cfg *Config) bool { return cfg.PeerKey == nil }, + opt: RandomIdentity, + }, + { + fallback: func(cfg *Config) bool { return cfg.Peerstore == nil }, + opt: DefaultPeerstore, + }, +} + +// Defaults configures libp2p to use the default options. Can be combined with +// other options to *extend* the default options. +var Defaults Option = func(cfg *Config) error { + for _, def := range defaults { + if err := cfg.Apply(def.opt); err != nil { + return err + } + } + return nil +} + +// FallbackDefaults applies default options to the libp2p node if and only if no +// other relevent options have been applied. will be appended to the options +// passed into New. +var FallbackDefaults Option = func(cfg *Config) error { + for _, def := range defaults { + if !def.fallback(cfg) { + continue + } + if err := cfg.Apply(def.opt); err != nil { + return err + } + } + return nil +} diff --git a/error_util.go b/error_util.go new file mode 100644 index 000000000..86827f4ea --- /dev/null +++ b/error_util.go @@ -0,0 +1,17 @@ +package libp2p + +import ( + "fmt" + "runtime" +) + +func traceError(err error, skip int) error { + if err == nil { + return nil + } + _, file, line, ok := runtime.Caller(skip + 1) + if !ok { + return err + } + return fmt.Errorf("%s:%d: %s", file, line, err) +} diff --git a/examples/chat/chat.go b/examples/chat/chat.go index 8f211ba94..942cb1e32 100644 --- a/examples/chat/chat.go +++ b/examples/chat/chat.go @@ -39,13 +39,13 @@ import ( mrand "math/rand" "os" + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p-crypto" "github.com/libp2p/go-libp2p-host" "github.com/libp2p/go-libp2p-net" "github.com/libp2p/go-libp2p-peer" "github.com/libp2p/go-libp2p-peerstore" - "github.com/libp2p/go-libp2p-swarm" - "github.com/libp2p/go-libp2p/p2p/host/basic" "github.com/multiformats/go-multiaddr" ) @@ -155,37 +155,27 @@ func main() { } // Creates a new RSA key pair for this host - prvKey, pubKey, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r) + prvKey, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r) if err != nil { panic(err) } - // Getting host ID from public key. - // host ID is the hash of public key - nodeID, _ := peer.IDFromPublicKey(pubKey) - // 0.0.0.0 will listen on any interface device sourceMultiAddr, _ := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", *sourcePort)) - // Adding self to the peerstore. - ps := peerstore.NewPeerstore() - ps.AddPrivKey(nodeID, prvKey) - ps.AddPubKey(nodeID, pubKey) - - // Creating a new Swarm network. - network, err := swarm.NewNetwork(context.Background(), []multiaddr.Multiaddr{sourceMultiAddr}, nodeID, ps, nil) + // libp2p.New constructs a new libp2p Host. + // Other options can be added here. + host, err := libp2p.New( + context.Background(), + libp2p.ListenAddrs(sourceMultiAddr), + libp2p.Identity(prvKey), + ) if err != nil { panic(err) } - // NewHost constructs a new *BasicHost and activates it by attaching its - // stream and connection handlers to the given inet.Network (network). - // Other options like NATManager can also be added here. - // See docs: https://godoc.org/github.com/libp2p/go-libp2p/p2p/host/basic#HostOpts - host := basichost.New(network) - if *dest == "" { // Set a function as stream handler. // This function is called when a peer initiate a connection and starts a stream with this peer. diff --git a/examples/echo/main.go b/examples/echo/main.go index 412df18fc..32d156b73 100644 --- a/examples/echo/main.go +++ b/examples/echo/main.go @@ -49,7 +49,7 @@ func makeBasicHost(listenPort int, secio bool, randseed int64) (host.Host, error } if !secio { - opts = append(opts, libp2p.NoEncryption()) + opts = append(opts, libp2p.NoSecurity) } basicHost, err := libp2p.New(context.Background(), opts...) diff --git a/examples/http-proxy/proxy.go b/examples/http-proxy/proxy.go index f8206a8ca..07e36b0db 100644 --- a/examples/http-proxy/proxy.go +++ b/examples/http-proxy/proxy.go @@ -12,16 +12,14 @@ import ( // We need to import libp2p's libraries that we use in this project. // In order to work, these libraries need to be rewritten by gx-go. - crypto "github.com/libp2p/go-libp2p-crypto" host "github.com/libp2p/go-libp2p-host" inet "github.com/libp2p/go-libp2p-net" peer "github.com/libp2p/go-libp2p-peer" ps "github.com/libp2p/go-libp2p-peerstore" - swarm "github.com/libp2p/go-libp2p-swarm" ma "github.com/multiformats/go-multiaddr" manet "github.com/multiformats/go-multiaddr-net" - bhost "github.com/libp2p/go-libp2p/p2p/host/basic" + libp2p "github.com/libp2p/go-libp2p" ) // Protocol defines the libp2p protocol that we will use for the libp2p proxy @@ -33,27 +31,11 @@ const Protocol = "/proxy-example/0.0.1" // makeRandomHost creates a libp2p host with a randomly generated identity. // This step is described in depth in other tutorials. func makeRandomHost(port int) host.Host { - priv, pub, err := crypto.GenerateKeyPair(crypto.RSA, 2048) + host, err := libp2p.New(context.Background(), libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port))) if err != nil { log.Fatalln(err) } - pid, err := peer.IDFromPublicKey(pub) - if err != nil { - log.Fatalln(err) - } - listen, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port)) - if err != nil { - log.Fatalln(err) - } - ps := ps.NewPeerstore() - ps.AddPrivKey(pid, priv) - ps.AddPubKey(pid, pub) - n, err := swarm.NewNetwork(context.Background(), - []ma.Multiaddr{listen}, pid, ps, nil) - if err != nil { - log.Fatalln(err) - } - return bhost.New(n) + return host } // ProxyService provides HTTP proxying on top of libp2p by launching an diff --git a/examples/multipro/main.go b/examples/multipro/main.go index 4f9e144c2..3350ea383 100644 --- a/examples/multipro/main.go +++ b/examples/multipro/main.go @@ -6,11 +6,9 @@ import ( "log" "math/rand" + libp2p "github.com/libp2p/go-libp2p" crypto "github.com/libp2p/go-libp2p-crypto" - peer "github.com/libp2p/go-libp2p-peer" ps "github.com/libp2p/go-libp2p-peerstore" - swarm "github.com/libp2p/go-libp2p-swarm" - bhost "github.com/libp2p/go-libp2p/p2p/host/basic" ma "github.com/multiformats/go-multiaddr" ) @@ -18,14 +16,13 @@ import ( func makeRandomNode(port int, done chan bool) *Node { // Ignoring most errors for brevity // See echo example for more details and better implementation - priv, pub, _ := crypto.GenerateKeyPair(crypto.Secp256k1, 256) - pid, _ := peer.IDFromPublicKey(pub) + priv, _, _ := crypto.GenerateKeyPair(crypto.Secp256k1, 256) listen, _ := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port)) - peerStore := ps.NewPeerstore() - peerStore.AddPrivKey(pid, priv) - peerStore.AddPubKey(pid, pub) - n, _ := swarm.NewNetwork(context.Background(), []ma.Multiaddr{listen}, pid, peerStore, nil) - host := bhost.New(n) + host, _ := libp2p.New( + context.Background(), + libp2p.ListenAddrs(listen), + libp2p.Identity(priv), + ) return NewNode(host, done) } diff --git a/examples/protocol-multiplexing-with-multicodecs/main.go b/examples/protocol-multiplexing-with-multicodecs/main.go index 86c069b29..5aa4f6fd6 100644 --- a/examples/protocol-multiplexing-with-multicodecs/main.go +++ b/examples/protocol-multiplexing-with-multicodecs/main.go @@ -8,15 +8,11 @@ import ( "math/rand" "time" - crypto "github.com/libp2p/go-libp2p-crypto" host "github.com/libp2p/go-libp2p-host" inet "github.com/libp2p/go-libp2p-net" - peer "github.com/libp2p/go-libp2p-peer" ps "github.com/libp2p/go-libp2p-peerstore" - swarm "github.com/libp2p/go-libp2p-swarm" - ma "github.com/multiformats/go-multiaddr" - bhost "github.com/libp2p/go-libp2p/p2p/host/basic" + libp2p "github.com/libp2p/go-libp2p" multicodec "github.com/multiformats/go-multicodec" json "github.com/multiformats/go-multicodec/json" ) @@ -80,17 +76,11 @@ var conversationMsgs = []string{ } func makeRandomHost(port int) host.Host { - // Ignoring most errors for brevity - // See echo example for more details and better implementation - priv, pub, _ := crypto.GenerateKeyPair(crypto.RSA, 2048) - pid, _ := peer.IDFromPublicKey(pub) - listen, _ := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port)) - ps := ps.NewPeerstore() - ps.AddPrivKey(pid, priv) - ps.AddPubKey(pid, pub) - n, _ := swarm.NewNetwork(context.Background(), - []ma.Multiaddr{listen}, pid, ps, nil) - return bhost.New(n) + h, err := libp2p.New(context.Background(), libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port))) + if err != nil { + panic(err) + } + return h } func main() { diff --git a/libp2p.go b/libp2p.go index bfb0c1819..936b2220d 100644 --- a/libp2p.go +++ b/libp2p.go @@ -2,240 +2,49 @@ package libp2p import ( "context" - "crypto/rand" - "fmt" - crypto "github.com/libp2p/go-libp2p-crypto" + config "github.com/libp2p/go-libp2p/config" + host "github.com/libp2p/go-libp2p-host" - pnet "github.com/libp2p/go-libp2p-interface-pnet" - metrics "github.com/libp2p/go-libp2p-metrics" - peer "github.com/libp2p/go-libp2p-peer" - pstore "github.com/libp2p/go-libp2p-peerstore" - swarm "github.com/libp2p/go-libp2p-swarm" - transport "github.com/libp2p/go-libp2p-transport" - bhost "github.com/libp2p/go-libp2p/p2p/host/basic" - mux "github.com/libp2p/go-stream-muxer" - ma "github.com/multiformats/go-multiaddr" - mplex "github.com/whyrusleeping/go-smux-multiplex" - msmux "github.com/whyrusleeping/go-smux-multistream" - yamux "github.com/whyrusleeping/go-smux-yamux" ) // Config describes a set of settings for a libp2p node -type Config struct { - Transports []transport.Transport - Muxer mux.Transport - ListenAddrs []ma.Multiaddr - PeerKey crypto.PrivKey - Peerstore pstore.Peerstore - Protector pnet.Protector - Reporter metrics.Reporter - DisableSecio bool - EnableNAT bool -} - -type Option func(cfg *Config) error +type Config = config.Config -func Transports(tpts ...transport.Transport) Option { - return func(cfg *Config) error { - cfg.Transports = append(cfg.Transports, tpts...) - return nil - } -} +// Option is a libp2p config option that can be given to the libp2p constructor +// (`libp2p.New`). +type Option = config.Option -func ListenAddrStrings(s ...string) Option { +// ChainOptions chains multiple options into a single option. +func ChainOptions(opts ...Option) Option { return func(cfg *Config) error { - for _, addrstr := range s { - a, err := ma.NewMultiaddr(addrstr) - if err != nil { + for _, opt := range opts { + if err := opt(cfg); err != nil { return err } - cfg.ListenAddrs = append(cfg.ListenAddrs, a) - } - return nil - } -} - -func ListenAddrs(addrs ...ma.Multiaddr) Option { - return func(cfg *Config) error { - cfg.ListenAddrs = append(cfg.ListenAddrs, addrs...) - return nil - } -} - -type transportEncOpt int - -const ( - EncPlaintext = transportEncOpt(0) - EncSecio = transportEncOpt(1) -) - -func TransportEncryption(tenc ...transportEncOpt) Option { - return func(cfg *Config) error { - if len(tenc) != 1 { - return fmt.Errorf("can only specify a single transport encryption option right now") - } - - // TODO: actually make this pluggable, otherwise tls will get tricky - switch tenc[0] { - case EncPlaintext: - cfg.DisableSecio = true - case EncSecio: - // noop - default: - return fmt.Errorf("unrecognized transport encryption option: %d", tenc[0]) - } - return nil - } -} - -func NoEncryption() Option { - return TransportEncryption(EncPlaintext) -} - -func NATPortMap() Option { - return func(cfg *Config) error { - cfg.EnableNAT = true - return nil - } -} - -func Muxer(m mux.Transport) Option { - return func(cfg *Config) error { - if cfg.Muxer != nil { - return fmt.Errorf("cannot specify multiple muxer options") } - - cfg.Muxer = m - return nil - } -} - -func Peerstore(ps pstore.Peerstore) Option { - return func(cfg *Config) error { - if cfg.Peerstore != nil { - return fmt.Errorf("cannot specify multiple peerstore options") - } - - cfg.Peerstore = ps - return nil - } -} - -func PrivateNetwork(prot pnet.Protector) Option { - return func(cfg *Config) error { - if cfg.Protector != nil { - return fmt.Errorf("cannot specify multiple private network options") - } - - cfg.Protector = prot - return nil - } -} - -func BandwidthReporter(rep metrics.Reporter) Option { - return func(cfg *Config) error { - if cfg.Reporter != nil { - return fmt.Errorf("cannot specify multiple bandwidth reporter options") - } - - cfg.Reporter = rep - return nil - } -} - -func Identity(sk crypto.PrivKey) Option { - return func(cfg *Config) error { - if cfg.PeerKey != nil { - return fmt.Errorf("cannot specify multiple identities") - } - - cfg.PeerKey = sk return nil } } +// New constructs a new libp2p node with the given options (falling back on +// reasonable defaults). +// +// Canceling the passed context will stop the returned libp2p node. func New(ctx context.Context, opts ...Option) (host.Host, error) { - var cfg Config - for _, opt := range opts { - if err := opt(&cfg); err != nil { - return nil, err - } - } - - return newWithCfg(ctx, &cfg) + return NewWithoutDefaults(ctx, append(opts, FallbackDefaults)...) } -func newWithCfg(ctx context.Context, cfg *Config) (host.Host, error) { - // If no key was given, generate a random 2048 bit RSA key - if cfg.PeerKey == nil { - priv, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, rand.Reader) - if err != nil { - return nil, err - } - cfg.PeerKey = priv - } - - // Obtain Peer ID from public key - pid, err := peer.IDFromPublicKey(cfg.PeerKey.GetPublic()) - if err != nil { - return nil, err - } - - // Create a new blank peerstore if none was passed in - ps := cfg.Peerstore - if ps == nil { - ps = pstore.NewPeerstore() - } - - // Set default muxer if none was passed in - muxer := cfg.Muxer - if muxer == nil { - muxer = DefaultMuxer() - } - - // If secio is disabled, don't add our private key to the peerstore - if !cfg.DisableSecio { - ps.AddPrivKey(pid, cfg.PeerKey) - ps.AddPubKey(pid, cfg.PeerKey.GetPublic()) - } - - swrm, err := swarm.NewSwarmWithProtector(ctx, cfg.ListenAddrs, pid, ps, cfg.Protector, muxer, cfg.Reporter) - if err != nil { +// NewWithoutDefaults constructs a new libp2p node with the given options but +// *without* falling back on reasonable defaults. +// +// Warning: This function should not be considered a stable interface. We may +// choose to add required services at any time and, by using this function, you +// opt-out of any defaults we may provide. +func NewWithoutDefaults(ctx context.Context, opts ...Option) (host.Host, error) { + var cfg Config + if err := cfg.Apply(opts...); err != nil { return nil, err } - - netw := (*swarm.Network)(swrm) - - hostOpts := &bhost.HostOpts{} - - if cfg.EnableNAT { - hostOpts.NATManager = bhost.NewNATManager(netw) - } - - return bhost.NewHost(ctx, netw, hostOpts) -} - -func DefaultMuxer() mux.Transport { - // Set up stream multiplexer - tpt := msmux.NewBlankTransport() - - // By default, support yamux and multiplex - tpt.AddTransport("/yamux/1.0.0", yamux.DefaultTransport) - tpt.AddTransport("/mplex/6.3.0", mplex.DefaultTransport) - - return tpt -} - -func Defaults(cfg *Config) error { - // Create a multiaddress that listens on a random port on all interfaces - addr, err := ma.NewMultiaddr("/ip4/0.0.0.0/tcp/0") - if err != nil { - return err - } - - cfg.ListenAddrs = []ma.Multiaddr{addr} - cfg.Peerstore = pstore.NewPeerstore() - cfg.Muxer = DefaultMuxer() - return nil + return cfg.NewNode(ctx) } diff --git a/libp2p_test.go b/libp2p_test.go index d2ab62e4d..1b38bbc36 100644 --- a/libp2p_test.go +++ b/libp2p_test.go @@ -3,6 +3,7 @@ package libp2p import ( "context" "fmt" + "strings" "testing" crypto "github.com/libp2p/go-libp2p-crypto" @@ -10,10 +11,32 @@ import ( ) func TestNewHost(t *testing.T) { - _, err := makeRandomHost(t, 9000) + h, err := makeRandomHost(t, 9000) if err != nil { t.Fatal(err) } + h.Close() +} + +func TestBadTransportConstructor(t *testing.T) { + ctx := context.Background() + h, err := New(ctx, Transport(func() {})) + if err == nil { + h.Close() + t.Fatal("expected an error") + } + if !strings.Contains(err.Error(), "libp2p_test.go") { + t.Error("expected error to contain debugging info") + } +} + +func TestInsecure(t *testing.T) { + ctx := context.Background() + h, err := New(ctx, NoSecurity) + if err != nil { + t.Fatal(err) + } + h.Close() } func makeRandomHost(t *testing.T, port int) (host.Host, error) { @@ -26,7 +49,9 @@ func makeRandomHost(t *testing.T, port int) (host.Host, error) { opts := []Option{ ListenAddrStrings(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port)), Identity(priv), - Muxer(DefaultMuxer()), + DefaultTransports, + DefaultMuxers, + DefaultSecurity, NATPortMap(), } diff --git a/options.go b/options.go new file mode 100644 index 000000000..a17fc02e8 --- /dev/null +++ b/options.go @@ -0,0 +1,243 @@ +package libp2p + +// This file contains all libp2p configuration options (except the defaults, +// those are in defaults.go) + +import ( + "fmt" + "net" + + config "github.com/libp2p/go-libp2p/config" + bhost "github.com/libp2p/go-libp2p/p2p/host/basic" + + circuit "github.com/libp2p/go-libp2p-circuit" + crypto "github.com/libp2p/go-libp2p-crypto" + ifconnmgr "github.com/libp2p/go-libp2p-interface-connmgr" + pnet "github.com/libp2p/go-libp2p-interface-pnet" + metrics "github.com/libp2p/go-libp2p-metrics" + pstore "github.com/libp2p/go-libp2p-peerstore" + filter "github.com/libp2p/go-maddr-filter" + ma "github.com/multiformats/go-multiaddr" +) + +// ListenAddrStrings configures libp2p to listen on the given (unparsed) +// addresses. +func ListenAddrStrings(s ...string) Option { + return func(cfg *Config) error { + for _, addrstr := range s { + a, err := ma.NewMultiaddr(addrstr) + if err != nil { + return err + } + cfg.ListenAddrs = append(cfg.ListenAddrs, a) + } + return nil + } +} + +// ListenAddrs configures libp2p to listen on the given addresses. +func ListenAddrs(addrs ...ma.Multiaddr) Option { + return func(cfg *Config) error { + cfg.ListenAddrs = append(cfg.ListenAddrs, addrs...) + return nil + } +} + +// Security configures libp2p to use the given security transport (or transport +// constructor). +// +// Name is the protocol name. +// +// The transport can be a constructed security.Transport or a function taking +// any subset of this libp2p node's: +// * Public key +// * Private key +// * Peer ID +// * Host +// * Network +// * Peerstore +func Security(name string, tpt interface{}) Option { + stpt, err := config.SecurityConstructor(tpt) + err = traceError(err, 1) + return func(cfg *Config) error { + if err != nil { + return err + } + if cfg.Insecure { + return fmt.Errorf("cannot use security transports with an insecure libp2p configuration") + } + cfg.SecurityTransports = append(cfg.SecurityTransports, config.MsSecC{SecC: stpt, ID: name}) + return nil + } +} + +// NoSecurity is an option that completely disables all transport security. +// It's incompatible with all other transport security protocols. +var NoSecurity Option = func(cfg *Config) error { + if len(cfg.SecurityTransports) > 0 { + return fmt.Errorf("cannot use security transports with an insecure libp2p configuration") + } + cfg.Insecure = true + return nil +} + +// Muxer configures libp2p to use the given stream multiplexer (or stream +// multiplexer constructor). +// +// Name is the protocol name. +// +// The transport can be a constructed mux.Transport or a function taking any +// subset of this libp2p node's: +// * Peer ID +// * Host +// * Network +// * Peerstore +func Muxer(name string, tpt interface{}) Option { + mtpt, err := config.MuxerConstructor(tpt) + err = traceError(err, 1) + return func(cfg *Config) error { + if err != nil { + return err + } + cfg.Muxers = append(cfg.Muxers, config.MsMuxC{MuxC: mtpt, ID: name}) + return nil + } +} + +// Transport configures libp2p to use the given transport (or transport +// constructor). +// +// The transport can be a constructed transport.Transport or a function taking +// any subset of this libp2p node's: +// * Transport Upgrader (*tptu.Upgrader) +// * Host +// * Stream muxer (muxer.Transport) +// * Security transport (security.Transport) +// * Private network protector (pnet.Protector) +// * Peer ID +// * Private Key +// * Public Key +// * Address filter (filter.Filter) +// * Peerstore +func Transport(tpt interface{}) Option { + tptc, err := config.TransportConstructor(tpt) + err = traceError(err, 1) + return func(cfg *Config) error { + if err != nil { + return err + } + cfg.Transports = append(cfg.Transports, tptc) + return nil + } +} + +// Peerstore configures libp2p to use the given peerstore. +func Peerstore(ps pstore.Peerstore) Option { + return func(cfg *Config) error { + if cfg.Peerstore != nil { + return fmt.Errorf("cannot specify multiple peerstore options") + } + + cfg.Peerstore = ps + return nil + } +} + +// PrivateNetwork configures libp2p to use the given private network protector. +func PrivateNetwork(prot pnet.Protector) Option { + return func(cfg *Config) error { + if cfg.Protector != nil { + return fmt.Errorf("cannot specify multiple private network options") + } + + cfg.Protector = prot + return nil + } +} + +// BandwidthReporter configures libp2p to use the given bandwidth reporter. +func BandwidthReporter(rep metrics.Reporter) Option { + return func(cfg *Config) error { + if cfg.Reporter != nil { + return fmt.Errorf("cannot specify multiple bandwidth reporter options") + } + + cfg.Reporter = rep + return nil + } +} + +// Identity configures libp2p to use the given private key to identify itself. +func Identity(sk crypto.PrivKey) Option { + return func(cfg *Config) error { + if cfg.PeerKey != nil { + return fmt.Errorf("cannot specify multiple identities") + } + + cfg.PeerKey = sk + return nil + } +} + +// ConnectionManager configures libp2p to use the given connection manager. +func ConnectionManager(connman ifconnmgr.ConnManager) Option { + return func(cfg *Config) error { + if cfg.ConnManager != nil { + return fmt.Errorf("cannot specify multiple connection managers") + } + cfg.ConnManager = connman + return nil + } +} + +// AddrsFactory configures libp2p to use the given address factory. +func AddrsFactory(factory config.AddrsFactory) Option { + return func(cfg *Config) error { + if cfg.AddrsFactory != nil { + return fmt.Errorf("cannot specify multiple address factories") + } + cfg.AddrsFactory = factory + return nil + } +} + +// EnableRelay configures libp2p to enable the relay transport. +func EnableRelay(options ...circuit.RelayOpt) Option { + return func(cfg *Config) error { + cfg.Relay = true + cfg.RelayOpts = options + return nil + } +} + +// FilterAddresses configures libp2p to never dial nor accept connections from +// the given addresses. +func FilterAddresses(addrs ...*net.IPNet) Option { + return func(cfg *Config) error { + if cfg.Filters == nil { + cfg.Filters = filter.NewFilters() + } + for _, addr := range addrs { + cfg.Filters.AddDialFilter(addr) + } + return nil + } +} + +// NATPortMap configures libp2p to use the default NATManager. The default +// NATManager will attempt to open a port in your network's firewall using UPnP. +func NATPortMap() Option { + return NATManager(bhost.NewNATManager) +} + +// NATManager will configure libp2p to use the requested NATManager. This +// function should be passed a NATManager *constructor* that takes a libp2p Network. +func NATManager(nm config.NATManagerC) Option { + return func(cfg *Config) error { + if cfg.NATManager != nil { + return fmt.Errorf("cannot specify multiple NATManagers") + } + cfg.NATManager = nm + return nil + } +} diff --git a/p2p/discovery/mdns_test.go b/p2p/discovery/mdns_test.go index 579fc5bf6..bb0e84d6f 100644 --- a/p2p/discovery/mdns_test.go +++ b/p2p/discovery/mdns_test.go @@ -8,7 +8,7 @@ import ( bhost "github.com/libp2p/go-libp2p/p2p/host/basic" host "github.com/libp2p/go-libp2p-host" - netutil "github.com/libp2p/go-libp2p-netutil" + swarmt "github.com/libp2p/go-libp2p-swarm/testing" pstore "github.com/libp2p/go-libp2p-peerstore" ) @@ -28,8 +28,8 @@ func TestMdnsDiscovery(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - a := bhost.New(netutil.GenSwarmNetwork(t, ctx)) - b := bhost.New(netutil.GenSwarmNetwork(t, ctx)) + a := bhost.New(swarmt.GenSwarm(t, ctx)) + b := bhost.New(swarmt.GenSwarm(t, ctx)) sa, err := NewMdnsService(ctx, a, time.Second, "someTag") if err != nil { diff --git a/p2p/host/basic/basic_host.go b/p2p/host/basic/basic_host.go index 0d566f433..018f2691d 100644 --- a/p2p/host/basic/basic_host.go +++ b/p2p/host/basic/basic_host.go @@ -9,10 +9,8 @@ import ( logging "github.com/ipfs/go-log" goprocess "github.com/jbenet/goprocess" - circuit "github.com/libp2p/go-libp2p-circuit" + goprocessctx "github.com/jbenet/goprocess/context" ifconnmgr "github.com/libp2p/go-libp2p-interface-connmgr" - metrics "github.com/libp2p/go-libp2p-metrics" - mstream "github.com/libp2p/go-libp2p-metrics/stream" inet "github.com/libp2p/go-libp2p-net" peer "github.com/libp2p/go-libp2p-peer" pstore "github.com/libp2p/go-libp2p-peerstore" @@ -67,8 +65,6 @@ type BasicHost struct { negtimeout time.Duration proc goprocess.Process - - bwc metrics.Reporter } // HostOpts holds options that can be passed to NewHost in order to @@ -97,25 +93,14 @@ type HostOpts struct { // NATManager takes care of setting NAT port mappings, and discovering external addresses. // If omitted, this will simply be disabled. - NATManager NATManager - - // BandwidthReporter is used for collecting aggregate metrics of the - // bandwidth used by various protocols. - BandwidthReporter metrics.Reporter + NATManager func(inet.Network) NATManager // ConnManager is a libp2p connection manager ConnManager ifconnmgr.ConnManager - - // Relay indicates whether the host should use circuit relay transport - EnableRelay bool - - // RelayOpts are options for the relay transport; only meaningful when Relay=true - RelayOpts []circuit.RelayOpt } // NewHost constructs a new *BasicHost and activates it by attaching its stream and connection handlers to the given inet.Network. func NewHost(ctx context.Context, net inet.Network, opts *HostOpts) (*BasicHost, error) { - ctx, cancel := context.WithCancel(ctx) h := &BasicHost{ network: net, mux: msmux.NewMultistreamMuxer(), @@ -124,11 +109,10 @@ func NewHost(ctx context.Context, net inet.Network, opts *HostOpts) (*BasicHost, maResolver: madns.DefaultResolver, } - h.proc = goprocess.WithTeardown(func() error { + h.proc = goprocessctx.WithContextAndTeardown(ctx, func() error { if h.natmgr != nil { h.natmgr.Close() } - cancel() return h.Network().Close() }) @@ -152,18 +136,13 @@ func NewHost(ctx context.Context, net inet.Network, opts *HostOpts) (*BasicHost, } if opts.NATManager != nil { - h.natmgr = opts.NATManager + h.natmgr = opts.NATManager(net) } if opts.MultiaddrResolver != nil { h.maResolver = opts.MultiaddrResolver } - if opts.BandwidthReporter != nil { - h.bwc = opts.BandwidthReporter - h.ids.Reporter = opts.BandwidthReporter - } - if opts.ConnManager == nil { h.cmgr = &ifconnmgr.NullConnMgr{} } else { @@ -173,20 +152,16 @@ func NewHost(ctx context.Context, net inet.Network, opts *HostOpts) (*BasicHost, net.SetConnHandler(h.newConnHandler) net.SetStreamHandler(h.newStreamHandler) - - if opts.EnableRelay { - err := circuit.AddRelayTransport(ctx, h, opts.RelayOpts...) - if err != nil { - h.Close() - return nil, err - } - } - return h, nil } // New constructs and sets up a new *BasicHost with given Network and options. -// Three options can be passed: NATPortMap, AddrsFactory, and metrics.Reporter. +// The following options can be passed: +// * NATPortMap +// * AddrsFactory +// * ifconnmgr.ConnManager +// * madns.Resolver +// // This function is deprecated in favor of NewHost and HostOpts. func New(net inet.Network, opts ...interface{}) *BasicHost { hostopts := &HostOpts{} @@ -196,10 +171,8 @@ func New(net inet.Network, opts ...interface{}) *BasicHost { case Option: switch o { case NATPortMap: - hostopts.NATManager = newNatManager(net) + hostopts.NATManager = NewNATManager } - case metrics.Reporter: - hostopts.BandwidthReporter = o case AddrsFactory: hostopts.AddrsFactory = AddrsFactory(o) case ifconnmgr.ConnManager: @@ -270,10 +243,6 @@ func (h *BasicHost) newStreamHandler(s inet.Stream) { } s.SetProtocol(protocol.ID(protoID)) - - if h.bwc != nil { - s = mstream.WrapStream(s, h.bwc) - } log.Debugf("protocol negotiation took %s", took) go handle(protoID, s) @@ -366,10 +335,6 @@ func (h *BasicHost) NewStream(ctx context.Context, p peer.ID, pids ...protocol.I s.SetProtocol(selpid) h.Peerstore().AddProtocols(p, selected) - if h.bwc != nil { - s = mstream.WrapStream(s, h.bwc) - } - return s, nil } @@ -403,10 +368,6 @@ func (h *BasicHost) newStream(ctx context.Context, p peer.ID, pid protocol.ID) ( s.SetProtocol(pid) - if h.bwc != nil { - s = mstream.WrapStream(s, h.bwc) - } - lzcon := msmux.NewMSSelect(s, string(pid)) return &streamWrapper{ Stream: s, @@ -536,11 +497,6 @@ func (h *BasicHost) Close() error { return h.proc.Close() } -// GetBandwidthReporter exposes the Host's bandiwth metrics reporter -func (h *BasicHost) GetBandwidthReporter() metrics.Reporter { - return h.bwc -} - type streamWrapper struct { inet.Stream rw io.ReadWriter diff --git a/p2p/host/basic/basic_host_test.go b/p2p/host/basic/basic_host_test.go index 7cf8136e6..27c81d552 100644 --- a/p2p/host/basic/basic_host_test.go +++ b/p2p/host/basic/basic_host_test.go @@ -8,11 +8,13 @@ import ( "testing" "time" + testutil "github.com/libp2p/go-testutil" + host "github.com/libp2p/go-libp2p-host" inet "github.com/libp2p/go-libp2p-net" - testutil "github.com/libp2p/go-libp2p-netutil" pstore "github.com/libp2p/go-libp2p-peerstore" protocol "github.com/libp2p/go-libp2p-protocol" + swarmt "github.com/libp2p/go-libp2p-swarm/testing" ma "github.com/multiformats/go-multiaddr" madns "github.com/multiformats/go-multiaddr-dns" ) @@ -20,8 +22,8 @@ import ( func TestHostSimple(t *testing.T) { ctx := context.Background() - h1 := New(testutil.GenSwarmNetwork(t, ctx)) - h2 := New(testutil.GenSwarmNetwork(t, ctx)) + h1 := New(swarmt.GenSwarm(t, ctx)) + h2 := New(swarmt.GenSwarm(t, ctx)) defer h1.Close() defer h2.Close() @@ -74,7 +76,7 @@ func TestHostAddrsFactory(t *testing.T) { } ctx := context.Background() - h := New(testutil.GenSwarmNetwork(t, ctx), AddrsFactory(addrsFactory)) + h := New(swarmt.GenSwarm(t, ctx), AddrsFactory(addrsFactory)) defer h.Close() addrs := h.Addrs() @@ -87,8 +89,8 @@ func TestHostAddrsFactory(t *testing.T) { } func getHostPair(ctx context.Context, t *testing.T) (host.Host, host.Host) { - h1 := New(testutil.GenSwarmNetwork(t, ctx)) - h2 := New(testutil.GenSwarmNetwork(t, ctx)) + h1 := New(swarmt.GenSwarm(t, ctx)) + h2 := New(swarmt.GenSwarm(t, ctx)) h2pi := h2.Peerstore().PeerInfo(h2.ID()) if err := h1.Connect(ctx, h2pi); err != nil { @@ -193,8 +195,8 @@ func TestHostProtoPreknowledge(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - h1 := New(testutil.GenSwarmNetwork(t, ctx)) - h2 := New(testutil.GenSwarmNetwork(t, ctx)) + h1 := New(swarmt.GenSwarm(t, ctx)) + h2 := New(swarmt.GenSwarm(t, ctx)) conn := make(chan protocol.ID) handler := func(s inet.Stream) { @@ -358,7 +360,7 @@ func TestAddrResolution(t *testing.T) { } resolver := &madns.Resolver{Backend: backend} - h := New(testutil.GenSwarmNetwork(t, ctx), resolver) + h := New(swarmt.GenSwarm(t, ctx), resolver) defer h.Close() pi, err := pstore.InfoFromP2pAddr(p2paddr1) diff --git a/p2p/net/mock/mock_conn.go b/p2p/net/mock/mock_conn.go index fcb634624..68e9c840c 100644 --- a/p2p/net/mock/mock_conn.go +++ b/p2p/net/mock/mock_conn.go @@ -118,12 +118,12 @@ func (c *conn) NewStream() (inet.Stream, error) { return s, nil } -func (c *conn) GetStreams() ([]inet.Stream, error) { +func (c *conn) GetStreams() []inet.Stream { var out []inet.Stream for e := c.streams.Front(); e != nil; e = e.Next() { out = append(out, e.Value.(*stream)) } - return out, nil + return out } // LocalMultiaddr is the Multiaddr on this side diff --git a/p2p/protocol/identify/id.go b/p2p/protocol/identify/id.go index 66930a3b4..8f8394fbd 100644 --- a/p2p/protocol/identify/id.go +++ b/p2p/protocol/identify/id.go @@ -13,8 +13,6 @@ import ( ic "github.com/libp2p/go-libp2p-crypto" host "github.com/libp2p/go-libp2p-host" lgbl "github.com/libp2p/go-libp2p-loggables" - metrics "github.com/libp2p/go-libp2p-metrics" - mstream "github.com/libp2p/go-libp2p-metrics/stream" inet "github.com/libp2p/go-libp2p-net" peer "github.com/libp2p/go-libp2p-peer" pstore "github.com/libp2p/go-libp2p-peerstore" @@ -44,7 +42,6 @@ var ClientVersion = "go-libp2p/3.3.4" type IDService struct { Host host.Host - Reporter metrics.Reporter // connections undergoing identification // for wait purposes currid map[inet.Conn]chan struct{} @@ -64,7 +61,7 @@ func NewIDService(h host.Host) *IDService { Host: h, currid: make(map[inet.Conn]chan struct{}), } - h.SetStreamHandler(ID, s.RequestHandler) + h.SetStreamHandler(ID, s.requestHandler) h.Network().Notify((*netNotifiee)(s)) return s } @@ -95,21 +92,17 @@ func (ids *IDService) IdentifyConn(c inet.Conn) { c.Close() return } - defer s.Close() + defer inet.FullClose(s) s.SetProtocol(ID) - if ids.Reporter != nil { - s = mstream.WrapStream(s, ids.Reporter) - } - // ok give the response to our handler. if err := msmux.SelectProtoOrFail(ID, s); err != nil { log.Event(context.TODO(), "IdentifyOpenFailed", c.RemotePeer(), logging.Metadata{"error": err}) return } - ids.ResponseHandler(s) + ids.responseHandler(s) ids.currmu.Lock() _, found := ids.currid[c] @@ -122,14 +115,10 @@ func (ids *IDService) IdentifyConn(c inet.Conn) { } } -func (ids *IDService) RequestHandler(s inet.Stream) { - defer s.Close() +func (ids *IDService) requestHandler(s inet.Stream) { + defer inet.FullClose(s) c := s.Conn() - if ids.Reporter != nil { - s = mstream.WrapStream(s, ids.Reporter) - } - w := ggio.NewDelimitedWriter(s) mes := pb.Identify{} ids.populateMessage(&mes, s.Conn()) @@ -139,8 +128,7 @@ func (ids *IDService) RequestHandler(s inet.Stream) { c.RemotePeer(), c.RemoteMultiaddr()) } -func (ids *IDService) ResponseHandler(s inet.Stream) { - defer s.Close() +func (ids *IDService) responseHandler(s inet.Stream) { c := s.Conn() r := ggio.NewDelimitedReader(s, 2048) diff --git a/p2p/protocol/identify/id_test.go b/p2p/protocol/identify/id_test.go index 7e82f9528..79a09d2f9 100644 --- a/p2p/protocol/identify/id_test.go +++ b/p2p/protocol/identify/id_test.go @@ -6,9 +6,9 @@ import ( "time" ic "github.com/libp2p/go-libp2p-crypto" - testutil "github.com/libp2p/go-libp2p-netutil" peer "github.com/libp2p/go-libp2p-peer" pstore "github.com/libp2p/go-libp2p-peerstore" + swarmt "github.com/libp2p/go-libp2p-swarm/testing" identify "github.com/libp2p/go-libp2p/p2p/protocol/identify" blhost "github.com/libp2p/go-libp2p-blankhost" @@ -20,8 +20,8 @@ func subtestIDService(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - h1 := blhost.NewBlankHost(testutil.GenSwarmNetwork(t, ctx)) - h2 := blhost.NewBlankHost(testutil.GenSwarmNetwork(t, ctx)) + h1 := blhost.NewBlankHost(swarmt.GenSwarm(t, ctx)) + h2 := blhost.NewBlankHost(swarmt.GenSwarm(t, ctx)) h1p := h1.ID() h2p := h2.ID() @@ -65,7 +65,7 @@ func subtestIDService(t *testing.T) { ids2.IdentifyConn(c[0]) addrs := h1.Peerstore().Addrs(h1p) - addrs = append(addrs, c[0].RemoteMultiaddr(), forgetMe) + addrs = append(addrs, forgetMe) // and the protocol versions. t.Log("test peer2 has peer1 addrs correctly") diff --git a/p2p/protocol/ping/ping_test.go b/p2p/protocol/ping/ping_test.go index a260cb81d..adcb3ca69 100644 --- a/p2p/protocol/ping/ping_test.go +++ b/p2p/protocol/ping/ping_test.go @@ -5,17 +5,17 @@ import ( "testing" "time" - netutil "github.com/libp2p/go-libp2p-netutil" peer "github.com/libp2p/go-libp2p-peer" pstore "github.com/libp2p/go-libp2p-peerstore" + swarmt "github.com/libp2p/go-libp2p-swarm/testing" bhost "github.com/libp2p/go-libp2p/p2p/host/basic" ) func TestPing(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - h1 := bhost.New(netutil.GenSwarmNetwork(t, ctx)) - h2 := bhost.New(netutil.GenSwarmNetwork(t, ctx)) + h1 := bhost.New(swarmt.GenSwarm(t, ctx)) + h2 := bhost.New(swarmt.GenSwarm(t, ctx)) err := h1.Connect(ctx, pstore.PeerInfo{ ID: h2.ID(), diff --git a/p2p/test/backpressure/backpressure_test.go b/p2p/test/backpressure/backpressure_test.go index 8e783118d..ab84ab2ab 100644 --- a/p2p/test/backpressure/backpressure_test.go +++ b/p2p/test/backpressure/backpressure_test.go @@ -13,9 +13,9 @@ import ( logging "github.com/ipfs/go-log" host "github.com/libp2p/go-libp2p-host" inet "github.com/libp2p/go-libp2p-net" - testutil "github.com/libp2p/go-libp2p-netutil" peer "github.com/libp2p/go-libp2p-peer" protocol "github.com/libp2p/go-libp2p-protocol" + swarmt "github.com/libp2p/go-libp2p-swarm/testing" ) var log = logging.Logger("backpressure") @@ -137,8 +137,8 @@ a problem. // ok that's enough setup. let's do it! ctx := context.Background() - h1 := bhost.New(testutil.GenSwarmNetwork(t, ctx)) - h2 := bhost.New(testutil.GenSwarmNetwork(t, ctx)) + h1 := bhost.New(swarmt.GenSwarm(t, ctx)) + h2 := bhost.New(swarmt.GenSwarm(t, ctx)) // setup receiver handler h1.SetStreamHandler(protocol.TestingID, receiver) @@ -274,8 +274,8 @@ func TestStBackpressureStreamWrite(t *testing.T) { // setup the networks ctx := context.Background() - h1 := bhost.New(testutil.GenSwarmNetwork(t, ctx)) - h2 := bhost.New(testutil.GenSwarmNetwork(t, ctx)) + h1 := bhost.New(swarmt.GenSwarm(t, ctx)) + h2 := bhost.New(swarmt.GenSwarm(t, ctx)) // setup sender handler on 1 h1.SetStreamHandler(protocol.TestingID, sender) diff --git a/p2p/test/reconnects/reconnect_test.go b/p2p/test/reconnects/reconnect_test.go index e8851efe8..2f721c360 100644 --- a/p2p/test/reconnects/reconnect_test.go +++ b/p2p/test/reconnects/reconnect_test.go @@ -14,17 +14,10 @@ import ( logging "github.com/ipfs/go-log" host "github.com/libp2p/go-libp2p-host" inet "github.com/libp2p/go-libp2p-net" - testutil "github.com/libp2p/go-libp2p-netutil" protocol "github.com/libp2p/go-libp2p-protocol" - swarm "github.com/libp2p/go-libp2p-swarm" - ps "github.com/libp2p/go-peerstream" + swarmt "github.com/libp2p/go-libp2p-swarm/testing" ) -func init() { - // change the garbage collect timeout for testing. - ps.GarbageCollectTimeout = 10 * time.Millisecond -} - var log = logging.Logger("reconnect") func EchoStreamHandler(stream inet.Stream) { @@ -109,8 +102,8 @@ func newSender() (chan sendChans, func(s inet.Stream)) { // TestReconnect tests whether hosts are able to disconnect and reconnect. func TestReconnect2(t *testing.T) { ctx := context.Background() - h1 := bhost.New(testutil.GenSwarmNetwork(t, ctx)) - h2 := bhost.New(testutil.GenSwarmNetwork(t, ctx)) + h1 := bhost.New(swarmt.GenSwarm(t, ctx)) + h2 := bhost.New(swarmt.GenSwarm(t, ctx)) hosts := []host.Host{h1, h2} h1.SetStreamHandler(protocol.TestingID, EchoStreamHandler) @@ -129,11 +122,11 @@ func TestReconnect2(t *testing.T) { // TestReconnect tests whether hosts are able to disconnect and reconnect. func TestReconnect5(t *testing.T) { ctx := context.Background() - h1 := bhost.New(testutil.GenSwarmNetwork(t, ctx)) - h2 := bhost.New(testutil.GenSwarmNetwork(t, ctx)) - h3 := bhost.New(testutil.GenSwarmNetwork(t, ctx)) - h4 := bhost.New(testutil.GenSwarmNetwork(t, ctx)) - h5 := bhost.New(testutil.GenSwarmNetwork(t, ctx)) + h1 := bhost.New(swarmt.GenSwarm(t, ctx)) + h2 := bhost.New(swarmt.GenSwarm(t, ctx)) + h3 := bhost.New(swarmt.GenSwarm(t, ctx)) + h4 := bhost.New(swarmt.GenSwarm(t, ctx)) + h5 := bhost.New(swarmt.GenSwarm(t, ctx)) hosts := []host.Host{h1, h2, h3, h4, h5} h1.SetStreamHandler(protocol.TestingID, EchoStreamHandler) @@ -219,13 +212,11 @@ func SubtestConnSendDisc(t *testing.T, hosts []host.Host) { // close connection cs := h1.Network().Conns() for _, c := range cs { - sc := c.(*swarm.Conn) - if sc.LocalPeer() > sc.RemotePeer() { - continue // only close it on one side. + if c.LocalPeer() > c.RemotePeer() { + continue } - - log.Debugf("closing: %s", sc.RawConn()) - sc.Close() + log.Debugf("closing: %s", c) + c.Close() } } diff --git a/package.json b/package.json index f70b3baaf..98fd293af 100644 --- a/package.json +++ b/package.json @@ -18,21 +18,11 @@ "name": "mdns", "version": "0.1.1" }, - { - "hash": "QmWBug6eBS7AxRdCDVuSY5CnSit7cS2XnPFYJWqWDumhCG", - "name": "go-msgio", - "version": "0.0.3" - }, { "hash": "QmNiJuT8Ja3hMVpBHXv3Q6dwmperaQ6JjLtpMQgMCD7xvx", "name": "go-ipfs-util", "version": "1.2.7" }, - { - "hash": "QmUusaX99BZoELh7dmPgirqRQ1FAmMnmnBn3oiqDFGBUSc", - "name": "go-keyspace", - "version": "1.0.0" - }, { "hash": "QmbXRda5H2K3MSQyWWxTMtd8DWuguEBUCe6hpxfXVpFUGj", "name": "go-multistream", @@ -54,24 +44,9 @@ "version": "1.4.1" }, { - "hash": "QmRK2LxanhK2gZq6k6R7vk5ZoYZk8ULSSTB7FzDsMUX6CB", + "hash": "QmcGXGdw9BWDysPJQHxJinjGHha3eEg4vzFETre4woNwcX", "name": "go-multiaddr-net", - "version": "1.5.7" - }, - { - "hash": "QmZyZDi491cCNTLfAhwcaDii2Kg4pwKRkhqQzURGDvY6ua", - "name": "go-multihash", - "version": "1.0.7" - }, - { - "hash": "QmSMZwvs3n4GBikZ7hKzT17c3bk65FmyZo2JqtJ16swqCv", - "name": "multiaddr-filter", - "version": "1.0.2" - }, - { - "hash": "QmaPHkZLbQQbvcyavn8q1GFHg6o6yeceyHFSJ3Pjf3p3TQ", - "name": "go-crypto", - "version": "0.0.0" + "version": "1.6.0" }, { "hash": "QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV", @@ -83,38 +58,6 @@ "name": "go-multiaddr", "version": "1.2.6" }, - { - "hash": "QmYvsG72GsfLgUeSojXArjnU6L4Wmwk7wuAxtNLuyXcc1T", - "name": "randbo", - "version": "0.0.0" - }, - { - "hash": "QmeQW4ayVqi7Jjay1SrP2wYydsH9KwSrzQBnqyC25gPFnG", - "name": "go-notifier", - "version": "1.0.0" - }, - { - "hash": "QmWHgLqrghM9zw77nF6gdvT9ExQ2RB9pLxkd8sDHZf1rWb", - "name": "go-temp-err-catcher", - "version": "0.0.0" - }, - { - "hash": "QmVXXxPsnDY16szK4gPy1oz4qKd8HHshemX1miZR2frtJo", - "name": "go-peerstream", - "version": "2.1.5" - }, - { - "author": "whyrusleeping", - "hash": "QmTy17Jm1foTnvUS9JXRhLbRQ3XuC64jPTjUfpB4mHz2QM", - "name": "mafmt", - "version": "1.2.5" - }, - { - "author": "whyrusleeping", - "hash": "QmTd4Jgb4nbJq5uR55KJgGLyHWmM3dovS21D1HcwRneSLu", - "name": "gorocheck", - "version": "0.0.0" - }, { "author": "whyrusleeping", "hash": "QmPDZJxtWGfcwLPazJxD4h3v3aDs43V7UNAVs3Jz1Wo7o4", @@ -123,33 +66,33 @@ }, { "author": "whyrusleeping", - "hash": "QmP47neqyP4NR9CKbjVogZ8U9Gybxfcfsa8HtPSPSxwiA8", + "hash": "QmQS7P1VV4JuqbXEEaPQZ5ERHDQuGp8qk26Gfdg9ZtP1Eb", "name": "go-libp2p-secio", - "version": "1.2.7" + "version": "2.0.0" }, { "author": "whyrusleeping", - "hash": "QmdeiKhUy1TVGBaKxt7y1QmBDLBdisSrLJ1x58Eoj4PXUh", + "hash": "QmZb7hAgQEhW9dBbzBudU39gCeD4zbe6xafD52LUuF4cUN", "name": "go-libp2p-peerstore", - "version": "1.4.17" + "version": "1.4.18" }, { "author": "whyrusleeping", - "hash": "QmPUHzTLPZFYqv8WqcBTuMFYTgeom4uHHEaxzk7bd5GYZB", + "hash": "QmYnjSGtvn7LhrxCvwrU9uDWxKyg28uBYeXvgzTDDDzVy4", "name": "go-libp2p-transport", - "version": "2.2.14" + "version": "3.0.0" }, { "author": "whyrusleeping", - "hash": "QmdxKHpkZCTV3C7xdE1iJdPfFm5LVvMPvirdFmKu1TimzY", + "hash": "QmU7NiV3ZRJoNk8XZEKazs4AW7XQT1rQCrhh8cmhSjZgrC", "name": "go-tcp-transport", - "version": "1.2.9" + "version": "2.0.0" }, { "author": "whyrusleeping", - "hash": "Qmf2UAmRwDG4TvnkQpHZWPAzw7rpCYVhxmRXmYxXr5LD1g", + "hash": "QmYF6XMumtqvXtZfQKrCokXEdFvfy2i7tbpvSRzRrHyY8c", "name": "go-maddr-filter", - "version": "1.1.6" + "version": "1.1.7" }, { "author": "whyrusleeping", @@ -157,12 +100,6 @@ "name": "go-libp2p-protocol", "version": "1.0.0" }, - { - "author": "whyrusleeping", - "hash": "QmTGSre9j1otFgsr1opCUQDXTPSM6BTZnMWwPeA5nYJM7w", - "name": "go-addr-util", - "version": "1.2.7" - }, { "author": "whyrusleeping", "hash": "QmUJzxQQ2kzwQubsMqBTr1NGDpLfh7pGA2E1oaJULcKDPq", @@ -171,57 +108,45 @@ }, { "author": "whyrusleeping", - "hash": "QmYSQpi68jBLVUx62u543RVvnjjaQQDDxyopWWG31kiUkG", - "name": "go-libp2p-conn", - "version": "1.7.7" - }, - { - "author": "whyrusleeping", - "hash": "QmXoz9o2PT3tEzf7hicegwex5UgVP54n3k82K7jrWFyN86", + "hash": "QmYj8wdn5sZEHX2XMDWGBvcXJNdzVbaVpHmXvhHBVZepen", "name": "go-libp2p-net", - "version": "2.0.7" + "version": "3.0.0" }, { "author": "whyrusleeping", - "hash": "QmVvu4bS5QLfS19ePkp5Wgzn2ZUma5oXTT9BgDFyQLxUZF", + "hash": "QmNnaGds3p4hfTqSH4KURKh8pBRcisAWYbNDEGeMZ7c3Hv", "name": "go-libp2p-metrics", - "version": "2.0.6" + "version": "2.1.0" }, { "author": "whyrusleeping", - "hash": "QmYDNqBAMWVMHKndYR35Sd8PfEVWBiDmpHYkuRJTunJDeJ", - "name": "go-libp2p-interface-conn", - "version": "0.4.13" - }, - { - "author": "whyrusleeping", - "hash": "QmaSfSMvc1VPZ8JbMponFs4WHvF9FgEruF56opm5E1RgQA", + "hash": "QmdHyfNVTZ5VtUx4Xz23z8wtnioSrFQ28XSfpVkdhQBkGA", "name": "go-libp2p-host", - "version": "2.1.8" + "version": "3.0.0" }, { "author": "whyrusleeping", - "hash": "QmRpKdg1xs4Yyrn9yrVYRBp7AQqyRxMLpD6Jgp1eZAGqEr", + "hash": "QmPzT3rJnSP8VFP1kw7Ly7HP8AprKNZtwLHXHnxfVSbWT3", "name": "go-libp2p-swarm", - "version": "2.1.9" + "version": "3.0.0" }, { "author": "whyrusleeping", - "hash": "QmXtFH52dAPCq5i4iYjr1g8xVFVJD3fwKWWyNHjVB4sHRp", + "hash": "QmQF7htcTXeVqdTg4fKPGU59PeeTpsFgn9UquiixwbTPG1", "name": "go-libp2p-nat", - "version": "0.0.8" + "version": "0.8.0" }, { "author": "whyrusleeping", - "hash": "Qma2UuHusnaFV24DgeZ5hyrM9uc4UdyVaZbtn2FQsPRhES", + "hash": "Qmb3r9qUR7PnkyUKztmXp8sQhzXZHGmRg7fR5zsB1ebWMj", "name": "go-libp2p-netutil", - "version": "0.3.13" + "version": "0.4.0" }, { "author": "whyrusleeping", - "hash": "QmYEmPwCBe7ZUFfuymozopHTuF3JXejvJPDAjwtyQCrsDi", + "hash": "QmQ6ASb73YCy77TLfxzKnzQFUyFKMQzDhmjwjaQp6rxK34", "name": "go-libp2p-blankhost", - "version": "0.2.8" + "version": "0.3.0" }, { "author": "whyrusleeping", @@ -255,9 +180,9 @@ }, { "author": "vyzo", - "hash": "QmR5sXZi68rm9m2E3KiXj6hE5m3GeLaDjbLPUeV6W3MLR8", + "hash": "QmNXLcLAcfo8yp59FxFQJNa7pDbUUw97QN9GwefWWFK4hk", "name": "go-libp2p-circuit", - "version": "2.0.14" + "version": "2.1.0" }, { "author": "lgierth", @@ -267,9 +192,9 @@ }, { "author": "why", - "hash": "QmfQNieWBPwmnUjXWPZbjJPzhNwFFabTb5RQ79dyVWGujQ", + "hash": "QmWCWsDQnnQ9Mo9V3GK8TSR91662FdFxjjqPX8YbHC8Ltz", "name": "go-libp2p-interface-connmgr", - "version": "0.0.8" + "version": "0.0.7" }, { "author": "whyrusleeping", @@ -288,6 +213,42 @@ "hash": "QmcBWojPoNh4qm7zvv4qiepvCnnc7ALS9qcp7TNwwxT1gT", "name": "go.uuid", "version": "1.1.0" + }, + { + "author": "whyrusleeping", + "hash": "QmTeRSFgnXRCh13sxsZkLTVCc1diUbZiT5mkGUgkR1J1on", + "name": "go-ws-transport", + "version": "2.0.0" + }, + { + "author": "stebalien", + "hash": "QmRYk8zWrXSkXsE16vM8yxByqM6eVvnXzDXKGvHFJJubVc", + "name": "go-conn-security-multistream", + "version": "0.1.0" + }, + { + "author": "Stebalien", + "hash": "QmSieFUauuYnroStqmRAEgu9BMXDNY5LbtNgzXcFitBKXQ", + "name": "go-conn-security", + "version": "0.1.1" + }, + { + "author": "libp2p", + "hash": "QmW7Ump7YyBMr712Ta3iEVh3ZYcfVvJaPryfbCnyE826b4", + "name": "go-libp2p-interface-pnet", + "version": "3.0.0" + }, + { + "author": "whyrusleeping", + "hash": "QmY9JXR3FupnYAYJWK9aMr9bCpqWKcToQ1tz8DVGTrHpHw", + "name": "go-stream-muxer", + "version": "3.0.0" + }, + { + "author": "steb", + "hash": "Qmf3ejfGWR8Bd3wKFBvwYGFMJ9TeKJwYJUc2WchXjMxzg7", + "name": "go-libp2p-transport-upgrader", + "version": "0.1.0" } ], "gxVersion": "0.4.0",