Black Lives Matter. Support the Equal Justice Initiative.

Source file src/net/udpsock_posix.go

Documentation: net

     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  //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
     6  // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
     7  
     8  package net
     9  
    10  import (
    11  	"context"
    12  	"syscall"
    13  )
    14  
    15  func sockaddrToUDP(sa syscall.Sockaddr) Addr {
    16  	switch sa := sa.(type) {
    17  	case *syscall.SockaddrInet4:
    18  		return &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
    19  	case *syscall.SockaddrInet6:
    20  		return &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneCache.name(int(sa.ZoneId))}
    21  	}
    22  	return nil
    23  }
    24  
    25  func (a *UDPAddr) family() int {
    26  	if a == nil || len(a.IP) <= IPv4len {
    27  		return syscall.AF_INET
    28  	}
    29  	if a.IP.To4() != nil {
    30  		return syscall.AF_INET
    31  	}
    32  	return syscall.AF_INET6
    33  }
    34  
    35  func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
    36  	if a == nil {
    37  		return nil, nil
    38  	}
    39  	return ipToSockaddr(family, a.IP, a.Port, a.Zone)
    40  }
    41  
    42  func (a *UDPAddr) toLocal(net string) sockaddr {
    43  	return &UDPAddr{loopbackIP(net), a.Port, a.Zone}
    44  }
    45  
    46  func (c *UDPConn) readFrom(b []byte, addr *UDPAddr) (int, *UDPAddr, error) {
    47  	n, sa, err := c.fd.readFrom(b)
    48  	switch sa := sa.(type) {
    49  	case *syscall.SockaddrInet4:
    50  		*addr = UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
    51  	case *syscall.SockaddrInet6:
    52  		*addr = UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneCache.name(int(sa.ZoneId))}
    53  	default:
    54  		// No sockaddr, so don't return UDPAddr.
    55  		addr = nil
    56  	}
    57  	return n, addr, err
    58  }
    59  
    60  func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
    61  	var sa syscall.Sockaddr
    62  	n, oobn, flags, sa, err = c.fd.readMsg(b, oob, 0)
    63  	switch sa := sa.(type) {
    64  	case *syscall.SockaddrInet4:
    65  		addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
    66  	case *syscall.SockaddrInet6:
    67  		addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneCache.name(int(sa.ZoneId))}
    68  	}
    69  	return
    70  }
    71  
    72  func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) {
    73  	if c.fd.isConnected {
    74  		return 0, ErrWriteToConnected
    75  	}
    76  	if addr == nil {
    77  		return 0, errMissingAddress
    78  	}
    79  	sa, err := addr.sockaddr(c.fd.family)
    80  	if err != nil {
    81  		return 0, err
    82  	}
    83  	return c.fd.writeTo(b, sa)
    84  }
    85  
    86  func (c *UDPConn) writeMsg(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
    87  	if c.fd.isConnected && addr != nil {
    88  		return 0, 0, ErrWriteToConnected
    89  	}
    90  	if !c.fd.isConnected && addr == nil {
    91  		return 0, 0, errMissingAddress
    92  	}
    93  	sa, err := addr.sockaddr(c.fd.family)
    94  	if err != nil {
    95  		return 0, 0, err
    96  	}
    97  	return c.fd.writeMsg(b, oob, sa)
    98  }
    99  
   100  func (sd *sysDialer) dialUDP(ctx context.Context, laddr, raddr *UDPAddr) (*UDPConn, error) {
   101  	fd, err := internetSocket(ctx, sd.network, laddr, raddr, syscall.SOCK_DGRAM, 0, "dial", sd.Dialer.Control)
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  	return newUDPConn(fd), nil
   106  }
   107  
   108  func (sl *sysListener) listenUDP(ctx context.Context, laddr *UDPAddr) (*UDPConn, error) {
   109  	fd, err := internetSocket(ctx, sl.network, laddr, nil, syscall.SOCK_DGRAM, 0, "listen", sl.ListenConfig.Control)
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  	return newUDPConn(fd), nil
   114  }
   115  
   116  func (sl *sysListener) listenMulticastUDP(ctx context.Context, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
   117  	fd, err := internetSocket(ctx, sl.network, gaddr, nil, syscall.SOCK_DGRAM, 0, "listen", sl.ListenConfig.Control)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  	c := newUDPConn(fd)
   122  	if ip4 := gaddr.IP.To4(); ip4 != nil {
   123  		if err := listenIPv4MulticastUDP(c, ifi, ip4); err != nil {
   124  			c.Close()
   125  			return nil, err
   126  		}
   127  	} else {
   128  		if err := listenIPv6MulticastUDP(c, ifi, gaddr.IP); err != nil {
   129  			c.Close()
   130  			return nil, err
   131  		}
   132  	}
   133  	return c, nil
   134  }
   135  
   136  func listenIPv4MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
   137  	if ifi != nil {
   138  		if err := setIPv4MulticastInterface(c.fd, ifi); err != nil {
   139  			return err
   140  		}
   141  	}
   142  	if err := setIPv4MulticastLoopback(c.fd, false); err != nil {
   143  		return err
   144  	}
   145  	if err := joinIPv4Group(c.fd, ifi, ip); err != nil {
   146  		return err
   147  	}
   148  	return nil
   149  }
   150  
   151  func listenIPv6MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
   152  	if ifi != nil {
   153  		if err := setIPv6MulticastInterface(c.fd, ifi); err != nil {
   154  			return err
   155  		}
   156  	}
   157  	if err := setIPv6MulticastLoopback(c.fd, false); err != nil {
   158  		return err
   159  	}
   160  	if err := joinIPv6Group(c.fd, ifi, ip); err != nil {
   161  		return err
   162  	}
   163  	return nil
   164  }
   165  

View as plain text