// 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`.
package manet import ( ma ) // 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 } type halfOpen interface { net.Conn CloseRead() error CloseWrite() error } func wrap( net.Conn, , ma.Multiaddr) Conn { := maEndpoints{ laddr: , 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 := .(type) { case *net.TCPConn: return &struct { *net.TCPConn maEndpoints }{, } case *net.UDPConn: return &struct { *net.UDPConn maEndpoints }{, } case *net.IPConn: return &struct { *net.IPConn maEndpoints }{, } case *net.UnixConn: return &struct { *net.UnixConn maEndpoints }{, } case halfOpen: return &struct { halfOpen maEndpoints }{, } default: return &struct { net.Conn maEndpoints }{, } } } // 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: // // - 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. func ( net.Conn) (Conn, error) { if == nil { return nil, fmt.Errorf("failed to convert nconn.LocalAddr: nil") } , := FromNetAddr(.LocalAddr()) if != nil { return nil, fmt.Errorf("failed to convert nconn.LocalAddr: %s", ) } , := FromNetAddr(.RemoteAddr()) if != nil { return nil, fmt.Errorf("failed to convert nconn.RemoteAddr: %s", ) } return wrap(, , ), nil } type maEndpoints struct { laddr ma.Multiaddr raddr ma.Multiaddr } // LocalMultiaddr returns the local address associated with // this connection func ( *maEndpoints) () ma.Multiaddr { return .laddr } // RemoteMultiaddr returns the remote address associated with // this connection func ( *maEndpoints) () ma.Multiaddr { return .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 { // Dialer is just an embedded net.Dialer, with all its options. 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 ( *Dialer) ( ma.Multiaddr) (Conn, error) { return .DialContext(context.Background(), ) } // DialContext allows to provide a custom context to Dial(). func ( *Dialer) ( context.Context, ma.Multiaddr) (Conn, error) { // if a LocalAddr is specified, use it on the embedded dialer. if .LocalAddr != nil { // convert our multiaddr to net.Addr friendly , := ToNetAddr(.LocalAddr) if != nil { return nil, } // set the dialer's LocalAddr as naddr .Dialer.LocalAddr = } // get the net.Dial friendly arguments from the remote addr , , := DialArgs() if != nil { return nil, } // ok, Dial! var net.Conn switch { case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "unix": , = .Dialer.DialContext(, , ) if != nil { return nil, } default: return nil, fmt.Errorf("unrecognized network: %s", ) } // get local address (pre-specified or assigned within net.Conn) := .LocalAddr // This block helps us avoid parsing addresses in transports (such as unix // sockets) that don't have local addresses when dialing out. if == nil && .LocalAddr().String() != "" { , = FromNetAddr(.LocalAddr()) if != nil { return nil, } } return wrap(, , ), nil } // 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 ( ma.Multiaddr) (Conn, error) { return (&Dialer{}).Dial() } // 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 } type netListenerAdapter struct { Listener } func ( *netListenerAdapter) () (net.Conn, error) { return .Listener.Accept() } // NetListener turns this Listener into a net.Listener. // // - 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. func ( Listener) net.Listener { return &netListenerAdapter{} } // 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 ( *maListener) () (Conn, error) { , := .Listener.Accept() if != nil { return nil, } var ma.Multiaddr // This block protects us in transports (i.e. unix sockets) that don't have // remote addresses for inbound connections. if := .RemoteAddr(); != nil && .String() != "" { , = FromNetAddr() if != nil { return nil, fmt.Errorf("failed to convert conn.RemoteAddr: %s", ) } } var ma.Multiaddr if := .LocalAddr(); != nil && .String() != "" { , = FromNetAddr() if != nil { return nil, fmt.Errorf("failed to convert conn.LocalAddr: %s", ) } } return wrap(, , ), nil } // Multiaddr returns the listener's (local) Multiaddr. func ( *maListener) () ma.Multiaddr { return .laddr } // Addr returns the listener's network address. func ( *maListener) () net.Addr { return .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 ( ma.Multiaddr) (Listener, error) { // get the net.Listen friendly arguments from the remote addr , , := DialArgs() if != nil { return nil, } , := net.Listen(, ) if != nil { return nil, } // 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() } // WrapNetListener wraps a net.Listener with a manet.Listener. func ( net.Listener) (Listener, error) { if , := .(*netListenerAdapter); { return .Listener, nil } , := FromNetAddr(.Addr()) if != nil { return nil, } return &maListener{ Listener: , laddr: , }, nil } // A PacketConn is a generic packet oriented network connection which uses an // underlying net.PacketConn, wrapped with the locally bound Multiaddr. type PacketConn interface { net.PacketConn LocalMultiaddr() ma.Multiaddr ReadFromMultiaddr(b []byte) (int, ma.Multiaddr, error) WriteToMultiaddr(b []byte, maddr ma.Multiaddr) (int, error) } // maPacketConn implements PacketConn type maPacketConn struct { net.PacketConn laddr ma.Multiaddr } var _ PacketConn = (*maPacketConn)(nil) // LocalMultiaddr returns the bound local Multiaddr. func ( *maPacketConn) () ma.Multiaddr { return .laddr } func ( *maPacketConn) ( []byte) (int, ma.Multiaddr, error) { , , := .ReadFrom() , := FromNetAddr() return , , } func ( *maPacketConn) ( []byte, ma.Multiaddr) (int, error) { , := ToNetAddr() if != nil { return 0, } return .WriteTo(, ) } // 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 ( ma.Multiaddr) (PacketConn, error) { , , := DialArgs() if != nil { return nil, } , := net.ListenPacket(, ) if != nil { return nil, } // We want to fetch the new multiaddr from the listener, as it may // have resolved to some other value. WrapPacketConn does this. return WrapPacketConn() } // WrapPacketConn wraps a net.PacketConn with a manet.PacketConn. func ( net.PacketConn) (PacketConn, error) { , := FromNetAddr(.LocalAddr()) if != nil { return nil, } return &maPacketConn{ PacketConn: , laddr: , }, nil } // InterfaceMultiaddrs will return the addresses matching net.InterfaceAddrs func () ([]ma.Multiaddr, error) { , := net.InterfaceAddrs() if != nil { return nil, } := make([]ma.Multiaddr, len()) for , := range { [], = FromNetAddr() if != nil { return nil, } } return , nil } // AddrMatch returns the Multiaddrs that match the protocol stack on addr func ( ma.Multiaddr, []ma.Multiaddr) []ma.Multiaddr { // we should match transports entirely. := .Protocols() := make([]ma.Multiaddr, 0, len()) for , := range { := .Protocols() if len() != len() { continue } := true for , := range { if [].Code != .Code { = false break } } if { = append(, ) } } return }