blob: 12a348399057f0c5be27cd51048a11d1ae738f2d [file] [log] [blame]
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -04001// 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
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -04005package net
6
7import (
Russ Coxeb692922011-11-01 22:05:34 -04008 "errors"
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -04009 "os"
Mikio Hara03d4c7c2012-02-17 10:59:30 +090010 "syscall"
Brad Fitzpatrickef6806f2012-11-08 10:35:16 -060011 "time"
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040012)
13
Mikio Harae2c453e2013-03-31 16:47:54 +090014// UDPConn is the implementation of the Conn and PacketConn interfaces
15// for UDP network connections.
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040016type UDPConn struct {
Mikio Hara306afc72012-11-13 16:18:37 +090017 conn
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040018}
19
Mikio Harae2c453e2013-03-31 16:47:54 +090020func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }
Akshat Kumar66b69a12013-02-19 17:11:17 -080021
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040022// 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//
Mikio Harad6665bc2012-09-26 16:11:49 +090026// 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.
Russ Coxeb692922011-11-01 22:05:34 -040029func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
Akshat Kumar66b69a12013-02-19 17:11:17 -080030 if !c.ok() || c.fd.data == nil {
Rob Pike56069f02012-02-17 10:04:29 +110031 return 0, nil, syscall.EINVAL
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040032 }
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040033 buf := make([]byte, udpHeaderSize+len(b))
Mikio Hara306afc72012-11-13 16:18:37 +090034 m, err := c.fd.data.Read(buf)
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040035 if err != nil {
36 return
37 }
38 if m < udpHeaderSize {
Russ Coxeb692922011-11-01 22:05:34 -040039 return 0, nil, errors.New("short read reading UDP header")
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040040 }
41 buf = buf[:m]
42
43 h, buf := unmarshalUDPHeader(buf)
44 n = copy(b, buf)
Mikio Harae8cf49f2012-11-27 00:45:42 +090045 return n, &UDPAddr{IP: h.raddr, Port: int(h.rport)}, nil
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040046}
47
Mikio Hara3d400db2012-01-29 19:11:05 +090048// ReadFrom implements the PacketConn ReadFrom method.
Anthony Martin253ed022012-11-30 11:41:50 -080049func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040050 if !c.ok() {
Rob Pike56069f02012-02-17 10:04:29 +110051 return 0, nil, syscall.EINVAL
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040052 }
53 return c.ReadFromUDP(b)
54}
55
Mikio Harad6665bc2012-09-26 16:11:49 +090056// ReadMsgUDP reads a packet from c, copying the payload into b and
Robert Griesemer0ad265d2013-03-20 16:32:37 -070057// the associated out-of-band data into oob. It returns the number
Mikio Harad6665bc2012-09-26 16:11:49 +090058// 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.
61func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
62 return 0, 0, 0, nil, syscall.EPLAN9
63}
64
65// WriteToUDP writes a UDP packet to addr via c, copying the payload
66// from b.
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040067//
Mikio Harad6665bc2012-09-26 16:11:49 +090068// 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.
Anthony Martin253ed022012-11-30 11:41:50 -080072func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
Akshat Kumar66b69a12013-02-19 17:11:17 -080073 if !c.ok() || c.fd.data == nil {
Rob Pike56069f02012-02-17 10:04:29 +110074 return 0, syscall.EINVAL
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040075 }
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040076 h := new(udpHeader)
77 h.raddr = addr.IP.To16()
Mikio Hara306afc72012-11-13 16:18:37 +090078 h.laddr = c.fd.laddr.(*UDPAddr).IP.To16()
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040079 h.ifcaddr = IPv6zero // ignored (receive only)
80 h.rport = uint16(addr.Port)
Mikio Hara306afc72012-11-13 16:18:37 +090081 h.lport = uint16(c.fd.laddr.(*UDPAddr).Port)
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040082
83 buf := make([]byte, udpHeaderSize+len(b))
84 i := copy(buf, h.Bytes())
85 copy(buf[i:], b)
Mikio Hara306afc72012-11-13 16:18:37 +090086 return c.fd.data.Write(buf)
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040087}
88
Mikio Hara3d400db2012-01-29 19:11:05 +090089// WriteTo implements the PacketConn WriteTo method.
Anthony Martin253ed022012-11-30 11:41:50 -080090func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040091 if !c.ok() {
Rob Pike56069f02012-02-17 10:04:29 +110092 return 0, syscall.EINVAL
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040093 }
94 a, ok := addr.(*UDPAddr)
95 if !ok {
Mikio Hara306afc72012-11-13 16:18:37 +090096 return 0, &OpError{"write", c.fd.dir, addr, syscall.EINVAL}
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040097 }
98 return c.WriteToUDP(b, a)
99}
100
Mikio Harad6665bc2012-09-26 16:11:49 +0900101// WriteMsgUDP writes a packet to addr via c, copying the payload from
102// b and the associated out-of-band data from oob. It returns the
103// number of payload and out-of-band bytes written.
104func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
105 return 0, 0, syscall.EPLAN9
106}
107
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400108// DialUDP connects to the remote address raddr on the network net,
Mikio Harad6665bc2012-09-26 16:11:49 +0900109// which must be "udp", "udp4", or "udp6". If laddr is not nil, it is
110// used as the local address for the connection.
Anthony Martin253ed022012-11-30 11:41:50 -0800111func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
Brad Fitzpatrickef6806f2012-11-08 10:35:16 -0600112 return dialUDP(net, laddr, raddr, noDeadline)
113}
114
Mikio Hara306afc72012-11-13 16:18:37 +0900115func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) {
Brad Fitzpatrickef6806f2012-11-08 10:35:16 -0600116 if !deadline.IsZero() {
117 panic("net.dialUDP: deadline not implemented on Plan 9")
118 }
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400119 switch net {
120 case "udp", "udp4", "udp6":
121 default:
122 return nil, UnknownNetworkError(net)
123 }
124 if raddr == nil {
Mikio Hara77cb8952012-01-24 02:59:43 +0900125 return nil, &OpError{"dial", net, nil, errMissingAddress}
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400126 }
Mikio Hara306afc72012-11-13 16:18:37 +0900127 fd, err := dialPlan9(net, laddr, raddr)
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400128 if err != nil {
Mikio Hara306afc72012-11-13 16:18:37 +0900129 return nil, err
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400130 }
Akshat Kumar66b69a12013-02-19 17:11:17 -0800131 return newUDPConn(fd), nil
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400132}
133
134const udpHeaderSize = 16*3 + 2*2
135
136type udpHeader struct {
137 raddr, laddr, ifcaddr IP
138 rport, lport uint16
139}
140
141func (h *udpHeader) Bytes() []byte {
142 b := make([]byte, udpHeaderSize)
143 i := 0
144 i += copy(b[i:i+16], h.raddr)
145 i += copy(b[i:i+16], h.laddr)
146 i += copy(b[i:i+16], h.ifcaddr)
147 b[i], b[i+1], i = byte(h.rport>>8), byte(h.rport), i+2
148 b[i], b[i+1], i = byte(h.lport>>8), byte(h.lport), i+2
149 return b
150}
151
152func unmarshalUDPHeader(b []byte) (*udpHeader, []byte) {
153 h := new(udpHeader)
154 h.raddr, b = IP(b[:16]), b[16:]
155 h.laddr, b = IP(b[:16]), b[16:]
156 h.ifcaddr, b = IP(b[:16]), b[16:]
157 h.rport, b = uint16(b[0])<<8|uint16(b[1]), b[2:]
158 h.lport, b = uint16(b[0])<<8|uint16(b[1]), b[2:]
159 return h, b
160}
161
Mikio Harad6665bc2012-09-26 16:11:49 +0900162// ListenUDP listens for incoming UDP packets addressed to the local
Mikio Hara245dc622013-03-29 15:06:43 +0900163// address laddr. Net must be "udp", "udp4", or "udp6". If laddr has
164// a port of 0, ListenUDP will choose an available port.
165// The LocalAddr method of the returned UDPConn can be used to
166// discover the port. The returned connection's ReadFrom and WriteTo
Mikio Harad6665bc2012-09-26 16:11:49 +0900167// methods can be used to receive and send UDP packets with per-packet
168// addressing.
Mikio Hara306afc72012-11-13 16:18:37 +0900169func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400170 switch net {
171 case "udp", "udp4", "udp6":
172 default:
173 return nil, UnknownNetworkError(net)
174 }
175 if laddr == nil {
Mikio Hara677c6e62012-11-13 12:56:28 +0900176 laddr = &UDPAddr{}
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400177 }
178 l, err := listenPlan9(net, laddr)
179 if err != nil {
Mikio Hara306afc72012-11-13 16:18:37 +0900180 return nil, err
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400181 }
182 _, err = l.ctl.WriteString("headers")
183 if err != nil {
Mikio Hara306afc72012-11-13 16:18:37 +0900184 return nil, err
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400185 }
Akshat Kumar66b69a12013-02-19 17:11:17 -0800186 l.data, err = os.OpenFile(l.dir+"/data", os.O_RDWR, 0)
187 if err != nil {
188 return nil, err
189 }
190 return newUDPConn(l.netFD()), nil
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400191}
192
Mikio Hara2f63afd2012-02-01 01:53:26 +0900193// ListenMulticastUDP listens for incoming multicast UDP packets
Mikio Harad6665bc2012-09-26 16:11:49 +0900194// addressed to the group address gaddr on ifi, which specifies the
195// interface to join. ListenMulticastUDP uses default multicast
196// interface if ifi is nil.
Mikio Hara2f63afd2012-02-01 01:53:26 +0900197func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
Mikio Hara03d4c7c2012-02-17 10:59:30 +0900198 return nil, syscall.EPLAN9
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400199}