Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
go-libp2p
Commits
a5858912
Commit
a5858912
authored
Oct 17, 2018
by
vyzo
Browse files
autorelay hosts
parent
a89e74a1
Changes
3
Hide whitespace changes
Inline
Side-by-side
p2p/host/relay/autorelay.go
0 → 100644
View file @
a5858912
package
relay
import
(
"context"
"fmt"
"math/rand"
"sync"
"time"
basic
"github.com/libp2p/go-libp2p/p2p/host/basic"
autonat
"github.com/libp2p/go-libp2p-autonat"
discovery
"github.com/libp2p/go-libp2p-discovery"
host
"github.com/libp2p/go-libp2p-host"
inet
"github.com/libp2p/go-libp2p-net"
peer
"github.com/libp2p/go-libp2p-peer"
pstore
"github.com/libp2p/go-libp2p-peerstore"
ma
"github.com/multiformats/go-multiaddr"
manet
"github.com/multiformats/go-multiaddr-net"
)
var
DesiredRelays
=
3
// AutoRelayHost is a Host that uses relays for connectivity when a NAT is detected.
type
AutoRelayHost
struct
{
*
basic
.
BasicHost
discover
discovery
.
Discoverer
autonat
autonat
.
AutoNAT
addrsF
basic
.
AddrsFactory
disconnect
chan
struct
{}
mx
sync
.
Mutex
relays
map
[
peer
.
ID
]
pstore
.
PeerInfo
addrs
[]
ma
.
Multiaddr
}
func
NewAutoRelayHost
(
ctx
context
.
Context
,
bhost
*
basic
.
BasicHost
,
discover
discovery
.
Discoverer
)
*
AutoRelayHost
{
autonat
:=
autonat
.
NewAutoNAT
(
ctx
,
bhost
)
h
:=
&
AutoRelayHost
{
BasicHost
:
bhost
,
discover
:
discover
,
autonat
:
autonat
,
addrsF
:
bhost
.
AddrsFactory
,
relays
:
make
(
map
[
peer
.
ID
]
pstore
.
PeerInfo
),
disconnect
:
make
(
chan
struct
{},
1
),
}
bhost
.
AddrsFactory
=
h
.
hostAddrs
bhost
.
Network
()
.
Notify
(
h
)
go
h
.
background
(
ctx
)
return
h
}
func
(
h
*
AutoRelayHost
)
hostAddrs
(
addrs
[]
ma
.
Multiaddr
)
[]
ma
.
Multiaddr
{
h
.
mx
.
Lock
()
defer
h
.
mx
.
Unlock
()
if
h
.
addrs
!=
nil
&&
h
.
autonat
.
Status
()
==
autonat
.
NATStatusPrivate
{
return
h
.
addrs
}
else
{
return
h
.
addrsF
(
addrs
)
}
}
func
(
h
*
AutoRelayHost
)
background
(
ctx
context
.
Context
)
{
select
{
case
<-
time
.
After
(
autonat
.
AutoNATBootDelay
+
30
*
time
.
Second
)
:
case
<-
ctx
.
Done
()
:
return
}
for
{
wait
:=
autonat
.
AutoNATRefreshInterval
switch
h
.
autonat
.
Status
()
{
case
autonat
.
NATStatusUnknown
:
wait
=
autonat
.
AutoNATRetryInterval
case
autonat
.
NATStatusPublic
:
case
autonat
.
NATStatusPrivate
:
h
.
findRelays
(
ctx
)
}
select
{
case
<-
h
.
disconnect
:
// invalidate addrs
h
.
mx
.
Lock
()
h
.
addrs
=
nil
h
.
mx
.
Unlock
()
case
<-
time
.
After
(
wait
)
:
case
<-
ctx
.
Done
()
:
return
}
}
}
func
(
h
*
AutoRelayHost
)
findRelays
(
ctx
context
.
Context
)
{
h
.
mx
.
Lock
()
if
len
(
h
.
relays
)
>=
DesiredRelays
{
h
.
mx
.
Unlock
()
return
}
need
:=
DesiredRelays
-
len
(
h
.
relays
)
h
.
mx
.
Unlock
()
limit
:=
20
for
;
need
>
limit
;
limit
*=
2
{
}
dctx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
60
*
time
.
Second
)
pis
,
err
:=
discovery
.
FindPeers
(
dctx
,
h
.
discover
,
"/libp2p/relay"
,
limit
)
cancel
()
if
err
!=
nil
{
log
.
Debugf
(
"error discovering relays: %s"
,
err
.
Error
())
return
}
// TODO better relay selection strategy; this just selects random relays
// but we should probably use ping latency as the selection metric
shuffleRelays
(
pis
)
update
:=
0
for
_
,
pi
:=
range
pis
{
h
.
mx
.
Lock
()
if
_
,
ok
:=
h
.
relays
[
pi
.
ID
];
ok
{
h
.
mx
.
Unlock
()
continue
}
h
.
mx
.
Unlock
()
cctx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
60
*
time
.
Second
)
err
=
h
.
Connect
(
cctx
,
pi
)
cancel
()
if
err
!=
nil
{
log
.
Debugf
(
"error connecting to relay %s: %s"
,
pi
.
ID
,
err
.
Error
())
continue
}
log
.
Debugf
(
"connected to relay %s"
,
pi
.
ID
)
h
.
mx
.
Lock
()
h
.
relays
[
pi
.
ID
]
=
pi
h
.
mx
.
Unlock
()
update
++
need
--
if
need
==
0
{
break
}
}
if
update
>
0
||
h
.
addrs
==
nil
{
h
.
updateAddrs
()
}
}
func
(
h
*
AutoRelayHost
)
updateAddrs
()
{
h
.
doUpdateAddrs
()
h
.
PushIdentify
()
}
func
(
h
*
AutoRelayHost
)
doUpdateAddrs
()
{
h
.
mx
.
Lock
()
defer
h
.
mx
.
Unlock
()
addrs
:=
h
.
addrsF
(
h
.
AllAddrs
())
raddrs
:=
make
([]
ma
.
Multiaddr
,
0
,
len
(
addrs
)
+
len
(
h
.
relays
))
// remove our public addresses from the list and replace them by just the public IP
for
_
,
addr
:=
range
addrs
{
if
manet
.
IsPublicAddr
(
addr
)
{
ip
,
err
:=
addr
.
ValueForProtocol
(
ma
.
P_IP4
)
if
err
==
nil
{
pub
,
err
:=
ma
.
NewMultiaddr
(
fmt
.
Sprintf
(
"/ip4/%s"
,
ip
))
if
err
!=
nil
{
panic
(
err
)
}
if
!
containsAddr
(
raddrs
,
pub
)
{
raddrs
=
append
(
raddrs
,
pub
)
}
continue
}
ip
,
err
=
addr
.
ValueForProtocol
(
ma
.
P_IP6
)
if
err
==
nil
{
pub
,
err
:=
ma
.
NewMultiaddr
(
fmt
.
Sprintf
(
"/ip6/%s"
,
ip
))
if
err
!=
nil
{
panic
(
err
)
}
if
!
containsAddr
(
raddrs
,
pub
)
{
raddrs
=
append
(
raddrs
,
pub
)
}
continue
}
}
else
{
raddrs
=
append
(
raddrs
,
addr
)
}
}
circuit
,
err
:=
ma
.
NewMultiaddr
(
"/p2p-circuit"
)
if
err
!=
nil
{
panic
(
err
)
}
for
_
,
pi
:=
range
h
.
relays
{
for
_
,
addr
:=
range
pi
.
Addrs
{
if
!
manet
.
IsPrivateAddr
(
addr
)
{
pub
:=
addr
.
Encapsulate
(
circuit
)
raddrs
=
append
(
raddrs
,
pub
)
}
}
}
h
.
addrs
=
raddrs
}
func
shuffleRelays
(
pis
[]
pstore
.
PeerInfo
)
{
for
i
:=
range
pis
{
j
:=
rand
.
Intn
(
i
+
1
)
pis
[
i
],
pis
[
j
]
=
pis
[
j
],
pis
[
i
]
}
}
func
containsAddr
(
lst
[]
ma
.
Multiaddr
,
addr
ma
.
Multiaddr
)
bool
{
for
_
,
xaddr
:=
range
lst
{
if
xaddr
.
Equal
(
addr
)
{
return
true
}
}
return
false
}
// notify
func
(
h
*
AutoRelayHost
)
Listen
(
inet
.
Network
,
ma
.
Multiaddr
)
{}
func
(
h
*
AutoRelayHost
)
ListenClose
(
inet
.
Network
,
ma
.
Multiaddr
)
{}
func
(
h
*
AutoRelayHost
)
Connected
(
inet
.
Network
,
inet
.
Conn
)
{}
func
(
h
*
AutoRelayHost
)
Disconnected
(
_
inet
.
Network
,
c
inet
.
Conn
)
{
p
:=
c
.
RemotePeer
()
h
.
mx
.
Lock
()
defer
h
.
mx
.
Unlock
()
if
_
,
ok
:=
h
.
relays
[
p
];
ok
{
delete
(
h
.
relays
,
p
)
select
{
case
h
.
disconnect
<-
struct
{}{}
:
default
:
}
}
}
func
(
h
*
AutoRelayHost
)
OpenedStream
(
inet
.
Network
,
inet
.
Stream
)
{}
func
(
h
*
AutoRelayHost
)
ClosedStream
(
inet
.
Network
,
inet
.
Stream
)
{}
var
_
host
.
Host
=
(
*
AutoRelayHost
)(
nil
)
p2p/host/relay/log.go
0 → 100644
View file @
a5858912
package
relay
import
(
logging
"github.com/ipfs/go-log"
)
var
log
=
logging
.
Logger
(
"relay"
)
p2p/host/relay/relay.go
0 → 100644
View file @
a5858912
package
relay
import
(
"context"
discovery
"github.com/libp2p/go-libp2p-discovery"
host
"github.com/libp2p/go-libp2p-host"
)
// RelayHost is a Host that provides Relay services.
type
RelayHost
struct
{
host
.
Host
advertise
discovery
.
Advertiser
}
// New constructs a new RelayHost
func
NewRelayHost
(
ctx
context
.
Context
,
host
host
.
Host
,
advertise
discovery
.
Advertiser
)
*
RelayHost
{
h
:=
&
RelayHost
{
Host
:
host
,
advertise
:
advertise
}
discovery
.
Advertise
(
ctx
,
advertise
,
"/libp2p/relay"
)
return
h
}
var
_
host
.
Host
=
(
*
RelayHost
)(
nil
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment