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