2017-03-16 16:07:42 +01:00
// Package manet provides Multiaddr
// (https://github.com/multiformats/go-multiaddr) specific versions of common
// functions in Go's standard `net` package. This means wrappers of standard
// net symbols like `net.Dial` and `net.Listen`, as well as conversion to
// and from `net.Addr`.
2014-11-05 00:38:21 -08:00
package manet
2014-10-11 01:23:49 -07:00
import (
2016-08-16 20:31:17 -07:00
"context"
2023-01-05 17:14:00 -04:00
"errors"
2014-10-11 01:23:49 -07:00
"fmt"
"net"
2023-01-05 17:14:00 -04:00
"runtime"
"strings"
"git.wow.st/gmp/jni"
"golang.org/x/mobile/app"
2014-10-11 01:23:49 -07:00
2016-09-19 10:30:07 +08:00
ma "github.com/multiformats/go-multiaddr"
2014-10-11 01:23:49 -07:00
)
// Conn is the equivalent of a net.Conn object. It is the
// result of calling the Dial or Listen functions in this
// package, with associated local and remote Multiaddrs.
type Conn interface {
net . Conn
// LocalMultiaddr returns the local Multiaddr associated
// with this connection
LocalMultiaddr ( ) ma . Multiaddr
// RemoteMultiaddr returns the remote Multiaddr associated
// with this connection
RemoteMultiaddr ( ) ma . Multiaddr
}
2018-06-21 14:13:48 -07:00
type halfOpen interface {
net . Conn
CloseRead ( ) error
CloseWrite ( ) error
}
func wrap ( nconn net . Conn , laddr , raddr ma . Multiaddr ) Conn {
endpts := maEndpoints {
laddr : laddr ,
raddr : raddr ,
}
// This sucks. However, it's the only way to reliably expose the
// underlying methods. This way, users that need access to, e.g.,
// CloseRead and CloseWrite, can do so via type assertions.
switch nconn := nconn . ( type ) {
case * net . TCPConn :
return & struct {
* net . TCPConn
maEndpoints
} { nconn , endpts }
case * net . UDPConn :
return & struct {
* net . UDPConn
maEndpoints
} { nconn , endpts }
case * net . IPConn :
return & struct {
* net . IPConn
maEndpoints
} { nconn , endpts }
case * net . UnixConn :
return & struct {
* net . UnixConn
maEndpoints
} { nconn , endpts }
case halfOpen :
return & struct {
halfOpen
maEndpoints
} { nconn , endpts }
default :
return & struct {
net . Conn
maEndpoints
} { nconn , endpts }
}
}
// WrapNetConn wraps a net.Conn object with a Multiaddr friendly Conn.
//
// This function does it's best to avoid "hiding" methods exposed by the wrapped
// type. Guarantees:
//
2022-08-25 14:07:44 +02:00
// - If the wrapped connection exposes the "half-open" closer methods
// (CloseWrite, CloseRead), these will be available on the wrapped connection
// via type assertions.
// - If the wrapped connection is a UnixConn, IPConn, TCPConn, or UDPConn, all
// methods on these wrapped connections will be available via type assertions.
2014-10-11 01:23:49 -07:00
func WrapNetConn ( nconn net . Conn ) ( Conn , error ) {
2015-06-18 14:39:26 -07:00
if nconn == nil {
return nil , fmt . Errorf ( "failed to convert nconn.LocalAddr: nil" )
}
2014-10-11 01:23:49 -07:00
laddr , err := FromNetAddr ( nconn . LocalAddr ( ) )
if err != nil {
return nil , fmt . Errorf ( "failed to convert nconn.LocalAddr: %s" , err )
}
raddr , err := FromNetAddr ( nconn . RemoteAddr ( ) )
if err != nil {
return nil , fmt . Errorf ( "failed to convert nconn.RemoteAddr: %s" , err )
}
2018-06-21 14:13:48 -07:00
return wrap ( nconn , laddr , raddr ) , nil
2014-10-11 01:23:49 -07:00
}
2018-06-21 14:13:48 -07:00
type maEndpoints struct {
2014-10-11 01:23:49 -07:00
laddr ma . Multiaddr
raddr ma . Multiaddr
}
// LocalMultiaddr returns the local address associated with
// this connection
2018-06-21 14:13:48 -07:00
func ( c * maEndpoints ) LocalMultiaddr ( ) ma . Multiaddr {
2014-10-11 01:23:49 -07:00
return c . laddr
}
// RemoteMultiaddr returns the remote address associated with
// this connection
2018-06-21 14:13:48 -07:00
func ( c * maEndpoints ) RemoteMultiaddr ( ) ma . Multiaddr {
2014-10-11 01:23:49 -07:00
return c . raddr
}
// Dialer contains options for connecting to an address. It
// is effectively the same as net.Dialer, but its LocalAddr
// and RemoteAddr options are Multiaddrs, instead of net.Addrs.
type Dialer struct {
2014-11-20 00:54:16 -08:00
// Dialer is just an embedded net.Dialer, with all its options.
2014-10-11 01:23:49 -07:00
net . Dialer
// LocalAddr is the local address to use when dialing an
// address. The address must be of a compatible type for the
// network being dialed.
// If nil, a local address is automatically chosen.
LocalAddr ma . Multiaddr
}
// Dial connects to a remote address, using the options of the
// Dialer. Dialer uses an underlying net.Dialer to Dial a
// net.Conn, then wraps that in a Conn object (with local and
// remote Multiaddrs).
func ( d * Dialer ) Dial ( remote ma . Multiaddr ) ( Conn , error ) {
2016-08-16 20:31:17 -07:00
return d . DialContext ( context . Background ( ) , remote )
}
2014-10-11 01:23:49 -07:00
2017-03-16 16:07:42 +01:00
// DialContext allows to provide a custom context to Dial().
2016-08-16 20:31:17 -07:00
func ( d * Dialer ) DialContext ( ctx context . Context , remote ma . Multiaddr ) ( Conn , error ) {
2014-10-11 01:23:49 -07:00
// if a LocalAddr is specified, use it on the embedded dialer.
if d . LocalAddr != nil {
// convert our multiaddr to net.Addr friendly
naddr , err := ToNetAddr ( d . LocalAddr )
if err != nil {
return nil , err
}
// set the dialer's LocalAddr as naddr
d . Dialer . LocalAddr = naddr
}
// get the net.Dial friendly arguments from the remote addr
rnet , rnaddr , err := DialArgs ( remote )
if err != nil {
return nil , err
}
// ok, Dial!
2014-11-20 00:54:16 -08:00
var nconn net . Conn
switch rnet {
2018-11-30 19:37:21 -05:00
case "tcp" , "tcp4" , "tcp6" , "udp" , "udp4" , "udp6" , "unix" :
2016-08-16 20:31:17 -07:00
nconn , err = d . Dialer . DialContext ( ctx , rnet , rnaddr )
2014-11-20 00:54:16 -08:00
if err != nil {
return nil , err
}
2016-09-15 19:24:46 -07:00
default :
return nil , fmt . Errorf ( "unrecognized network: %s" , rnet )
2014-10-11 01:23:49 -07:00
}
// get local address (pre-specified or assigned within net.Conn)
local := d . LocalAddr
2018-11-30 19:37:21 -05:00
// This block helps us avoid parsing addresses in transports (such as unix
// sockets) that don't have local addresses when dialing out.
if local == nil && nconn . LocalAddr ( ) . String ( ) != "" {
2014-10-11 01:23:49 -07:00
local , err = FromNetAddr ( nconn . LocalAddr ( ) )
if err != nil {
return nil , err
}
}
2018-06-21 14:13:48 -07:00
return wrap ( nconn , local , remote ) , nil
2014-10-11 01:23:49 -07:00
}
// Dial connects to a remote address. It uses an underlying net.Conn,
// then wraps it in a Conn object (with local and remote Multiaddrs).
func Dial ( remote ma . Multiaddr ) ( Conn , error ) {
return ( & Dialer { } ) . Dial ( remote )
}
// A Listener is a generic network listener for stream-oriented protocols.
// it uses an embedded net.Listener, overriding net.Listener.Accept to
// return a Conn and providing Multiaddr.
type Listener interface {
// Accept waits for and returns the next connection to the listener.
// Returns a Multiaddr friendly Conn
Accept ( ) ( Conn , error )
// Close closes the listener.
// Any blocked Accept operations will be unblocked and return errors.
Close ( ) error
// Multiaddr returns the listener's (local) Multiaddr.
Multiaddr ( ) ma . Multiaddr
// Addr returns the net.Listener's network address.
Addr ( ) net . Addr
}
2018-03-08 08:40:19 -08:00
type netListenerAdapter struct {
Listener
}
func ( nla * netListenerAdapter ) Accept ( ) ( net . Conn , error ) {
return nla . Listener . Accept ( )
}
// NetListener turns this Listener into a net.Listener.
//
2022-08-25 14:07:44 +02:00
// - Connections returned from Accept implement multiaddr/net Conn.
// - Calling WrapNetListener on the net.Listener returned by this function will
// return the original (underlying) multiaddr/net Listener.
2018-03-08 08:40:19 -08:00
func NetListener ( l Listener ) net . Listener {
return & netListenerAdapter { l }
}
2014-10-11 01:23:49 -07:00
// maListener implements Listener
type maListener struct {
net . Listener
laddr ma . Multiaddr
}
// Accept waits for and returns the next connection to the listener.
// Returns a Multiaddr friendly Conn
func ( l * maListener ) Accept ( ) ( Conn , error ) {
nconn , err := l . Listener . Accept ( )
if err != nil {
return nil , err
}
2018-11-30 19:37:21 -05:00
var raddr ma . Multiaddr
// This block protects us in transports (i.e. unix sockets) that don't have
// remote addresses for inbound connections.
2021-06-23 10:48:13 -07:00
if addr := nconn . RemoteAddr ( ) ; addr != nil && addr . String ( ) != "" {
raddr , err = FromNetAddr ( addr )
2018-11-30 19:37:21 -05:00
if err != nil {
return nil , fmt . Errorf ( "failed to convert conn.RemoteAddr: %s" , err )
}
2014-10-11 01:23:49 -07:00
}
2021-01-21 14:59:39 +05:30
var laddr ma . Multiaddr
2021-06-23 10:48:13 -07:00
if addr := nconn . LocalAddr ( ) ; addr != nil && addr . String ( ) != "" {
laddr , err = FromNetAddr ( addr )
2021-01-21 14:59:39 +05:30
if err != nil {
return nil , fmt . Errorf ( "failed to convert conn.LocalAddr: %s" , err )
}
}
return wrap ( nconn , laddr , raddr ) , nil
2014-10-11 01:23:49 -07:00
}
// Multiaddr returns the listener's (local) Multiaddr.
func ( l * maListener ) Multiaddr ( ) ma . Multiaddr {
return l . laddr
}
// Addr returns the listener's network address.
func ( l * maListener ) Addr ( ) net . Addr {
return l . Listener . Addr ( )
}
// Listen announces on the local network address laddr.
// The Multiaddr must be a "ThinWaist" stream-oriented network:
// ip4/tcp, ip6/tcp, (TODO: unix, unixpacket)
// See Dial for the syntax of laddr.
func Listen ( laddr ma . Multiaddr ) ( Listener , error ) {
// get the net.Listen friendly arguments from the remote addr
lnet , lnaddr , err := DialArgs ( laddr )
if err != nil {
return nil , err
}
2016-06-10 15:33:31 -07:00
nl , err := net . Listen ( lnet , lnaddr )
2014-11-20 05:09:46 -08:00
if err != nil {
return nil , err
2014-10-11 01:23:49 -07:00
}
2015-01-18 22:20:46 -08:00
// we want to fetch the new multiaddr from the listener, as it may
// have resolved to some other value. WrapNetListener does it for us.
return WrapNetListener ( nl )
}
// WrapNetListener wraps a net.Listener with a manet.Listener.
func WrapNetListener ( nl net . Listener ) ( Listener , error ) {
2018-03-08 08:40:19 -08:00
if nla , ok := nl . ( * netListenerAdapter ) ; ok {
return nla . Listener , nil
}
2015-01-18 22:20:46 -08:00
laddr , err := FromNetAddr ( nl . Addr ( ) )
2015-01-12 18:07:14 -08:00
if err != nil {
return nil , err
}
2014-10-11 01:23:49 -07:00
return & maListener {
Listener : nl ,
laddr : laddr ,
} , nil
}
2014-11-05 00:38:21 -08:00
2016-12-17 00:17:22 +00:00
// A PacketConn is a generic packet oriented network connection which uses an
// underlying net.PacketConn, wrapped with the locally bound Multiaddr.
type PacketConn interface {
2018-03-03 21:19:40 -05:00
net . PacketConn
2016-12-17 00:17:22 +00:00
2018-03-03 21:19:40 -05:00
LocalMultiaddr ( ) ma . Multiaddr
2016-12-17 00:17:22 +00:00
2018-03-03 21:19:40 -05:00
ReadFromMultiaddr ( b [ ] byte ) ( int , ma . Multiaddr , error )
WriteToMultiaddr ( b [ ] byte , maddr ma . Multiaddr ) ( int , error )
2016-12-17 00:17:22 +00:00
}
// maPacketConn implements PacketConn
type maPacketConn struct {
net . PacketConn
laddr ma . Multiaddr
}
2018-03-03 21:19:40 -05:00
var _ PacketConn = ( * maPacketConn ) ( nil )
2016-12-17 00:17:22 +00:00
2018-03-03 21:19:40 -05:00
// LocalMultiaddr returns the bound local Multiaddr.
func ( l * maPacketConn ) LocalMultiaddr ( ) ma . Multiaddr {
2016-12-17 00:17:22 +00:00
return l . laddr
}
2018-03-03 21:19:40 -05:00
func ( l * maPacketConn ) ReadFromMultiaddr ( b [ ] byte ) ( int , ma . Multiaddr , error ) {
n , addr , err := l . ReadFrom ( b )
2016-12-17 00:17:22 +00:00
maddr , _ := FromNetAddr ( addr )
return n , maddr , err
}
2018-03-03 21:19:40 -05:00
func ( l * maPacketConn ) WriteToMultiaddr ( b [ ] byte , maddr ma . Multiaddr ) ( int , error ) {
2016-12-17 00:17:22 +00:00
addr , err := ToNetAddr ( maddr )
if err != nil {
return 0 , err
}
2018-03-03 21:19:40 -05:00
return l . WriteTo ( b , addr )
2016-12-17 00:17:22 +00:00
}
// ListenPacket announces on the local network address laddr.
// The Multiaddr must be a packet driven network, like udp4 or udp6.
// See Dial for the syntax of laddr.
func ListenPacket ( laddr ma . Multiaddr ) ( PacketConn , error ) {
lnet , lnaddr , err := DialArgs ( laddr )
if err != nil {
return nil , err
}
pc , err := net . ListenPacket ( lnet , lnaddr )
if err != nil {
return nil , err
}
// We want to fetch the new multiaddr from the listener, as it may
// have resolved to some other value. WrapPacketConn does this.
return WrapPacketConn ( pc )
}
// WrapPacketConn wraps a net.PacketConn with a manet.PacketConn.
func WrapPacketConn ( pc net . PacketConn ) ( PacketConn , error ) {
laddr , err := FromNetAddr ( pc . LocalAddr ( ) )
if err != nil {
return nil , err
}
return & maPacketConn {
PacketConn : pc ,
laddr : laddr ,
} , nil
}
2014-11-05 00:38:21 -08:00
// InterfaceMultiaddrs will return the addresses matching net.InterfaceAddrs
func InterfaceMultiaddrs ( ) ( [ ] ma . Multiaddr , error ) {
addrs , err := net . InterfaceAddrs ( )
if err != nil {
2023-01-05 17:14:00 -04:00
if runtime . GOOS == "android" {
// To fix [x/mobile: Calling net.InterfaceAddrs() fails on Android SDK 30](https://github.com/golang/go/issues/40569)
addrs , err = getInterfaceAddrsFromAndroid ( )
if err != nil {
return nil , err
}
} else {
return nil , err
}
2014-11-05 00:38:21 -08:00
}
maddrs := make ( [ ] ma . Multiaddr , len ( addrs ) )
for i , a := range addrs {
maddrs [ i ] , err = FromNetAddr ( a )
if err != nil {
return nil , err
}
}
return maddrs , nil
}
2015-01-12 18:45:34 -08:00
2023-01-05 17:14:00 -04:00
func getInterfaceAddrsFromAndroid ( ) ( [ ] net . Addr , error ) {
var ifaceString string
// if use "golang.org/x/mobile/app", use app.RunOnJVM() below
err := app . RunOnJVM ( func ( vm , env , ctx uintptr ) error {
jniEnv := jni . EnvFor ( env )
// cls := jni.FindClass(jniEnv, "YOUR/PACKAGE/NAME/CLASSNAME")
// m := jni.GetMethodID(jniEnv, cls, "getInterfacesAsString", "()Ljava/lang/String;")
// n, err := jni.CallStaticObjectMethod(jniEnv, cls, m)
// above `YOUR.PACKAGE.NAME` `CLASSNAME.java` sometimes will cause strange [java.lang.ClassNotFoundException: Didn't find class on path: dexpathlist](https://stackoverflow.com/questions/22399572/java-lang-classnotfoundexception-didnt-find-class-on-path-dexpathlist)
// so use below `MainApplication.java` comes from `<application android:name=".MainApplication"` in `YOUR_PROJECT/android/app/src/main/AndroidManifest.xml`
appCtx := jni . Object ( ctx )
cls := jni . GetObjectClass ( jniEnv , appCtx )
m := jni . GetMethodID ( jniEnv , cls , "getInterfacesAsString" , "()Ljava/lang/String;" )
n , err := jni . CallObjectMethod ( jniEnv , appCtx , m )
if err != nil {
return errors . New ( "getInterfacesAsString Method invocation failed" )
}
ifaceString = jni . GoString ( jniEnv , jni . String ( n ) )
return nil
} )
if err != nil {
return nil , err
}
var ifat [ ] net . Addr
for _ , iface := range strings . Split ( ifaceString , "\n" ) {
// Example of the strings we're processing:
// wlan0 30 1500 true true false false true | fe80::2f60:2c82:4163:8389%wlan0/64 10.1.10.131/24
// r_rmnet_data0 21 1500 true false false false false | fe80::9318:6093:d1ad:ba7f%r_rmnet_data0/64
// mnet_data2 12 1500 true false false false false | fe80::3c8c:44dc:46a9:9907%rmnet_data2/64
if strings . TrimSpace ( iface ) == "" {
continue
}
fields := strings . Split ( iface , "|" )
if len ( fields ) != 2 {
// log.Printf("getInterfaces: unable to split %q", iface)
continue
}
addrs := strings . Trim ( fields [ 1 ] , " \n" )
for _ , addr := range strings . Split ( addrs , " " ) {
_ , ip , err := net . ParseCIDR ( addr )
if err == nil {
ifat = append ( ifat , ip )
}
}
}
return ifat , nil
}
2015-01-12 18:45:34 -08:00
// AddrMatch returns the Multiaddrs that match the protocol stack on addr
func AddrMatch ( match ma . Multiaddr , addrs [ ] ma . Multiaddr ) [ ] ma . Multiaddr {
// we should match transports entirely.
p1s := match . Protocols ( )
out := make ( [ ] ma . Multiaddr , 0 , len ( addrs ) )
for _ , a := range addrs {
p2s := a . Protocols ( )
if len ( p1s ) != len ( p2s ) {
continue
}
match := true
for i , p2 := range p2s {
if p1s [ i ] . Code != p2 . Code {
match = false
break
}
}
if match {
out = append ( out , a )
}
}
return out
}