// 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 manetimport (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.typeConninterface {net.Conn// LocalMultiaddr returns the local Multiaddr associated // with this connectionLocalMultiaddr() ma.Multiaddr// RemoteMultiaddr returns the remote Multiaddr associated // with this connectionRemoteMultiaddr() 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.TCPConnmaEndpoints }{, }case *net.UDPConn:return &struct { *net.UDPConnmaEndpoints }{, }case *net.IPConn:return &struct { *net.IPConnmaEndpoints }{, }case *net.UnixConn:return &struct { *net.UnixConnmaEndpoints }{, }casehalfOpen:return &struct {halfOpenmaEndpoints }{, }default:return &struct {net.ConnmaEndpoints }{, } }}// 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 {returnnil, fmt.Errorf("failed to convert nconn.LocalAddr: nil") } , := FromNetAddr(.LocalAddr())if != nil {returnnil, fmt.Errorf("failed to convert nconn.LocalAddr: %s", ) } , := FromNetAddr(.RemoteAddr())if != nil {returnnil, fmt.Errorf("failed to convert nconn.RemoteAddr: %s", ) }returnwrap(, , ), nil}type maEndpoints struct { laddr ma.Multiaddr raddr ma.Multiaddr}// LocalMultiaddr returns the local address associated with// this connectionfunc ( *maEndpoints) () ma.Multiaddr {return .laddr}// RemoteMultiaddr returns the remote address associated with// this connectionfunc ( *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.typeDialerstruct {// 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 {returnnil, }// set the dialer's LocalAddr as naddr .Dialer.LocalAddr = }// get the net.Dial friendly arguments from the remote addr , , := DialArgs()if != nil {returnnil, }// ok, Dial!varnet.Connswitch {case"tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "unix": , = .Dialer.DialContext(, , )if != nil {returnnil, }default:returnnil, 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 {returnnil, } }returnwrap(, , ), 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.typeListenerinterface {// Accept waits for and returns the next connection to the listener. // Returns a Multiaddr friendly ConnAccept() (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 Listenertype maListener struct {net.Listener laddr ma.Multiaddr}// Accept waits for and returns the next connection to the listener.// Returns a Multiaddr friendly Connfunc ( *maListener) () (Conn, error) { , := .Listener.Accept()if != nil {returnnil, }varma.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 {returnnil, fmt.Errorf("failed to convert conn.RemoteAddr: %s", ) } }varma.Multiaddrif := .LocalAddr(); != nil && .String() != "" { , = FromNetAddr()if != nil {returnnil, fmt.Errorf("failed to convert conn.LocalAddr: %s", ) } }returnwrap(, , ), 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 {returnnil, } , := net.Listen(, )if != nil {returnnil, }// we want to fetch the new multiaddr from the listener, as it may // have resolved to some other value. WrapNetListener does it for us.returnWrapNetListener()}// WrapNetListener wraps a net.Listener with a manet.Listener.func ( net.Listener) (Listener, error) {if , := .(*netListenerAdapter); {return .Listener, nil } , := FromNetAddr(.Addr())if != nil {returnnil, }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.typePacketConninterface {net.PacketConnLocalMultiaddr() ma.MultiaddrReadFromMultiaddr(b []byte) (int, ma.Multiaddr, error)WriteToMultiaddr(b []byte, maddr ma.Multiaddr) (int, error)}// maPacketConn implements PacketConntype 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 {return0, }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 {returnnil, } , := net.ListenPacket(, )if != nil {returnnil, }// We want to fetch the new multiaddr from the listener, as it may // have resolved to some other value. WrapPacketConn does this.returnWrapPacketConn()}// WrapPacketConn wraps a net.PacketConn with a manet.PacketConn.func ( net.PacketConn) (PacketConn, error) { , := FromNetAddr(.LocalAddr())if != nil {returnnil, }return &maPacketConn{PacketConn: ,laddr: , }, nil}// InterfaceMultiaddrs will return the addresses matching net.InterfaceAddrsfunc () ([]ma.Multiaddr, error) { , := net.InterfaceAddrs()if != nil {returnnil, } := make([]ma.Multiaddr, len())for , := range { [], = FromNetAddr()if != nil {returnnil, } }return , nil}// AddrMatch returns the Multiaddrs that match the protocol stack on addrfunc ( ma.Multiaddr, []ma.Multiaddr) []ma.Multiaddr {// we should match transports entirely. := .Protocols() := make([]ma.Multiaddr, 0, len())for , := range { := .Protocols()iflen() != len() {continue } := truefor , := range {if [].Code != .Code { = falsebreak } }if { = append(, ) } }return}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.