src/pkg/net/udpsock_posix.go - The Go Programming Language

Golang

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	// UDP sockets
     8	
     9	package net
    10	
    11	import (
    12		"errors"
    13		"os"
    14		"syscall"
    15		"time"
    16	)
    17	
    18	var ErrWriteToConnected = errors.New("use of WriteTo with pre-connected UDP")
    19	
    20	func sockaddrToUDP(sa syscall.Sockaddr) Addr {
    21		switch sa := sa.(type) {
    22		case *syscall.SockaddrInet4:
    23			return &UDPAddr{sa.Addr[0:], sa.Port}
    24		case *syscall.SockaddrInet6:
    25			return &UDPAddr{sa.Addr[0:], sa.Port}
    26		}
    27		return nil
    28	}
    29	
    30	func (a *UDPAddr) family() int {
    31		if a == nil || len(a.IP) <= IPv4len {
    32			return syscall.AF_INET
    33		}
    34		if a.IP.To4() != nil {
    35			return syscall.AF_INET
    36		}
    37		return syscall.AF_INET6
    38	}
    39	
    40	func (a *UDPAddr) isWildcard() bool {
    41		if a == nil || a.IP == nil {
    42			return true
    43		}
    44		return a.IP.IsUnspecified()
    45	}
    46	
    47	func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
    48		return ipToSockaddr(family, a.IP, a.Port)
    49	}
    50	
    51	func (a *UDPAddr) toAddr() sockaddr {
    52		if a == nil { // nil *UDPAddr
    53			return nil // nil interface
    54		}
    55		return a
    56	}
    57	
    58	// UDPConn is the implementation of the Conn and PacketConn
    59	// interfaces for UDP network connections.
    60	type UDPConn struct {
    61		fd *netFD
    62	}
    63	
    64	func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{fd} }
    65	
    66	func (c *UDPConn) ok() bool { return c != nil && c.fd != nil }
    67	
    68	// Implementation of the Conn interface - see Conn for documentation.
    69	
    70	// Read implements the Conn Read method.
    71	func (c *UDPConn) Read(b []byte) (int, error) {
    72		if !c.ok() {
    73			return 0, syscall.EINVAL
    74		}
    75		return c.fd.Read(b)
    76	}
    77	
    78	// Write implements the Conn Write method.
    79	func (c *UDPConn) Write(b []byte) (int, error) {
    80		if !c.ok() {
    81			return 0, syscall.EINVAL
    82		}
    83		return c.fd.Write(b)
    84	}
    85	
    86	// Close closes the UDP connection.
    87	func (c *UDPConn) Close() error {
    88		if !c.ok() {
    89			return syscall.EINVAL
    90		}
    91		return c.fd.Close()
    92	}
    93	
    94	// LocalAddr returns the local network address.
    95	func (c *UDPConn) LocalAddr() Addr {
    96		if !c.ok() {
    97			return nil
    98		}
    99		return c.fd.laddr
   100	}
   101	
   102	// RemoteAddr returns the remote network address, a *UDPAddr.
   103	func (c *UDPConn) RemoteAddr() Addr {
   104		if !c.ok() {
   105			return nil
   106		}
   107		return c.fd.raddr
   108	}
   109	
   110	// SetDeadline implements the Conn SetDeadline method.
   111	func (c *UDPConn) SetDeadline(t time.Time) error {
   112		if !c.ok() {
   113			return syscall.EINVAL
   114		}
   115		return setDeadline(c.fd, t)
   116	}
   117	
   118	// SetReadDeadline implements the Conn SetReadDeadline method.
   119	func (c *UDPConn) SetReadDeadline(t time.Time) error {
   120		if !c.ok() {
   121			return syscall.EINVAL
   122		}
   123		return setReadDeadline(c.fd, t)
   124	}
   125	
   126	// SetWriteDeadline implements the Conn SetWriteDeadline method.
   127	func (c *UDPConn) SetWriteDeadline(t time.Time) error {
   128		if !c.ok() {
   129			return syscall.EINVAL
   130		}
   131		return setWriteDeadline(c.fd, t)
   132	}
   133	
   134	// SetReadBuffer sets the size of the operating system's
   135	// receive buffer associated with the connection.
   136	func (c *UDPConn) SetReadBuffer(bytes int) error {
   137		if !c.ok() {
   138			return syscall.EINVAL
   139		}
   140		return setReadBuffer(c.fd, bytes)
   141	}
   142	
   143	// SetWriteBuffer sets the size of the operating system's
   144	// transmit buffer associated with the connection.
   145	func (c *UDPConn) SetWriteBuffer(bytes int) error {
   146		if !c.ok() {
   147			return syscall.EINVAL
   148		}
   149		return setWriteBuffer(c.fd, bytes)
   150	}
   151	
   152	// UDP-specific methods.
   153	
   154	// ReadFromUDP reads a UDP packet from c, copying the payload into b.
   155	// It returns the number of bytes copied into b and the return address
   156	// that was on the packet.
   157	//
   158	// ReadFromUDP can be made to time out and return an error with Timeout() == true
   159	// after a fixed time limit; see SetDeadline and SetReadDeadline.
   160	func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
   161		if !c.ok() {
   162			return 0, nil, syscall.EINVAL
   163		}
   164		n, sa, err := c.fd.ReadFrom(b)
   165		switch sa := sa.(type) {
   166		case *syscall.SockaddrInet4:
   167			addr = &UDPAddr{sa.Addr[0:], sa.Port}
   168		case *syscall.SockaddrInet6:
   169			addr = &UDPAddr{sa.Addr[0:], sa.Port}
   170		}
   171		return
   172	}
   173	
   174	// ReadFrom implements the PacketConn ReadFrom method.
   175	func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
   176		if !c.ok() {
   177			return 0, nil, syscall.EINVAL
   178		}
   179		n, uaddr, err := c.ReadFromUDP(b)
   180		return n, uaddr.toAddr(), err
   181	}
   182	
   183	// WriteToUDP writes a UDP packet to addr via c, copying the payload from b.
   184	//
   185	// WriteToUDP can be made to time out and return
   186	// an error with Timeout() == true after a fixed time limit;
   187	// see SetDeadline and SetWriteDeadline.
   188	// On packet-oriented connections, write timeouts are rare.
   189	func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
   190		if !c.ok() {
   191			return 0, syscall.EINVAL
   192		}
   193		if c.fd.isConnected {
   194			return 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected}
   195		}
   196		sa, err := addr.sockaddr(c.fd.family)
   197		if err != nil {
   198			return 0, &OpError{"write", c.fd.net, addr, err}
   199		}
   200		return c.fd.WriteTo(b, sa)
   201	}
   202	
   203	// WriteTo implements the PacketConn WriteTo method.
   204	func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
   205		if !c.ok() {
   206			return 0, syscall.EINVAL
   207		}
   208		a, ok := addr.(*UDPAddr)
   209		if !ok {
   210			return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
   211		}
   212		return c.WriteToUDP(b, a)
   213	}
   214	
   215	// File returns a copy of the underlying os.File, set to blocking mode.
   216	// It is the caller's responsibility to close f when finished.
   217	// Closing c does not affect f, and closing f does not affect c.
   218	func (c *UDPConn) File() (f *os.File, err error) { return c.fd.dup() }
   219	
   220	// DialUDP connects to the remote address raddr on the network net,
   221	// which must be "udp", "udp4", or "udp6".  If laddr is not nil, it is used
   222	// as the local address for the connection.
   223	func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
   224		switch net {
   225		case "udp", "udp4", "udp6":
   226		default:
   227			return nil, UnknownNetworkError(net)
   228		}
   229		if raddr == nil {
   230			return nil, &OpError{"dial", net, nil, errMissingAddress}
   231		}
   232		fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
   233		if err != nil {
   234			return nil, err
   235		}
   236		return newUDPConn(fd), nil
   237	}
   238	
   239	// ListenUDP listens for incoming UDP packets addressed to the
   240	// local address laddr.  The returned connection c's ReadFrom
   241	// and WriteTo methods can be used to receive and send UDP
   242	// packets with per-packet addressing.
   243	func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
   244		switch net {
   245		case "udp", "udp4", "udp6":
   246		default:
   247			return nil, UnknownNetworkError(net)
   248		}
   249		if laddr == nil {
   250			return nil, &OpError{"listen", net, nil, errMissingAddress}
   251		}
   252		fd, err := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
   253		if err != nil {
   254			return nil, err
   255		}
   256		return newUDPConn(fd), nil
   257	}
   258	
   259	// ListenMulticastUDP listens for incoming multicast UDP packets
   260	// addressed to the group address gaddr on ifi, which specifies
   261	// the interface to join.  ListenMulticastUDP uses default
   262	// multicast interface if ifi is nil.
   263	func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
   264		switch net {
   265		case "udp", "udp4", "udp6":
   266		default:
   267			return nil, UnknownNetworkError(net)
   268		}
   269		if gaddr == nil || gaddr.IP == nil {
   270			return nil, &OpError{"listenmulticast", net, nil, errMissingAddress}
   271		}
   272		fd, err := internetSocket(net, gaddr.toAddr(), nil, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
   273		if err != nil {
   274			return nil, err
   275		}
   276		c := newUDPConn(fd)
   277		ip4 := gaddr.IP.To4()
   278		if ip4 != nil {
   279			err := listenIPv4MulticastUDP(c, ifi, ip4)
   280			if err != nil {
   281				c.Close()
   282				return nil, err
   283			}
   284		} else {
   285			err := listenIPv6MulticastUDP(c, ifi, gaddr.IP)
   286			if err != nil {
   287				c.Close()
   288				return nil, err
   289			}
   290		}
   291		return c, nil
   292	}
   293	
   294	func listenIPv4MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
   295		if ifi != nil {
   296			err := setIPv4MulticastInterface(c.fd, ifi)
   297			if err != nil {
   298				return err
   299			}
   300		}
   301		err := setIPv4MulticastLoopback(c.fd, false)
   302		if err != nil {
   303			return err
   304		}
   305		err = joinIPv4GroupUDP(c, ifi, ip)
   306		if err != nil {
   307			return err
   308		}
   309		return nil
   310	}
   311	
   312	func listenIPv6MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
   313		if ifi != nil {
   314			err := setIPv6MulticastInterface(c.fd, ifi)
   315			if err != nil {
   316				return err
   317			}
   318		}
   319		err := setIPv6MulticastLoopback(c.fd, false)
   320		if err != nil {
   321			return err
   322		}
   323		err = joinIPv6GroupUDP(c, ifi, ip)
   324		if err != nil {
   325			return err
   326		}
   327		return nil
   328	}
   329	
   330	func joinIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
   331		err := joinIPv4Group(c.fd, ifi, ip)
   332		if err != nil {
   333			return &OpError{"joinipv4group", c.fd.net, &IPAddr{ip}, err}
   334		}
   335		return nil
   336	}
   337	
   338	func leaveIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
   339		err := leaveIPv4Group(c.fd, ifi, ip)
   340		if err != nil {
   341			return &OpError{"leaveipv4group", c.fd.net, &IPAddr{ip}, err}
   342		}
   343		return nil
   344	}
   345	
   346	func joinIPv6GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
   347		err := joinIPv6Group(c.fd, ifi, ip)
   348		if err != nil {
   349			return &OpError{"joinipv6group", c.fd.net, &IPAddr{ip}, err}
   350		}
   351		return nil
   352	}
   353	
   354	func leaveIPv6GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
   355		err := leaveIPv6Group(c.fd, ifi, ip)
   356		if err != nil {
   357			return &OpError{"leaveipv6group", c.fd.net, &IPAddr{ip}, err}
   358		}
   359		return nil
   360	}