2017-11-04 19:06:13 +00:00
|
|
|
package libp2p
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/rand"
|
2017-12-16 00:02:30 +00:00
|
|
|
"fmt"
|
2017-11-04 19:06:13 +00:00
|
|
|
|
|
|
|
crypto "github.com/libp2p/go-libp2p-crypto"
|
|
|
|
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"
|
|
|
|
)
|
|
|
|
|
2017-11-05 15:28:59 +00:00
|
|
|
// Config describes a set of settings for a libp2p node
|
2017-11-04 19:06:13 +00:00
|
|
|
type Config struct {
|
2017-12-14 21:10:09 +00:00
|
|
|
Transports []transport.Transport
|
|
|
|
Muxer mux.Transport
|
|
|
|
ListenAddrs []ma.Multiaddr
|
|
|
|
PeerKey crypto.PrivKey
|
|
|
|
Peerstore pstore.Peerstore
|
|
|
|
Protector pnet.Protector
|
|
|
|
Reporter metrics.Reporter
|
|
|
|
DisableSecio bool
|
2017-11-04 19:06:13 +00:00
|
|
|
}
|
|
|
|
|
2017-12-14 23:40:24 +00:00
|
|
|
type Option func(cfg *Config) error
|
|
|
|
|
2017-12-16 00:02:30 +00:00
|
|
|
func Transports(tpts ...transport.Transport) Option {
|
2017-12-14 23:40:24 +00:00
|
|
|
return func(cfg *Config) error {
|
2017-12-16 00:02:30 +00:00
|
|
|
cfg.Transports = append(cfg.Transports, tpts...)
|
2017-12-14 23:40:24 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-16 00:02:30 +00:00
|
|
|
func ListenAddrs(addrs ...ma.Multiaddr) Option {
|
2017-12-14 23:40:24 +00:00
|
|
|
return func(cfg *Config) error {
|
|
|
|
cfg.ListenAddrs = append(cfg.ListenAddrs, addrs...)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-16 00:02:30 +00:00
|
|
|
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
|
|
|
|
}
|
2017-12-14 23:40:24 +00:00
|
|
|
}
|
|
|
|
|
2017-12-16 00:02:30 +00:00
|
|
|
func NoEncryption() Option {
|
|
|
|
return TransportEncryption(EncPlaintext)
|
|
|
|
}
|
|
|
|
|
|
|
|
func Muxer(m mux.Transport) Option {
|
2017-12-14 23:40:24 +00:00
|
|
|
return func(cfg *Config) error {
|
2017-12-16 00:02:30 +00:00
|
|
|
if cfg.Muxer != nil {
|
|
|
|
return fmt.Errorf("cannot specify multiple muxer options")
|
|
|
|
}
|
|
|
|
|
2017-12-14 23:40:24 +00:00
|
|
|
cfg.Muxer = m
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-16 00:02:30 +00:00
|
|
|
func Peerstore(ps pstore.Peerstore) Option {
|
2017-12-14 23:40:24 +00:00
|
|
|
return func(cfg *Config) error {
|
2017-12-16 00:02:30 +00:00
|
|
|
if cfg.Peerstore != nil {
|
|
|
|
return fmt.Errorf("cannot specify multiple peerstore options")
|
|
|
|
}
|
|
|
|
|
2017-12-14 23:40:24 +00:00
|
|
|
cfg.Peerstore = ps
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-16 00:02:30 +00:00
|
|
|
func PrivateNetwork(prot pnet.Protector) Option {
|
2017-12-14 23:40:24 +00:00
|
|
|
return func(cfg *Config) error {
|
2017-12-16 00:02:30 +00:00
|
|
|
if cfg.Protector != nil {
|
|
|
|
return fmt.Errorf("cannot specify multiple private network options")
|
|
|
|
}
|
|
|
|
|
2017-12-14 23:40:24 +00:00
|
|
|
cfg.Protector = prot
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-16 00:02:30 +00:00
|
|
|
func BandwidthReporter(rep metrics.Reporter) Option {
|
2017-12-14 23:40:24 +00:00
|
|
|
return func(cfg *Config) error {
|
2017-12-16 00:02:30 +00:00
|
|
|
if cfg.Reporter != nil {
|
|
|
|
return fmt.Errorf("cannot specify multiple bandwidth reporter options")
|
|
|
|
}
|
|
|
|
|
2017-12-14 23:40:24 +00:00
|
|
|
cfg.Reporter = rep
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-16 00:02:30 +00:00
|
|
|
func Identity(sk crypto.PrivKey) Option {
|
|
|
|
return func(cfg *Config) error {
|
|
|
|
if cfg.PeerKey != nil {
|
|
|
|
return fmt.Errorf("cannot specify multiple identities")
|
2017-12-14 23:40:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cfg.PeerKey = sk
|
|
|
|
return nil
|
|
|
|
}
|
2017-11-05 15:28:59 +00:00
|
|
|
}
|
|
|
|
|
2017-12-16 00:02:30 +00:00
|
|
|
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
|
|
|
|
}
|
2017-11-04 19:06:13 +00:00
|
|
|
}
|
|
|
|
|
2017-12-16 00:02:30 +00:00
|
|
|
return newWithCfg(ctx, &cfg)
|
|
|
|
}
|
|
|
|
|
|
|
|
func newWithCfg(ctx context.Context, cfg *Config) (host.Host, error) {
|
2017-11-05 15:28:59 +00:00
|
|
|
// If no key was given, generate a random 2048 bit RSA key
|
2017-11-04 19:06:13 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2017-11-05 15:28:59 +00:00
|
|
|
// Create a new blank peerstore if none was passed in
|
2017-11-04 19:06:13 +00:00
|
|
|
ps := cfg.Peerstore
|
|
|
|
if ps == nil {
|
|
|
|
ps = pstore.NewPeerstore()
|
|
|
|
}
|
|
|
|
|
2018-01-18 11:17:22 +00:00
|
|
|
// Set default muxer if none was passed in
|
|
|
|
muxer := cfg.Muxer
|
|
|
|
if muxer == nil {
|
|
|
|
muxer = DefaultMuxer()
|
|
|
|
}
|
|
|
|
|
2017-12-14 21:10:09 +00:00
|
|
|
// 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())
|
|
|
|
}
|
2017-11-04 19:06:13 +00:00
|
|
|
|
2018-01-18 11:17:22 +00:00
|
|
|
swrm, err := swarm.NewSwarmWithProtector(ctx, cfg.ListenAddrs, pid, ps, cfg.Protector, muxer, cfg.Reporter)
|
2017-11-04 19:06:13 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
netw := (*swarm.Network)(swrm)
|
|
|
|
|
|
|
|
return bhost.New(netw), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DefaultMuxer() mux.Transport {
|
|
|
|
// Set up stream multiplexer
|
|
|
|
tpt := msmux.NewBlankTransport()
|
2017-11-05 15:28:59 +00:00
|
|
|
|
|
|
|
// By default, support yamux and multiplex
|
2017-11-04 19:06:13 +00:00
|
|
|
tpt.AddTransport("/yamux/1.0.0", yamux.DefaultTransport)
|
|
|
|
tpt.AddTransport("/mplex/6.3.0", mplex.DefaultTransport)
|
2017-11-05 15:28:59 +00:00
|
|
|
|
2017-11-04 19:06:13 +00:00
|
|
|
return tpt
|
|
|
|
}
|
|
|
|
|
2017-12-16 00:02:30 +00:00
|
|
|
func Defaults(cfg *Config) error {
|
2017-11-05 15:28:59 +00:00
|
|
|
// Create a multiaddress that listens on a random port on all interfaces
|
|
|
|
addr, err := ma.NewMultiaddr("/ip4/0.0.0.0/tcp/0")
|
2017-11-04 19:06:13 +00:00
|
|
|
if err != nil {
|
2017-12-16 00:02:30 +00:00
|
|
|
return err
|
2017-11-04 19:06:13 +00:00
|
|
|
}
|
|
|
|
|
2017-12-16 00:02:30 +00:00
|
|
|
cfg.ListenAddrs = []ma.Multiaddr{addr}
|
|
|
|
cfg.Peerstore = pstore.NewPeerstore()
|
|
|
|
cfg.Muxer = DefaultMuxer()
|
|
|
|
return nil
|
2017-11-04 19:06:13 +00:00
|
|
|
}
|