github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/net/udpsock_posix.go (about) 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 }