github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/src/runtime/ppapi/network_nacl.go (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ppapi
     6  
     7  import (
     8  	"encoding/binary"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"net"
    13  	"strconv"
    14  	"strings"
    15  	"time"
    16  	"unsafe"
    17  )
    18  
    19  var (
    20  	errCreateAddressFailed      = errors.New("CreateAddress failed")
    21  	errMalformedAddress         = errors.New("malformed network address")
    22  	errLocalAddrFailed          = errors.New("LocalAddr failed")
    23  	errRemoteAddrFailed         = errors.New("RemoteAddr failed")
    24  	errDeadlineNotSupported     = errors.New("deadlines are not supported")
    25  	errCreateTCPSocketFailed    = errors.New("could not create TCP socket")
    26  	errCreateUDPSocketFailed    = errors.New("could not create UDP socket")
    27  	errNotConnected             = errors.New("not connected")
    28  	errCreateHostResolverFailed = errors.New("CreateHostResolver failed")
    29  	errCanonicalNameFailed      = errors.New("CanonicalName failed")
    30  	errCanonNameFlagNotSet      = errors.New("PP_HOSTRESOLVER_FLAG_CANONNAME not set in HostResolverHint")
    31  	errHostResolverFailed       = errors.New("host resolution failed")
    32  )
    33  
    34  // HostResolver supports host name resolution.
    35  //
    36  // It isn't normally necessary to use the HostResolver directly, since the Dial
    37  // and Listen methods perform host resolution automatically.
    38  type HostResolver struct {
    39  	Resource
    40  }
    41  
    42  // HostResolveHint represents hints for host resolution.
    43  type HostResolverHint struct {
    44  	Family NetAddressFamily
    45  	Flags  int32
    46  }
    47  
    48  // CreateHostResolver creates a HostResolver.
    49  func (inst Instance) CreateHostResolver() (resolver HostResolver, err error) {
    50  	resolver.id = ppb_hostresolver_create(inst.id)
    51  	if resolver.id == 0 {
    52  		err = errCreateHostResolverFailed
    53  	}
    54  	return
    55  }
    56  
    57  // Resolve requests resolution of a host name.
    58  //
    59  // If the call completes successfully, the results can be retrieved by
    60  // CanonicalName(), NetAddressCount() and NetAddress().
    61  func (resolver HostResolver) Resolve(host string, port uint16, hint *HostResolverHint) error {
    62  	name := append([]byte(host), 0)
    63  	code := ppb_hostresolver_resolve(
    64  		resolver.id, &name[0], port,
    65  		(*pp_HostResolverHint)(unsafe.Pointer(hint)), ppNullCompletionCallback)
    66  	return decodeError(Error(code))
    67  }
    68  
    69  // CanonicalName gets the canonical name of the host.
    70  func (resolver HostResolver) GetCanonicalName() (s string, err error) {
    71  	var ppVar pp_Var
    72  	ppb_hostresolver_get_canonical_name(&ppVar, resolver.id)
    73  	var v Var
    74  	v.fromPP(ppVar)
    75  	s, err = v.AsString()
    76  	if err != nil {
    77  		err = errCanonicalNameFailed
    78  		return
    79  	}
    80  	if s == "" {
    81  		err = errCanonNameFlagNotSet
    82  		return
    83  	}
    84  	return
    85  }
    86  
    87  // NetAddresses returns the resolved network addresses.
    88  func (resolver HostResolver) NetAddresses() []NetAddress {
    89  	count := ppb_hostresolver_get_net_address_count(resolver.id)
    90  	var addresses []NetAddress
    91  	for i := uint32(0); i != count; i++ {
    92  		var addr NetAddress
    93  		addr.id = ppb_hostresolver_get_net_address(resolver.id, i)
    94  		if addr.id != 0 {
    95  			addresses = append(addresses, addr)
    96  		}
    97  	}
    98  	return addresses
    99  }
   100  
   101  // ResolveNetAddress resolves a network address.
   102  func (inst Instance) ResolveNetAddress(network, addr string) (na NetAddress, err error) {
   103  	if strings.HasPrefix(addr, "[::]:") {
   104  		// TODO(bprosnitz) We really shouldn't have to do this. Chrome won't resolve the IPv6
   105  		// address for some reason. Fix this.
   106  		addr = strings.Replace(addr, "[::]:", "127.0.0.1:", 1)
   107  	}
   108  	host, strport, err := net.SplitHostPort(addr)
   109  	if err != nil {
   110  		panic(fmt.Sprintf("Failed to resolve 1 %s: %s", addr, err))
   111  		return
   112  	}
   113  	port, err := strconv.Atoi(strport)
   114  	if err != nil {
   115  		panic(fmt.Sprintf("Failed to resolve 2 %s: %s", addr, err))
   116  
   117  		return
   118  	}
   119  	var hint HostResolverHint
   120  	switch network {
   121  	case "tcp", "udp":
   122  		hint.Family = PP_NETADDRESS_FAMILY_UNSPECIFIED
   123  	case "tcp4", "udp4":
   124  		hint.Family = PP_NETADDRESS_FAMILY_IPV4
   125  	case "tcp6", "udp6":
   126  		hint.Family = PP_NETADDRESS_FAMILY_IPV6
   127  	default:
   128  		err = fmt.Errorf("unsupported network: %q", network)
   129  		return
   130  	}
   131  	resolver, err := inst.CreateHostResolver()
   132  	if err != nil {
   133  		panic(fmt.Sprintf("Failed to resolve 3 %s: %s", addr, err))
   134  
   135  		return
   136  	}
   137  	defer resolver.Release()
   138  	if err = resolver.Resolve(host, uint16(port), &hint); err != nil {
   139  		panic(fmt.Sprintf("Failed to resolve 4 %s: %s", addr, err))
   140  		return
   141  	}
   142  	addrs := resolver.NetAddresses()
   143  	if len(addrs) == 0 {
   144  		err = errHostResolverFailed
   145  		panic(fmt.Sprintf("Failed to resolve 5 %s: %s", addr, err))
   146  		return
   147  	}
   148  	for _, addr := range addrs[1:] {
   149  		addr.Release()
   150  	}
   151  	na = addrs[0]
   152  	return
   153  }
   154  
   155  // ResolveTCPAddr parses addr as a TCP address of the form "host:port" or
   156  // "[ipv6-host%zone]:port" and resolves a pair of domain name and port name on
   157  // the network net, which must be "tcp", "tcp4" or "tcp6". A literal address or
   158  // host name for IPv6 must be enclosed in square brackets, as in "[::1]:80",
   159  // "[ipv6-host]:http" or "[ipv6-host%zone]:80".
   160  func (inst Instance) ResolveTCPAddr(network, addr string) (*net.TCPAddr, error) {
   161  	na, err := inst.ResolveNetAddress(network, addr)
   162  	if err != nil {
   163  		return nil, err
   164  	}
   165  	defer na.Release()
   166  	return na.TCPAddr()
   167  }
   168  
   169  // ResolveUDPAddr parses addr as a UDP address of the form "host:port" or
   170  // "[ipv6-host%zone]:port" and resolves a pair of domain name and port name on
   171  // the network net, which must be "udp", "udp4" or "udp6". A literal address or
   172  // host name for IPv6 must be enclosed in square brackets, as in "[::1]:80",
   173  // "[ipv6-host]:http" or "[ipv6-host%zone]:80".
   174  func (inst Instance) ResolveUDPAddr(network, addr string) (*net.UDPAddr, error) {
   175  	na, err := inst.ResolveNetAddress(network, addr)
   176  	if err != nil {
   177  		return nil, err
   178  	}
   179  	defer na.Release()
   180  	return na.UDPAddr()
   181  }
   182  
   183  // NetAddress represents a network address.
   184  type NetAddress struct {
   185  	Resource
   186  }
   187  
   188  // createTCPAddress creates an address from a net.TCPAddr.
   189  func (inst Instance) CreateTCPNetAddress(net string, addr *net.TCPAddr) (na NetAddress, err error) {
   190  	if net == "tcp" || net == "tcp4" {
   191  		if ipv4 := addr.IP.To4(); ipv4 != nil {
   192  			var ppNetAddress pp_NetAddress_IPv4
   193  			binary.BigEndian.PutUint16(ppNetAddress[0:2], uint16(addr.Port))
   194  			copy(ppNetAddress[2:6], ipv4)
   195  			na.id = ppb_netaddress_create_from_ipv4_address(inst.id, &ppNetAddress)
   196  			if na.id == 0 {
   197  				err = errCreateAddressFailed
   198  			}
   199  			return
   200  		}
   201  	}
   202  
   203  	if net == "tcp" || net == "tcp6" {
   204  		if ipv6 := addr.IP.To16(); ipv6 != nil {
   205  			var ppNetAddress pp_NetAddress_IPv6
   206  			binary.BigEndian.PutUint16(ppNetAddress[0:2], uint16(addr.Port))
   207  			copy(ppNetAddress[2:18], ipv6)
   208  			na.id = ppb_netaddress_create_from_ipv6_address(inst.id, &ppNetAddress)
   209  			if na.id == 0 {
   210  				err = errCreateAddressFailed
   211  			}
   212  			return
   213  		}
   214  	}
   215  
   216  	err = errMalformedAddress
   217  	return
   218  }
   219  
   220  // decodeTCPAddress returns the TCP address.
   221  func (na NetAddress) TCPAddr() (addr *net.TCPAddr, err error) {
   222  	family := ppb_netaddress_get_family(na.id)
   223  	switch family {
   224  	case PP_NETADDRESS_FAMILY_UNSPECIFIED:
   225  		err = errMalformedAddress
   226  	case PP_NETADDRESS_FAMILY_IPV4:
   227  		var ipv4 pp_NetAddress_IPv4
   228  		if ok := ppb_netaddress_describe_as_ipv4_address(na.id, &ipv4); ok == ppFalse {
   229  			err = errMalformedAddress
   230  			return
   231  		}
   232  		addr = &net.TCPAddr{Port: int(binary.BigEndian.Uint16(ipv4[0:2])), IP: make([]byte, 4)}
   233  		copy(addr.IP, ipv4[2:6])
   234  	case PP_NETADDRESS_FAMILY_IPV6:
   235  		var ipv6 pp_NetAddress_IPv6
   236  		if ok := ppb_netaddress_describe_as_ipv6_address(na.id, &ipv6); ok == ppFalse {
   237  			err = errMalformedAddress
   238  			return
   239  		}
   240  		addr = &net.TCPAddr{Port: int(binary.BigEndian.Uint16(ipv6[0:2])), IP: make([]byte, 16)}
   241  		copy(addr.IP, ipv6[2:18])
   242  	}
   243  	return
   244  }
   245  
   246  // createUDPAddress creates an address from a net.UDPAddr.
   247  func (inst Instance) CreateUDPNetAddress(net string, addr *net.UDPAddr) (na NetAddress, err error) {
   248  	if net == "udp" || net == "udp4" {
   249  		if ipv4 := addr.IP.To4(); ipv4 != nil {
   250  			var ppNetAddress pp_NetAddress_IPv4
   251  			binary.BigEndian.PutUint16(ppNetAddress[0:2], uint16(addr.Port))
   252  			copy(ppNetAddress[2:6], ipv4)
   253  			na.id = ppb_netaddress_create_from_ipv4_address(inst.id, &ppNetAddress)
   254  			if na.id == 0 {
   255  				err = errCreateAddressFailed
   256  			}
   257  			return
   258  		}
   259  	}
   260  
   261  	if net == "udp" || net == "udp6" {
   262  		if ipv6 := addr.IP.To16(); ipv6 != nil {
   263  			var ppNetAddress pp_NetAddress_IPv6
   264  			binary.BigEndian.PutUint16(ppNetAddress[0:2], uint16(addr.Port))
   265  			copy(ppNetAddress[2:18], ipv6)
   266  			na.id = ppb_netaddress_create_from_ipv6_address(inst.id, &ppNetAddress)
   267  			if na.id == 0 {
   268  				err = errCreateAddressFailed
   269  			}
   270  			return
   271  		}
   272  	}
   273  
   274  	err = errMalformedAddress
   275  	return
   276  }
   277  
   278  // decodeUDPAddress returns the UDP address.
   279  func (na NetAddress) UDPAddr() (addr *net.UDPAddr, err error) {
   280  	family := ppb_netaddress_get_family(na.id)
   281  	switch family {
   282  	case PP_NETADDRESS_FAMILY_UNSPECIFIED:
   283  		err = errMalformedAddress
   284  	case PP_NETADDRESS_FAMILY_IPV4:
   285  		var ipv4 pp_NetAddress_IPv4
   286  		if ok := ppb_netaddress_describe_as_ipv4_address(na.id, &ipv4); ok == ppFalse {
   287  			err = errMalformedAddress
   288  			return
   289  		}
   290  		addr = &net.UDPAddr{Port: int(binary.BigEndian.Uint16(ipv4[0:2])), IP: make([]byte, 4)}
   291  		copy(addr.IP, ipv4[2:6])
   292  	case PP_NETADDRESS_FAMILY_IPV6:
   293  		var ipv6 pp_NetAddress_IPv6
   294  		if ok := ppb_netaddress_describe_as_ipv6_address(na.id, &ipv6); ok == ppFalse {
   295  			err = errMalformedAddress
   296  			return
   297  		}
   298  		addr = &net.UDPAddr{Port: int(binary.BigEndian.Uint16(ipv6[0:2])), IP: make([]byte, 16)}
   299  		copy(addr.IP, ipv6[2:18])
   300  	}
   301  	return
   302  }
   303  
   304  // tcpSocket implements functions common to both dialed and lister sockets.
   305  type tcpSocket struct {
   306  	Resource
   307  	closed bool
   308  }
   309  
   310  // CreateTCPConn creates a fresh, unconnected socket.
   311  //
   312  // Permissions: Apps permission socket with subrule tcp-connect is required for
   313  // Connect(); subrule tcp-listen is required for Listen(). For more details
   314  // about network communication permissions, please see:
   315  // http://developer.chrome.com/apps/app_network.html
   316  func (inst Instance) createTCPConn() (s tcpSocket, err error) {
   317  	id := ppb_tcpsocket_create(inst.id)
   318  	if id == 0 {
   319  		err = errCreateTCPSocketFailed
   320  		return
   321  	}
   322  	s.id = id
   323  	return
   324  }
   325  
   326  // Bind the socket to an address.
   327  func (sock *tcpSocket) bind(addr *NetAddress) error {
   328  	code := ppb_tcpsocket_bind(sock.id, addr.id, ppNullCompletionCallback)
   329  	return decodeError(Error(code))
   330  }
   331  
   332  // Accept a connection.
   333  func (sock *tcpSocket) accept() (accepted *TCPConn, err error) {
   334  	accepted = &TCPConn{}
   335  	code := ppb_tcpsocket_accept(sock.id, &accepted.id, ppNullCompletionCallback)
   336  	if Error(code) == PP_ERROR_ABORTED {
   337  		err = io.EOF
   338  	} else if code < 0 {
   339  		err = decodeError(Error(code))
   340  	}
   341  	return
   342  }
   343  
   344  // Connects the socket to the given address.
   345  //
   346  // The socket must not be listening. Binding the socket beforehand is optional.
   347  func (sock *tcpSocket) connect(addr *NetAddress) error {
   348  	code := ppb_tcpsocket_connect(sock.id, addr.id, ppNullCompletionCallback)
   349  	return decodeError(Error(code))
   350  }
   351  
   352  // Starts listening.
   353  //
   354  // The socket must be bound and not connected.
   355  func (sock *tcpSocket) listen(backlog int) error {
   356  	code := ppb_tcpsocket_listen(sock.id, int32(backlog), ppNullCompletionCallback)
   357  	return decodeError(Error(code))
   358  }
   359  
   360  // localAddr returns the local address of the socket, if it is bound.
   361  func (sock *tcpSocket) localAddr() net.Addr {
   362  	var local NetAddress
   363  	local.id = ppb_tcpsocket_get_local_address(sock.id)
   364  	if local.id == 0 {
   365  		return nil
   366  	}
   367  	defer local.Release()
   368  
   369  	tcpAddr, err := local.TCPAddr()
   370  	if err != nil {
   371  		return nil
   372  	}
   373  	return tcpAddr
   374  }
   375  
   376  // remoteAddr returns the remote address of the socket, if it is connected.
   377  func (sock *tcpSocket) remoteAddr() net.Addr {
   378  	var local NetAddress
   379  	local.id = ppb_tcpsocket_get_remote_address(sock.id)
   380  	if local.id == 0 {
   381  		return nil
   382  	}
   383  	defer local.Release()
   384  
   385  	tcpAddr, err := local.TCPAddr()
   386  	if err != nil {
   387  		return nil
   388  	}
   389  	return tcpAddr
   390  }
   391  
   392  // TCPConn is a TCP socket.
   393  type TCPConn struct {
   394  	tcpSocket
   395  }
   396  
   397  // DialTCP connects to the remote address raddr on the network net, which must be
   398  // "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used as the local
   399  // address for the connection.
   400  func (inst Instance) DialTCP(net string, laddr, raddr *net.TCPAddr) (conn *TCPConn, err error) {
   401  	conn = &TCPConn{}
   402  	conn.tcpSocket, err = inst.createTCPConn()
   403  	if err != nil {
   404  		return
   405  	}
   406  	if laddr != nil {
   407  		var addr NetAddress
   408  		addr, err = inst.CreateTCPNetAddress(net, laddr)
   409  		if err != nil {
   410  			conn.Release()
   411  			return
   412  		}
   413  		defer addr.Release()
   414  		if err = conn.bind(&addr); err != nil {
   415  			conn.Release()
   416  			return
   417  		}
   418  	}
   419  	var addr NetAddress
   420  	addr, err = inst.CreateTCPNetAddress(net, raddr)
   421  	if err != nil {
   422  		conn.Release()
   423  		return
   424  	}
   425  	defer addr.Release()
   426  	if err = conn.connect(&addr); err != nil {
   427  		conn.Release()
   428  		return
   429  	}
   430  	return
   431  }
   432  
   433  // Close closes the connection.
   434  //
   435  // Any pending callbacks will still run, reporting PP_ERROR_ABORTED if pending
   436  // IO was interrupted. After a call to this method, no output buffer pointers
   437  // passed into previous Read() or Accept() calls will be accessed. It is not
   438  // valid to call Connect() or Listen() again.
   439  func (conn *TCPConn) Close() error {
   440  	ppb_tcpsocket_close(conn.id)
   441  	conn.Release()
   442  	conn.closed = true
   443  	return nil
   444  }
   445  
   446  // localAddr returns the local address of the socket, if it is bound.
   447  func (conn *TCPConn) LocalAddr() net.Addr {
   448  	return conn.localAddr()
   449  }
   450  
   451  // RemoteAddr returns the remote address of the socket, if it is connected.
   452  func (conn *TCPConn) RemoteAddr() net.Addr {
   453  	return conn.remoteAddr()
   454  }
   455  
   456  // Read reads data from the connection.  Deadlines are not supported.
   457  func (conn *TCPConn) Read(buf []byte) (n int, err error) {
   458  	if conn.closed {
   459  		return 0, fmt.Errorf("Reading from closed connection")
   460  	}
   461  	code := ppb_tcpsocket_read(conn.id, &buf[0], int32(len(buf)), ppNullCompletionCallback)
   462  	if code < 0 {
   463  		err = decodeError(Error(code))
   464  		return
   465  	}
   466  	if code == 0 {
   467  		err = io.EOF
   468  		return
   469  	}
   470  	n = int(code)
   471  	return
   472  }
   473  
   474  // Write writes data to the connection.  Deadlines are not supported.
   475  func (conn *TCPConn) Write(buf []byte) (n int, err error) {
   476  	if conn.closed {
   477  		return 0, fmt.Errorf("Writing to closed connection")
   478  	}
   479  	for len(buf) != 0 {
   480  		code := ppb_tcpsocket_write(conn.id, &buf[0], int32(len(buf)), ppNullCompletionCallback)
   481  		if code < 0 {
   482  			err = decodeError(Error(code))
   483  			return
   484  		}
   485  		if code == 0 {
   486  			err = io.EOF
   487  			return
   488  		}
   489  		amount := int(code)
   490  		n += amount
   491  		buf = buf[amount:]
   492  	}
   493  	return
   494  }
   495  
   496  // SetReadBuffer sets the size of the operating system's receive buffer
   497  // associated with the connection.
   498  func (conn *TCPConn) SetReadBuffer(bytes int) error {
   499  	v := VarFromInt(int32(bytes))
   500  	code := ppb_tcpsocket_set_option(conn.id, PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE, v.toPPVar(), ppNullCompletionCallback)
   501  	return decodeError(Error(code))
   502  }
   503  
   504  // SetWriteBuffer sets the size of the operating system's receive buffer
   505  // associated with the connection.
   506  func (conn *TCPConn) SetWriteBuffer(bytes int) error {
   507  	v := VarFromInt(int32(bytes))
   508  	code := ppb_tcpsocket_set_option(conn.id, PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE, v.toPPVar(), ppNullCompletionCallback)
   509  	return decodeError(Error(code))
   510  }
   511  
   512  // SetDeadline sets the read and write deadlines associated
   513  // with the connection.  Not supported.
   514  func (conn *TCPConn) SetDeadline(t time.Time) error {
   515  	return errDeadlineNotSupported
   516  }
   517  
   518  // SetReadDeadline sets the deadline for future Read calls.
   519  // Not supported.
   520  func (conn *TCPConn) SetReadDeadline(t time.Time) error {
   521  	return errDeadlineNotSupported
   522  }
   523  
   524  // SetWriteDeadline sets the deadline for future Write calls.
   525  // Not supported.
   526  func (conn *TCPConn) SetWriteDeadline(t time.Time) error {
   527  	return errDeadlineNotSupported
   528  }
   529  
   530  // TCPListener is a TCP network listener.
   531  type TCPListener struct {
   532  	tcpSocket
   533  }
   534  
   535  // ListenTCP announces on the TCP address laddr and returns a TCP listener. Net
   536  // must be "tcp", "tcp4", or "tcp6". If laddr has a port of 0, ListenTCP will
   537  // choose an available port. The caller can use the Addr method of TCPListener
   538  // to retrieve the chosen address.
   539  func (inst Instance) ListenTCP(net string, laddr *net.TCPAddr) (l *TCPListener, err error) {
   540  	l = &TCPListener{}
   541  	l.tcpSocket, err = inst.createTCPConn()
   542  	if err != nil {
   543  		return
   544  	}
   545  	if laddr != nil {
   546  		var addr NetAddress
   547  		addr, err = inst.CreateTCPNetAddress(net, laddr)
   548  		if err != nil {
   549  			l.Release()
   550  			return
   551  		}
   552  		defer addr.Release()
   553  		if err = l.bind(&addr); err != nil {
   554  			l.Release()
   555  			return
   556  		}
   557  	}
   558  	// TODO(jyh): where does the backlog 5 come from?
   559  	if err = l.listen(5); err != nil {
   560  		l.Release()
   561  		return
   562  	}
   563  	return
   564  }
   565  
   566  // Accept implements the Accept method in the Listener interface; it waits for
   567  // the next call and returns a generic Conn.
   568  func (l *TCPListener) Accept() (net.Conn, error) {
   569  	return l.AcceptTCP()
   570  }
   571  
   572  // AcceptTCP accepts the next incoming call and returns the new connection.
   573  func (l *TCPListener) AcceptTCP() (*TCPConn, error) {
   574  	return l.accept()
   575  }
   576  
   577  // Addr returns the listener's network address, a *TCPAddr.
   578  func (l *TCPListener) Addr() net.Addr {
   579  	return l.localAddr()
   580  }
   581  
   582  // Close stops listening on the TCP address. Already accepted connections are
   583  // not closed.
   584  func (l *TCPListener) Close() error {
   585  	ppb_tcpsocket_close(l.id)
   586  	return nil
   587  }
   588  
   589  // UDPConn is the implementation of the Conn and PacketConn interfaces for UDP network connections.
   590  type UDPConn struct {
   591  	Resource
   592  	inst       Instance
   593  	net        string
   594  	remoteAddr NetAddress
   595  }
   596  
   597  // Release the resources associated with the UDPConn.
   598  func (conn *UDPConn) Release() {
   599  	conn.remoteAddr.Release()
   600  	conn.Resource.Release()
   601  }
   602  
   603  // DialUDP connects to the remote address raddr on the network net, which must
   604  // be "udp", "udp4", or "udp6". If laddr is not nil, it is used as the local
   605  // address for the connection.
   606  func (inst Instance) DialUDP(net string, laddr, raddr *net.UDPAddr) (conn *UDPConn, err error) {
   607  	conn, err = inst.ListenUDP(net, laddr)
   608  	if err != nil {
   609  		return
   610  	}
   611  	conn.remoteAddr, err = inst.CreateUDPNetAddress(net, raddr)
   612  	if err != nil {
   613  		conn.Release()
   614  		return
   615  	}
   616  	return
   617  }
   618  
   619  // ListenUDP listens for incoming UDP packets addressed to the local address
   620  // laddr. Net must be "udp", "udp4", or "udp6". If laddr has a port of 0,
   621  // ListenUDP will choose an available port. The LocalAddr method of the returned
   622  // UDPConn can be used to discover the port. The returned connection's ReadFrom
   623  // and WriteTo methods can be used to receive and send UDP packets with
   624  // per-packet addressing.
   625  func (inst Instance) ListenUDP(net string, laddr *net.UDPAddr) (conn *UDPConn, err error) {
   626  	conn = &UDPConn{}
   627  	conn.inst = inst
   628  	conn.id = ppb_udpsocket_create(inst.id)
   629  	if conn.id == 0 {
   630  		err = errCreateUDPSocketFailed
   631  		return
   632  	}
   633  	if laddr != nil {
   634  		var addr NetAddress
   635  		addr, err = inst.CreateUDPNetAddress(net, laddr)
   636  		if err != nil {
   637  			conn.Release()
   638  			return
   639  		}
   640  		defer addr.Release()
   641  		code := ppb_udpsocket_bind(conn.id, addr.id, ppNullCompletionCallback)
   642  		if code < 0 {
   643  			conn.Release()
   644  			err = decodeError(Error(code))
   645  			return
   646  		}
   647  	}
   648  	conn.net = net
   649  	return
   650  }
   651  
   652  // Close closes the connection.
   653  func (conn *UDPConn) Close() error {
   654  	ppb_udpsocket_close(conn.id)
   655  	conn.Release()
   656  	return nil
   657  }
   658  
   659  // LocalAddr returns the local network address.
   660  func (conn *UDPConn) LocalAddr() net.Addr {
   661  	var na NetAddress
   662  	na.id = ppb_udpsocket_get_bound_address(conn.id)
   663  	if na.id == 0 {
   664  		return nil
   665  	}
   666  	defer na.Release()
   667  	addr, _ := na.UDPAddr()
   668  	return addr
   669  }
   670  
   671  // RemoteAddr returns the remote network address.
   672  func (conn *UDPConn) RemoteAddr() net.Addr {
   673  	addr, _ := conn.remoteAddr.UDPAddr()
   674  	return addr
   675  }
   676  
   677  // Read implements the net.Conn Read method.
   678  func (conn *UDPConn) Read(buf []byte) (n int, err error) {
   679  	n, _, err = conn.ReadFrom(buf)
   680  	return
   681  }
   682  
   683  // ReadFrom implements the net.PacketConn ReadFrom method.
   684  func (conn *UDPConn) ReadFrom(buf []byte) (n int, addr net.Addr, err error) {
   685  	n, addr, err = conn.ReadFromUDP(buf)
   686  	return
   687  }
   688  
   689  // ReadFromUDP reads a UDP packet from conn, copying the payload into buf. It
   690  // returns the number of bytes copied into buf and the return address that was
   691  // on the packet.
   692  func (conn *UDPConn) ReadFromUDP(buf []byte) (n int, addr *net.UDPAddr, err error) {
   693  	var na NetAddress
   694  	defer na.Release()
   695  	code := ppb_udpsocket_recvfrom(conn.id, &buf[0], int32(len(buf)), &na.id, ppNullCompletionCallback)
   696  	if Error(code) == PP_ERROR_ABORTED {
   697  		err = io.EOF
   698  	} else if code < 0 {
   699  		err = decodeError(Error(code))
   700  		return
   701  	}
   702  	n = int(code)
   703  	addr, _ = na.UDPAddr()
   704  	return
   705  }
   706  
   707  // Write implements the Conn Write method.
   708  func (conn *UDPConn) Write(buf []byte) (int, error) {
   709  	return conn.WriteToAddress(buf, conn.remoteAddr)
   710  }
   711  
   712  // WriteTo implements the PacketConn WriteTo method.
   713  func (conn *UDPConn) WriteTo(buf []byte, addr net.Addr) (int, error) {
   714  	na, err := conn.inst.ResolveNetAddress(addr.Network(), addr.String())
   715  	if err != nil {
   716  		return 0, err
   717  	}
   718  	defer na.Release()
   719  	return conn.WriteToAddress(buf, na)
   720  }
   721  
   722  // WriteToUDP writes a UDP packet to addr via conn, copying the payload from buf.
   723  func (conn *UDPConn) WriteToUDP(buf []byte, addr *net.UDPAddr) (int, error) {
   724  	na, err := conn.inst.CreateUDPNetAddress(conn.net, addr)
   725  	if err != nil {
   726  		return 0, err
   727  	}
   728  	defer na.Release()
   729  	return conn.WriteToAddress(buf, na)
   730  }
   731  
   732  // WriteToAddress writes a UDP packet to addr via conn, copying the payload from buf.
   733  func (conn *UDPConn) WriteToAddress(buf []byte, na NetAddress) (n int, err error) {
   734  	code := ppb_udpsocket_sendto(conn.id, &buf[0], int32(len(buf)), na.id, ppNullCompletionCallback)
   735  	if code < 0 {
   736  		err = decodeError(Error(code))
   737  		return
   738  	}
   739  	n = int(code)
   740  	return
   741  }
   742  
   743  // SetDeadline sets the read and write deadlines associated
   744  // with the connection.  Not supported.
   745  func (conn *UDPConn) SetDeadline(t time.Time) error {
   746  	return errDeadlineNotSupported
   747  }
   748  
   749  // SetReadDeadline sets the deadline for future Read calls.
   750  // Not supported.
   751  func (conn *UDPConn) SetReadDeadline(t time.Time) error {
   752  	return errDeadlineNotSupported
   753  }
   754  
   755  // SetWriteDeadline sets the deadline for future Write calls.
   756  // Not supported.
   757  func (conn *UDPConn) SetWriteDeadline(t time.Time) error {
   758  	return errDeadlineNotSupported
   759  }
   760  
   761  // Dial connects to the address on the named network.
   762  //
   763  // Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only), "udp",
   764  // "udp4" (IPv4-only), "udp6" (IPv6-only).
   765  //
   766  // For TCP and UDP networks, addresses have the form host:port. If host is a
   767  // literal IPv6 address or host name, it must be enclosed in square brackets as
   768  // in "[::1]:80" or "[ipv6-host%zone]:80".
   769  func (inst Instance) Dial(network, address string) (net.Conn, error) {
   770  	switch network {
   771  	case "tcp", "tcp4", "tcp6":
   772  		raddr, err := inst.ResolveTCPAddr(network, address)
   773  		if err != nil {
   774  			return nil, err
   775  		}
   776  		return inst.DialTCP(network, nil, raddr)
   777  	case "udp", "udp4", "udp6":
   778  		raddr, err := inst.ResolveUDPAddr(network, address)
   779  		if err != nil {
   780  			return nil, err
   781  		}
   782  		return inst.DialUDP(network, &net.UDPAddr{IP: net.IP{0, 0, 0, 0}}, raddr)
   783  	default:
   784  		return nil, fmt.Errorf("unsupported network: %q", network)
   785  	}
   786  }
   787  
   788  // Listen announces on the local network address laddr. The network net must be
   789  // a stream-oriented network: "tcp", "tcp4", "tcp6". See Dial for the syntax of
   790  // laddr.
   791  func (inst Instance) Listen(network, address string) (net.Listener, error) {
   792  	switch network {
   793  	case "tcp", "tcp4", "tcp6":
   794  		addr, err := inst.ResolveTCPAddr(network, address)
   795  		if err != nil {
   796  			return nil, err
   797  		}
   798  		return inst.ListenTCP(network, addr)
   799  	default:
   800  		return nil, fmt.Errorf("unsupported network: %q", network)
   801  	}
   802  }