Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Circuit Relay integration #4091

Merged
merged 16 commits into from
Aug 16, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 51 additions & 3 deletions core/commands/swarm.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io"
"path"
"sort"
"strings"

cmds "github.com/ipfs/go-ipfs/commands"
repo "github.com/ipfs/go-ipfs/repo"
Expand Down Expand Up @@ -127,8 +128,14 @@ var swarmPeersCmd = &cmds.Command{
}

buf := new(bytes.Buffer)
pipfs := ma.ProtocolWithCode(ma.P_IPFS).Name
for _, info := range ci.Peers {
fmt.Fprintf(buf, "%s/ipfs/%s", info.Addr, info.Peer)
ids := fmt.Sprintf("/%s/%s", pipfs, info.Peer)
if strings.HasSuffix(info.Addr, ids) {
fmt.Fprintf(buf, "%s", info.Addr)
} else {
fmt.Fprintf(buf, "%s%s", info.Addr, ids)
}
if info.Latency != "" {
fmt.Fprintf(buf, " %s", info.Latency)
}
Expand Down Expand Up @@ -197,7 +204,8 @@ var swarmAddrsCmd = &cmds.Command{
`,
},
Subcommands: map[string]*cmds.Command{
"local": swarmAddrsLocalCmd,
"local": swarmAddrsLocalCmd,
"listen": swarmAddrsListenCmd,
},
Run: func(req cmds.Request, res cmds.Response) {

Expand Down Expand Up @@ -256,7 +264,7 @@ var swarmAddrsLocalCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "List local addresses.",
ShortDescription: `
'ipfs swarm addrs local' lists all local addresses the node is listening on.
'ipfs swarm addrs local' lists all local listening addresses announced to the network.
`,
},
Options: []cmds.Option{
Expand Down Expand Up @@ -296,6 +304,46 @@ var swarmAddrsLocalCmd = &cmds.Command{
},
}

var swarmAddrsListenCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "List interface listening addresses.",
ShortDescription: `
'ipfs swarm addrs listen' lists all interface addresses the node is listening on.
`,
},
Run: func(req cmds.Request, res cmds.Response) {

n, err := req.InvocContext().GetNode()
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}

if n.PeerHost == nil {
res.SetError(errNotOnline, cmds.ErrClient)
return
}

var addrs []string
maddrs, err := n.PeerHost.Network().InterfaceListenAddresses()
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}

for _, addr := range maddrs {
addrs = append(addrs, addr.String())
}
sort.Sort(sort.StringSlice(addrs))

res.SetOutput(&stringList{addrs})
},
Type: stringList{},
Marshalers: cmds.MarshalerMap{
cmds.Text: stringListMarshaler,
},
}

var swarmConnectCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Open connection to a given address.",
Expand Down
53 changes: 50 additions & 3 deletions core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import (
ipnet "gx/ipfs/QmQq9YzmdFdWNTDdArueGyD7L5yyiRQigrRHJnTGkxcEjT/go-libp2p-interface-pnet"
p2phost "gx/ipfs/QmRNyPNJGNCaZyYonJj7owciWTsMd9gRfEKmZY3o6xwN3h/go-libp2p-host"
mssmux "gx/ipfs/QmRVYfZ7tWNHPBzWiG6KWGzvT2hcGems8srihsQE29x1U5/go-smux-multistream"
circuit "gx/ipfs/QmSC7288aesJAC3BQ4Duy6Pk2CMfQWL7cr5t9SV4HBmKFT/go-libp2p-circuit"
goprocess "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess"
mamask "gx/ipfs/QmSMZwvs3n4GBikZ7hKzT17c3bk65FmyZo2JqtJ16swqCv/multiaddr-filter"
u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
Expand Down Expand Up @@ -221,9 +222,12 @@ func (n *IpfsNode) startOnlineServices(ctx context.Context, routingOption Routin
hostopts := &ConstructPeerHostOpts{
AddrsFactory: addrsFactory,
DisableNatPortMap: cfg.Swarm.DisableNatPortMap,
DisableRelay: cfg.Swarm.DisableRelay,
EnableRelayHop: cfg.Swarm.EnableRelayHop,
}
peerhost, err := hostOption(ctx, n.Identity, n.Peerstore, n.Reporter,
addrfilter, tpt, protec, hostopts)

if err != nil {
return err
}
Expand Down Expand Up @@ -783,8 +787,10 @@ func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) {
}

type ConstructPeerHostOpts struct {
DisableNatPortMap bool
AddrsFactory p2pbhost.AddrsFactory
DisableNatPortMap bool
DisableRelay bool
EnableRelayHop bool
}

type HostOption func(ctx context.Context, id peer.ID, ps pstore.Peerstore, bwr metrics.Reporter, fs []*net.IPNet, tpt smux.Transport, protc ipnet.Protector, opts *ConstructPeerHostOpts) (p2phost.Host, error)
Expand All @@ -810,15 +816,56 @@ func constructPeerHost(ctx context.Context, id peer.ID, ps pstore.Peerstore, bwr
if !opts.DisableNatPortMap {
hostOpts = append(hostOpts, p2pbhost.NATPortMap)
}
if opts.AddrsFactory != nil {
hostOpts = append(hostOpts, opts.AddrsFactory)

addrsFactory := opts.AddrsFactory
if !opts.DisableRelay {
if addrsFactory != nil {
addrsFactory = composeAddrsFactory(addrsFactory, filterRelayAddrs)
} else {
addrsFactory = filterRelayAddrs
}
}

if addrsFactory != nil {
hostOpts = append(hostOpts, addrsFactory)
}

host := p2pbhost.New(network, hostOpts...)

if !opts.DisableRelay {
var relayOpts []circuit.RelayOpt
if opts.EnableRelayHop {
relayOpts = append(relayOpts, circuit.OptHop)
}

err := circuit.AddRelayTransport(ctx, host, relayOpts...)
if err != nil {
host.Close()
return nil, err
}
}

return host, nil
}

func filterRelayAddrs(addrs []ma.Multiaddr) []ma.Multiaddr {
var raddrs []ma.Multiaddr
for _, addr := range addrs {
_, err := addr.ValueForProtocol(circuit.P_CIRCUIT)
if err == nil {
continue
}
raddrs = append(raddrs, addr)
}
return raddrs
}

func composeAddrsFactory(f, g p2pbhost.AddrsFactory) p2pbhost.AddrsFactory {
return func(addrs []ma.Multiaddr) []ma.Multiaddr {
return f(g(addrs))
}
}

// startListening on the network addresses
func startListening(ctx context.Context, host p2phost.Host, cfg *config.Config) error {
listenAddrs, err := listenAddresses(cfg)
Expand Down
8 changes: 7 additions & 1 deletion docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ A boolean value. If set to true, all block reads from disk will be hashed and ve
- `BloomFilterSize`
A number representing the size in bytes of the blockstore's bloom filter. A value of zero represents the feature being disabled.

Default: `0`
Default: `0`

- `Params`
Extra parameters for datastore construction, not currently used.
Expand Down Expand Up @@ -228,3 +228,9 @@ improvement, as well as a reduction in memory usage.
- `DisableNatPortMap`
Disable NAT discovery.

- `DisableRelay`
Disables the p2p-circuit relay transport.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this disable relays entirely or just disable listening on relayed addresses? There are three cases:

  1. Listen using relays.
  2. Act as a relay.
  3. Connect to nodes through relays.

It would be nice to be able to enable/disable these independently. Can we currently do that?

Copy link
Contributor Author

@vyzo vyzo Aug 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting to true will disable the relay transport entirely.

The DislableRelay controls option 1 and 3, so by default we listen for relay connections and we can connect to peers through relay.
In order to act as a hop relay (2), you need to EnableRelayHop, in addition to having the relay transport enabled.

I don't think it makes sense to have more fine-grained independent configuration, as we can't really separate listening from dial (and do we really want to do that?) and we already have an option to control hop relaying.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed on IRC, I misunderstood what these toggles did. DisableRelay disables relaying entirely and we don't yet support advertising relayed addresses; when implemented, that will probably have an additional toggle.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's the plan.


- `EnableRelayHop`
Enables HOP relay for the node. If this is enabled, the node will act as
an intermediate (Hop Relay) node in relay circuits for connected peers.
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,12 @@
"hash": "QmQBB2dQLmQHJgs2gqZ3iqL2XiuCtUCvXzWt5kMXDf5Zcr",
"name": "go-maddr-filter",
"version": "1.1.4"
},
{
"author": "vyzo",
"hash": "QmSC7288aesJAC3BQ4Duy6Pk2CMfQWL7cr5t9SV4HBmKFT",
"name": "go-libp2p-circuit",
"version": "1.1.2"
}
],
"gxVersion": "0.10.0",
Expand Down
2 changes: 2 additions & 0 deletions repo/config/swarm.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ type SwarmConfig struct {
AddrFilters []string
DisableBandwidthMetrics bool
DisableNatPortMap bool
DisableRelay bool
EnableRelayHop bool
}
6 changes: 5 additions & 1 deletion test/sharness/t0060-daemon.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ test_expect_success "'ipfs swarm addrs local' works" '
ipfs swarm addrs local >local_addrs
'

test_expect_success "ipfs swarm addrs listen; works" '
ipfs swarm addrs listen >listen_addrs
'

test_expect_success "ipfs peer id looks good" '
test_check_peerid "$PEERID"
'
Expand All @@ -38,7 +42,7 @@ test_expect_success "ipfs gateway works with the correct allowed origin port" '
test_expect_success "ipfs daemon output looks good" '
STARTFILE="ipfs cat /ipfs/$HASH_WELCOME_DOCS/readme" &&
echo "Initializing daemon..." >expected_daemon &&
sed "s/^/Swarm listening on /" local_addrs >>expected_daemon &&
sed "s/^/Swarm listening on /" listen_addrs >>expected_daemon &&
sed "s/^/Swarm announcing /" local_addrs >>expected_daemon &&
echo "API server listening on '$API_MADDR'" >>expected_daemon &&
echo "Gateway (readonly) server listening on '$GWAY_MADDR'" >>expected_daemon &&
Expand Down
87 changes: 87 additions & 0 deletions test/sharness/t0182-circuit-relay.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/bin/sh

test_description="Test circuit relay"

. lib/test-lib.sh

# start iptb + wait for peering
NUM_NODES=3
test_expect_success 'init iptb' '
iptb init -n $NUM_NODES --bootstrap=none --port=0
'

# Network toplogy: A <-> Relay <-> B
test_expect_success 'start up nodes for configuration' '
iptb start --args --routing=none
'

test_expect_success 'configure EnableRelayHop in relay node' '
ipfsi 1 config --json Swarm.EnableRelayHop true
'

test_expect_success 'restart nodes' '
iptb stop &&
iptb start --args --routing=none
'

test_expect_success 'connect A <-> Relay' '
iptb connect 0 1
'

test_expect_success 'connect B <-> Relay' '
iptb connect 2 1
'

test_expect_success 'wait until relay is ready to do work' '
sleep 1
'

test_expect_success 'peer ids' '
PEERID_0=$(iptb get id 0) &&
PEERID_1=$(iptb get id 1) &&
PEERID_2=$(iptb get id 2)
'

test_expect_success 'connect A <-Relay-> B' '
ipfsi 0 swarm connect /p2p-circuit/ipfs/$PEERID_2 > peers_out
'

test_expect_success 'output looks good' '
echo "connect $PEERID_2 success" > peers_exp &&
test_cmp peers_exp peers_out
'

test_expect_success 'peers for A look good' '
ipfsi 0 swarm peers | grep p2p-circuit > peers_out &&
echo "/ipfs/$PEERID_1/p2p-circuit/ipfs/$PEERID_2" > peers_exp &&
test_cmp peers_exp peers_out
'

test_expect_success 'peers for B look good' '
ipfsi 2 swarm peers | grep p2p-circuit > peers_out &&
echo "/ipfs/$PEERID_1/p2p-circuit/ipfs/$PEERID_0" > peers_exp &&
test_cmp peers_exp peers_out
'

test_expect_success 'add an object in A' '
echo "hello relay" | ipfsi 0 add > peers_out
'

test_expect_success 'object ID' '
OBJID=$(cut -f3 -d " " peers_out)
'

test_expect_success 'cat the object in B' '
ipfsi 2 cat $OBJID > peers_out
'

test_expect_success 'output looks good' '
echo "hello relay" > peers_exp &&
test_cmp peers_exp peers_out
'

test_expect_success 'stop iptb' '
iptb stop
'

test_done
11 changes: 11 additions & 0 deletions thirdparty/ipfsaddr/ipfsaddr.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
ma "gx/ipfs/QmXY77cVe7rVRQXZZQRioukUM7aRW3BTcAgJe12MCtb3Ji/go-multiaddr"

path "github.com/ipfs/go-ipfs/path"
circuit "gx/ipfs/QmSC7288aesJAC3BQ4Duy6Pk2CMfQWL7cr5t9SV4HBmKFT/go-libp2p-circuit"
logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer"
)
Expand Down Expand Up @@ -106,6 +107,16 @@ func ParseMultiaddr(m ma.Multiaddr) (a IPFSAddr, err error) {

func Transport(iaddr IPFSAddr) (maddr ma.Multiaddr) {
maddr = iaddr.Multiaddr()

// /ipfs/QmId is part of the transport address for p2p-circuit
// TODO clean up the special case
// we need a consistent way of composing and consumig multiaddrs
// so that we don't have to do this
_, err := maddr.ValueForProtocol(circuit.P_CIRCUIT)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please create issue for this TODO. TODOs in code get lost in time and space.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, will do once we merge.

if err == nil {
return maddr
}

split := ma.Split(maddr)
maddr = ma.Join(split[:len(split)-1]...)
return
Expand Down