Skip to content

Commit

Permalink
Merge pull request #4091 from ipfs/feat/circuit-relay
Browse files Browse the repository at this point in the history
Circuit Relay integration
  • Loading branch information
whyrusleeping authored Aug 16, 2017
2 parents dea24ae + b6150b2 commit 22ee73d
Show file tree
Hide file tree
Showing 8 changed files with 219 additions and 8 deletions.
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.

- `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)
if err == nil {
return maddr
}

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

0 comments on commit 22ee73d

Please sign in to comment.