github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/src/net/udpsock_plan9.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 package net 6 7 import ( 8 "errors" 9 "os" 10 "syscall" 11 "time" 12 ) 13 14 // UDPConn is the implementation of the Conn and PacketConn interfaces 15 // for UDP network connections. 16 type UDPConn struct { 17 conn 18 } 19 20 func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} } 21 22 // ReadFromUDP reads a UDP packet from c, copying the payload into b. 23 // It returns the number of bytes copied into b and the return address 24 // that was on the packet. 25 // 26 // ReadFromUDP can be made to time out and return an error with 27 // Timeout() == true after a fixed time limit; see SetDeadline and 28 // SetReadDeadline. 29 func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) { 30 if !c.ok() || c.fd.data == nil { 31 return 0, nil, syscall.EINVAL 32 } 33 buf := make([]byte, udpHeaderSize+len(b)) 34 m, err := c.fd.data.Read(buf) 35 if err != nil { 36 return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 37 } 38 if m < udpHeaderSize { 39 return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: errors.New("short read reading UDP header")} 40 } 41 buf = buf[:m] 42 43 h, buf := unmarshalUDPHeader(buf) 44 n = copy(b, buf) 45 return n, &UDPAddr{IP: h.raddr, Port: int(h.rport)}, nil 46 } 47 48 // ReadFrom implements the PacketConn ReadFrom method. 49 func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) { 50 if !c.ok() { 51 return 0, nil, syscall.EINVAL 52 } 53 return c.ReadFromUDP(b) 54 } 55 56 // ReadMsgUDP reads a packet from c, copying the payload into b and 57 // the associated out-of-band data into oob. It returns the number 58 // of bytes copied into b, the number of bytes copied into oob, the 59 // flags that were set on the packet and the source address of the 60 // packet. 61 func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) { 62 return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9} 63 } 64 65 // WriteToUDP writes a UDP packet to addr via c, copying the payload 66 // from b. 67 // 68 // WriteToUDP can be made to time out and return an error with 69 // Timeout() == true after a fixed time limit; see SetDeadline and 70 // SetWriteDeadline. On packet-oriented connections, write timeouts 71 // are rare. 72 func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) { 73 if !c.ok() || c.fd.data == nil { 74 return 0, syscall.EINVAL 75 } 76 if addr == nil { 77 return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress} 78 } 79 h := new(udpHeader) 80 h.raddr = addr.IP.To16() 81 h.laddr = c.fd.laddr.(*UDPAddr).IP.To16() 82 h.ifcaddr = IPv6zero // ignored (receive only) 83 h.rport = uint16(addr.Port) 84 h.lport = uint16(c.fd.laddr.(*UDPAddr).Port) 85 86 buf := make([]byte, udpHeaderSize+len(b)) 87 i := copy(buf, h.Bytes()) 88 copy(buf[i:], b) 89 if _, err := c.fd.data.Write(buf); err != nil { 90 return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} 91 } 92 return len(b), nil 93 } 94 95 // WriteTo implements the PacketConn WriteTo method. 96 func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) { 97 if !c.ok() { 98 return 0, syscall.EINVAL 99 } 100 a, ok := addr.(*UDPAddr) 101 if !ok { 102 return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL} 103 } 104 return c.WriteToUDP(b, a) 105 } 106 107 // WriteMsgUDP writes a packet to addr via c if c isn't connected, or 108 // to c's remote destination address if c is connected (in which case 109 // addr must be nil). The payload is copied from b and the associated 110 // out-of-band data is copied from oob. It returns the number of 111 // payload and out-of-band bytes written. 112 func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) { 113 return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9} 114 } 115 116 // DialUDP connects to the remote address raddr on the network net, 117 // which must be "udp", "udp4", or "udp6". If laddr is not nil, it is 118 // used as the local address for the connection. 119 func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) { 120 return dialUDP(net, laddr, raddr, noDeadline) 121 } 122 123 func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) { 124 if !deadline.IsZero() { 125 panic("net.dialUDP: deadline not implemented on Plan 9") 126 } 127 switch net { 128 case "udp", "udp4", "udp6": 129 default: 130 return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)} 131 } 132 if raddr == nil { 133 return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress} 134 } 135 fd, err := dialPlan9(net, laddr, raddr) 136 if err != nil { 137 return nil, err 138 } 139 return newUDPConn(fd), nil 140 } 141 142 const udpHeaderSize = 16*3 + 2*2 143 144 type udpHeader struct { 145 raddr, laddr, ifcaddr IP 146 rport, lport uint16 147 } 148 149 func (h *udpHeader) Bytes() []byte { 150 b := make([]byte, udpHeaderSize) 151 i := 0 152 i += copy(b[i:i+16], h.raddr) 153 i += copy(b[i:i+16], h.laddr) 154 i += copy(b[i:i+16], h.ifcaddr) 155 b[i], b[i+1], i = byte(h.rport>>8), byte(h.rport), i+2 156 b[i], b[i+1], i = byte(h.lport>>8), byte(h.lport), i+2 157 return b 158 } 159 160 func unmarshalUDPHeader(b []byte) (*udpHeader, []byte) { 161 h := new(udpHeader) 162 h.raddr, b = IP(b[:16]), b[16:] 163 h.laddr, b = IP(b[:16]), b[16:] 164 h.ifcaddr, b = IP(b[:16]), b[16:] 165 h.rport, b = uint16(b[0])<<8|uint16(b[1]), b[2:] 166 h.lport, b = uint16(b[0])<<8|uint16(b[1]), b[2:] 167 return h, b 168 } 169 170 // ListenUDP listens for incoming UDP packets addressed to the local 171 // address laddr. Net must be "udp", "udp4", or "udp6". If laddr has 172 // a port of 0, ListenUDP will choose an available port. 173 // The LocalAddr method of the returned UDPConn can be used to 174 // discover the port. The returned connection's ReadFrom and WriteTo 175 // methods can be used to receive and send UDP packets with per-packet 176 // addressing. 177 func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) { 178 switch net { 179 case "udp", "udp4", "udp6": 180 default: 181 return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)} 182 } 183 if laddr == nil { 184 laddr = &UDPAddr{} 185 } 186 l, err := listenPlan9(net, laddr) 187 if err != nil { 188 return nil, err 189 } 190 _, err = l.ctl.WriteString("headers") 191 if err != nil { 192 return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err} 193 } 194 l.data, err = os.OpenFile(l.dir+"/data", os.O_RDWR, 0) 195 if err != nil { 196 return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err} 197 } 198 fd, err := l.netFD() 199 return newUDPConn(fd), err 200 } 201 202 // ListenMulticastUDP listens for incoming multicast UDP packets 203 // addressed to the group address gaddr on the interface ifi. 204 // Network must be "udp", "udp4" or "udp6". 205 // ListenMulticastUDP uses the system-assigned multicast interface 206 // when ifi is nil, although this is not recommended because the 207 // assignment depends on platforms and sometimes it might require 208 // routing configuration. 209 // 210 // ListenMulticastUDP is just for convenience of simple, small 211 // applications. There are golang.org/x/net/ipv4 and 212 // golang.org/x/net/ipv6 packages for general purpose uses. 213 func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) { 214 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: syscall.EPLAN9} 215 }