Run Format

Source file src/pkg/net/udpsock_posix.go

     1	// Copyright 2009 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	// +build darwin freebsd linux netbsd openbsd windows
     6	
     7	package net
     8	
     9	import (
    10		"syscall"
    11		"time"
    12	)
    13	
    14	func sockaddrToUDP(sa syscall.Sockaddr) Addr {
    15		switch sa := sa.(type) {
    16		case *syscall.SockaddrInet4:
    17			return &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
    18		case *syscall.SockaddrInet6:
    19			return &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
    20		}
    21		return nil
    22	}
    23	
    24	func (a *UDPAddr) family() int {
    25		if a == nil || len(a.IP) <= IPv4len {
    26			return syscall.AF_INET
    27		}
    28		if a.IP.To4() != nil {
    29			return syscall.AF_INET
    30		}
    31		return syscall.AF_INET6
    32	}
    33	
    34	func (a *UDPAddr) isWildcard() bool {
    35		if a == nil || a.IP == nil {
    36			return true
    37		}
    38		return a.IP.IsUnspecified()
    39	}
    40	
    41	func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
    42		return ipToSockaddr(family, a.IP, a.Port, a.Zone)
    43	}
    44	
    45	func (a *UDPAddr) toAddr() sockaddr {
    46		if a == nil { // nil *UDPAddr
    47			return nil // nil interface
    48		}
    49		return a
    50	}
    51	
    52	// UDPConn is the implementation of the Conn and PacketConn interfaces
    53	// for UDP network connections.
    54	type UDPConn struct {
    55		conn
    56	}
    57	
    58	func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }
    59	
    60	// ReadFromUDP reads a UDP packet from c, copying the payload into b.
    61	// It returns the number of bytes copied into b and the return address
    62	// that was on the packet.
    63	//
    64	// ReadFromUDP can be made to time out and return an error with
    65	// Timeout() == true after a fixed time limit; see SetDeadline and
    66	// SetReadDeadline.
    67	func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
    68		if !c.ok() {
    69			return 0, nil, syscall.EINVAL
    70		}
    71		n, sa, err := c.fd.ReadFrom(b)
    72		switch sa := sa.(type) {
    73		case *syscall.SockaddrInet4:
    74			addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
    75		case *syscall.SockaddrInet6:
    76			addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
    77		}
    78		return
    79	}
    80	
    81	// ReadFrom implements the PacketConn ReadFrom method.
    82	func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
    83		if !c.ok() {
    84			return 0, nil, syscall.EINVAL
    85		}
    86		n, addr, err := c.ReadFromUDP(b)
    87		return n, addr.toAddr(), err
    88	}
    89	
    90	// ReadMsgUDP reads a packet from c, copying the payload into b and
    91	// the associated out-of-band data into oob.  It returns the number
    92	// of bytes copied into b, the number of bytes copied into oob, the
    93	// flags that were set on the packet and the source address of the
    94	// packet.
    95	func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
    96		if !c.ok() {
    97			return 0, 0, 0, nil, syscall.EINVAL
    98		}
    99		var sa syscall.Sockaddr
   100		n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
   101		switch sa := sa.(type) {
   102		case *syscall.SockaddrInet4:
   103			addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
   104		case *syscall.SockaddrInet6:
   105			addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
   106		}
   107		return
   108	}
   109	
   110	// WriteToUDP writes a UDP packet to addr via c, copying the payload
   111	// from b.
   112	//
   113	// WriteToUDP can be made to time out and return an error with
   114	// Timeout() == true after a fixed time limit; see SetDeadline and
   115	// SetWriteDeadline.  On packet-oriented connections, write timeouts
   116	// are rare.
   117	func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
   118		if !c.ok() {
   119			return 0, syscall.EINVAL
   120		}
   121		if c.fd.isConnected {
   122			return 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected}
   123		}
   124		sa, err := addr.sockaddr(c.fd.family)
   125		if err != nil {
   126			return 0, &OpError{"write", c.fd.net, addr, err}
   127		}
   128		return c.fd.WriteTo(b, sa)
   129	}
   130	
   131	// WriteTo implements the PacketConn WriteTo method.
   132	func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
   133		if !c.ok() {
   134			return 0, syscall.EINVAL
   135		}
   136		a, ok := addr.(*UDPAddr)
   137		if !ok {
   138			return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
   139		}
   140		return c.WriteToUDP(b, a)
   141	}
   142	
   143	// WriteMsgUDP writes a packet to addr via c, copying the payload from
   144	// b and the associated out-of-band data from oob.  It returns the
   145	// number of payload and out-of-band bytes written.
   146	func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
   147		if !c.ok() {
   148			return 0, 0, syscall.EINVAL
   149		}
   150		if c.fd.isConnected {
   151			return 0, 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected}
   152		}
   153		sa, err := addr.sockaddr(c.fd.family)
   154		if err != nil {
   155			return 0, 0, &OpError{"write", c.fd.net, addr, err}
   156		}
   157		return c.fd.WriteMsg(b, oob, sa)
   158	}
   159	
   160	// DialUDP connects to the remote address raddr on the network net,
   161	// which must be "udp", "udp4", or "udp6".  If laddr is not nil, it is
   162	// used as the local address for the connection.
   163	func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
   164		return dialUDP(net, laddr, raddr, noDeadline)
   165	}
   166	
   167	func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) {
   168		switch net {
   169		case "udp", "udp4", "udp6":
   170		default:
   171			return nil, UnknownNetworkError(net)
   172		}
   173		if raddr == nil {
   174			return nil, &OpError{"dial", net, nil, errMissingAddress}
   175		}
   176		fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), deadline, syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
   177		if err != nil {
   178			return nil, err
   179		}
   180		return newUDPConn(fd), nil
   181	}
   182	
   183	// ListenUDP listens for incoming UDP packets addressed to the local
   184	// address laddr.  Net must be "udp", "udp4", or "udp6".  If laddr has
   185	// a port of 0, ListenUDP will choose an available port.
   186	// The LocalAddr method of the returned UDPConn can be used to
   187	// discover the port.  The returned connection's ReadFrom and WriteTo
   188	// methods can be used to receive and send UDP packets with per-packet
   189	// addressing.
   190	func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
   191		switch net {
   192		case "udp", "udp4", "udp6":
   193		default:
   194			return nil, UnknownNetworkError(net)
   195		}
   196		if laddr == nil {
   197			laddr = &UDPAddr{}
   198		}
   199		fd, err := internetSocket(net, laddr.toAddr(), nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
   200		if err != nil {
   201			return nil, err
   202		}
   203		return newUDPConn(fd), nil
   204	}
   205	
   206	// ListenMulticastUDP listens for incoming multicast UDP packets
   207	// addressed to the group address gaddr on ifi, which specifies the
   208	// interface to join.  ListenMulticastUDP uses default multicast
   209	// interface if ifi is nil.
   210	func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
   211		switch net {
   212		case "udp", "udp4", "udp6":
   213		default:
   214			return nil, UnknownNetworkError(net)
   215		}
   216		if gaddr == nil || gaddr.IP == nil {
   217			return nil, &OpError{"listen", net, nil, errMissingAddress}
   218		}
   219		fd, err := internetSocket(net, gaddr.toAddr(), nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
   220		if err != nil {
   221			return nil, err
   222		}
   223		c := newUDPConn(fd)
   224		if ip4 := gaddr.IP.To4(); ip4 != nil {
   225			if err := listenIPv4MulticastUDP(c, ifi, ip4); err != nil {
   226				c.Close()
   227				return nil, &OpError{"listen", net, &IPAddr{IP: ip4}, err}
   228			}
   229		} else {
   230			if err := listenIPv6MulticastUDP(c, ifi, gaddr.IP); err != nil {
   231				c.Close()
   232				return nil, &OpError{"listen", net, &IPAddr{IP: gaddr.IP}, err}
   233			}
   234		}
   235		return c, nil
   236	}
   237	
   238	func listenIPv4MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
   239		if ifi != nil {
   240			if err := setIPv4MulticastInterface(c.fd, ifi); err != nil {
   241				return err
   242			}
   243		}
   244		if err := setIPv4MulticastLoopback(c.fd, false); err != nil {
   245			return err
   246		}
   247		if err := joinIPv4Group(c.fd, ifi, ip); err != nil {
   248			return err
   249		}
   250		return nil
   251	}
   252	
   253	func listenIPv6MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
   254		if ifi != nil {
   255			if err := setIPv6MulticastInterface(c.fd, ifi); err != nil {
   256				return err
   257			}
   258		}
   259		if err := setIPv6MulticastLoopback(c.fd, false); err != nil {
   260			return err
   261		}
   262		if err := joinIPv6Group(c.fd, ifi, ip); err != nil {
   263			return err
   264		}
   265		return nil
   266	}

View as plain text