Home | History | Annotate | Download | only in 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 // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
      6 
      7 package net
      8 
      9 import (
     10 	"context"
     11 	"syscall"
     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: zoneCache.name(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) sockaddr(family int) (syscall.Sockaddr, error) {
     35 	if a == nil {
     36 		return nil, nil
     37 	}
     38 	return ipToSockaddr(family, a.IP, a.Port, a.Zone)
     39 }
     40 
     41 func (a *UDPAddr) toLocal(net string) sockaddr {
     42 	return &UDPAddr{loopbackIP(net), a.Port, a.Zone}
     43 }
     44 
     45 func (c *UDPConn) readFrom(b []byte) (int, *UDPAddr, error) {
     46 	var addr *UDPAddr
     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 	}
     54 	return n, addr, err
     55 }
     56 
     57 func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
     58 	var sa syscall.Sockaddr
     59 	n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
     60 	switch sa := sa.(type) {
     61 	case *syscall.SockaddrInet4:
     62 		addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
     63 	case *syscall.SockaddrInet6:
     64 		addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneCache.name(int(sa.ZoneId))}
     65 	}
     66 	return
     67 }
     68 
     69 func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) {
     70 	if c.fd.isConnected {
     71 		return 0, ErrWriteToConnected
     72 	}
     73 	if addr == nil {
     74 		return 0, errMissingAddress
     75 	}
     76 	sa, err := addr.sockaddr(c.fd.family)
     77 	if err != nil {
     78 		return 0, err
     79 	}
     80 	return c.fd.writeTo(b, sa)
     81 }
     82 
     83 func (c *UDPConn) writeMsg(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
     84 	if c.fd.isConnected && addr != nil {
     85 		return 0, 0, ErrWriteToConnected
     86 	}
     87 	if !c.fd.isConnected && addr == nil {
     88 		return 0, 0, errMissingAddress
     89 	}
     90 	sa, err := addr.sockaddr(c.fd.family)
     91 	if err != nil {
     92 		return 0, 0, err
     93 	}
     94 	return c.fd.writeMsg(b, oob, sa)
     95 }
     96 
     97 func dialUDP(ctx context.Context, net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
     98 	fd, err := internetSocket(ctx, net, laddr, raddr, syscall.SOCK_DGRAM, 0, "dial")
     99 	if err != nil {
    100 		return nil, err
    101 	}
    102 	return newUDPConn(fd), nil
    103 }
    104 
    105 func listenUDP(ctx context.Context, network string, laddr *UDPAddr) (*UDPConn, error) {
    106 	fd, err := internetSocket(ctx, network, laddr, nil, syscall.SOCK_DGRAM, 0, "listen")
    107 	if err != nil {
    108 		return nil, err
    109 	}
    110 	return newUDPConn(fd), nil
    111 }
    112 
    113 func listenMulticastUDP(ctx context.Context, network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
    114 	fd, err := internetSocket(ctx, network, gaddr, nil, syscall.SOCK_DGRAM, 0, "listen")
    115 	if err != nil {
    116 		return nil, err
    117 	}
    118 	c := newUDPConn(fd)
    119 	if ip4 := gaddr.IP.To4(); ip4 != nil {
    120 		if err := listenIPv4MulticastUDP(c, ifi, ip4); err != nil {
    121 			c.Close()
    122 			return nil, err
    123 		}
    124 	} else {
    125 		if err := listenIPv6MulticastUDP(c, ifi, gaddr.IP); err != nil {
    126 			c.Close()
    127 			return nil, err
    128 		}
    129 	}
    130 	return c, nil
    131 }
    132 
    133 func listenIPv4MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
    134 	if ifi != nil {
    135 		if err := setIPv4MulticastInterface(c.fd, ifi); err != nil {
    136 			return err
    137 		}
    138 	}
    139 	if err := setIPv4MulticastLoopback(c.fd, false); err != nil {
    140 		return err
    141 	}
    142 	if err := joinIPv4Group(c.fd, ifi, ip); err != nil {
    143 		return err
    144 	}
    145 	return nil
    146 }
    147 
    148 func listenIPv6MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
    149 	if ifi != nil {
    150 		if err := setIPv6MulticastInterface(c.fd, ifi); err != nil {
    151 			return err
    152 		}
    153 	}
    154 	if err := setIPv6MulticastLoopback(c.fd, false); err != nil {
    155 		return err
    156 	}
    157 	if err := joinIPv6Group(c.fd, ifi, ip); err != nil {
    158 		return err
    159 	}
    160 	return nil
    161 }
    162