blob: 4f298a42f878737bbfc0b6d4c694aeb08cf144fd [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
5// UDP for Plan 9
6
7package net
8
9import (
Russ Coxeb692922011-11-01 22:05:34 -040010 "errors"
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040011 "os"
Mikio Hara03d4c7c2012-02-17 10:59:30 +090012 "syscall"
Mikio Harab58b5ba2012-01-19 12:25:37 +090013 "time"
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040014)
15
16// UDPConn is the implementation of the Conn and PacketConn
17// interfaces for UDP network connections.
18type UDPConn struct {
19 plan9Conn
20}
21
Mikio Hara3d400db2012-01-29 19:11:05 +090022// SetDeadline implements the Conn SetDeadline method.
Mikio Harab58b5ba2012-01-19 12:25:37 +090023func (c *UDPConn) SetDeadline(t time.Time) error {
Mikio Hara03d4c7c2012-02-17 10:59:30 +090024 return syscall.EPLAN9
Mikio Harab58b5ba2012-01-19 12:25:37 +090025}
26
Mikio Hara3d400db2012-01-29 19:11:05 +090027// SetReadDeadline implements the Conn SetReadDeadline method.
Mikio Harab58b5ba2012-01-19 12:25:37 +090028func (c *UDPConn) SetReadDeadline(t time.Time) error {
Mikio Hara03d4c7c2012-02-17 10:59:30 +090029 return syscall.EPLAN9
Mikio Harab58b5ba2012-01-19 12:25:37 +090030}
31
Mikio Hara3d400db2012-01-29 19:11:05 +090032// SetWriteDeadline implements the Conn SetWriteDeadline method.
Mikio Harab58b5ba2012-01-19 12:25:37 +090033func (c *UDPConn) SetWriteDeadline(t time.Time) error {
Mikio Hara03d4c7c2012-02-17 10:59:30 +090034 return syscall.EPLAN9
Mikio Harab58b5ba2012-01-19 12:25:37 +090035}
36
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040037// UDP-specific methods.
38
39// ReadFromUDP reads a UDP packet from c, copying the payload into b.
40// It returns the number of bytes copied into b and the return address
41// that was on the packet.
42//
43// ReadFromUDP can be made to time out and return an error with Timeout() == true
Mikio Harab58b5ba2012-01-19 12:25:37 +090044// after a fixed time limit; see SetDeadline and SetReadDeadline.
Russ Coxeb692922011-11-01 22:05:34 -040045func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040046 if !c.ok() {
Rob Pike56069f02012-02-17 10:04:29 +110047 return 0, nil, syscall.EINVAL
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040048 }
49 if c.data == nil {
50 c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
51 if err != nil {
52 return 0, nil, err
53 }
54 }
55 buf := make([]byte, udpHeaderSize+len(b))
56 m, err := c.data.Read(buf)
57 if err != nil {
58 return
59 }
60 if m < udpHeaderSize {
Russ Coxeb692922011-11-01 22:05:34 -040061 return 0, nil, errors.New("short read reading UDP header")
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040062 }
63 buf = buf[:m]
64
65 h, buf := unmarshalUDPHeader(buf)
66 n = copy(b, buf)
67 return n, &UDPAddr{h.raddr, int(h.rport)}, nil
68}
69
Mikio Hara3d400db2012-01-29 19:11:05 +090070// ReadFrom implements the PacketConn ReadFrom method.
Russ Coxeb692922011-11-01 22:05:34 -040071func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err error) {
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040072 if !c.ok() {
Rob Pike56069f02012-02-17 10:04:29 +110073 return 0, nil, syscall.EINVAL
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040074 }
75 return c.ReadFromUDP(b)
76}
77
78// WriteToUDP writes a UDP packet to addr via c, copying the payload from b.
79//
80// WriteToUDP can be made to time out and return
81// an error with Timeout() == true after a fixed time limit;
Mikio Harab58b5ba2012-01-19 12:25:37 +090082// see SetDeadline and SetWriteDeadline.
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040083// On packet-oriented connections, write timeouts are rare.
Russ Coxeb692922011-11-01 22:05:34 -040084func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err error) {
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040085 if !c.ok() {
Rob Pike56069f02012-02-17 10:04:29 +110086 return 0, syscall.EINVAL
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040087 }
88 if c.data == nil {
89 c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
90 if err != nil {
91 return 0, err
92 }
93 }
94 h := new(udpHeader)
95 h.raddr = addr.IP.To16()
96 h.laddr = c.laddr.(*UDPAddr).IP.To16()
97 h.ifcaddr = IPv6zero // ignored (receive only)
98 h.rport = uint16(addr.Port)
99 h.lport = uint16(c.laddr.(*UDPAddr).Port)
100
101 buf := make([]byte, udpHeaderSize+len(b))
102 i := copy(buf, h.Bytes())
103 copy(buf[i:], b)
104 return c.data.Write(buf)
105}
106
Mikio Hara3d400db2012-01-29 19:11:05 +0900107// WriteTo implements the PacketConn WriteTo method.
Russ Coxeb692922011-11-01 22:05:34 -0400108func (c *UDPConn) WriteTo(b []byte, addr Addr) (n int, err error) {
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400109 if !c.ok() {
Rob Pike56069f02012-02-17 10:04:29 +1100110 return 0, syscall.EINVAL
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400111 }
112 a, ok := addr.(*UDPAddr)
113 if !ok {
Rob Pike56069f02012-02-17 10:04:29 +1100114 return 0, &OpError{"write", c.dir, addr, syscall.EINVAL}
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400115 }
116 return c.WriteToUDP(b, a)
117}
118
119// DialUDP connects to the remote address raddr on the network net,
120// which must be "udp", "udp4", or "udp6". If laddr is not nil, it is used
121// as the local address for the connection.
Russ Coxeb692922011-11-01 22:05:34 -0400122func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err error) {
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400123 switch net {
124 case "udp", "udp4", "udp6":
125 default:
126 return nil, UnknownNetworkError(net)
127 }
128 if raddr == nil {
Mikio Hara77cb8952012-01-24 02:59:43 +0900129 return nil, &OpError{"dial", net, nil, errMissingAddress}
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400130 }
131 c1, err := dialPlan9(net, laddr, raddr)
132 if err != nil {
133 return
134 }
135 return &UDPConn{*c1}, nil
136}
137
138const udpHeaderSize = 16*3 + 2*2
139
140type udpHeader struct {
141 raddr, laddr, ifcaddr IP
142 rport, lport uint16
143}
144
145func (h *udpHeader) Bytes() []byte {
146 b := make([]byte, udpHeaderSize)
147 i := 0
148 i += copy(b[i:i+16], h.raddr)
149 i += copy(b[i:i+16], h.laddr)
150 i += copy(b[i:i+16], h.ifcaddr)
151 b[i], b[i+1], i = byte(h.rport>>8), byte(h.rport), i+2
152 b[i], b[i+1], i = byte(h.lport>>8), byte(h.lport), i+2
153 return b
154}
155
156func unmarshalUDPHeader(b []byte) (*udpHeader, []byte) {
157 h := new(udpHeader)
158 h.raddr, b = IP(b[:16]), b[16:]
159 h.laddr, b = IP(b[:16]), b[16:]
160 h.ifcaddr, b = IP(b[:16]), b[16:]
161 h.rport, b = uint16(b[0])<<8|uint16(b[1]), b[2:]
162 h.lport, b = uint16(b[0])<<8|uint16(b[1]), b[2:]
163 return h, b
164}
165
166// ListenUDP listens for incoming UDP packets addressed to the
167// local address laddr. The returned connection c's ReadFrom
168// and WriteTo methods can be used to receive and send UDP
169// packets with per-packet addressing.
Russ Coxeb692922011-11-01 22:05:34 -0400170func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err error) {
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400171 switch net {
172 case "udp", "udp4", "udp6":
173 default:
174 return nil, UnknownNetworkError(net)
175 }
176 if laddr == nil {
Mikio Hara77cb8952012-01-24 02:59:43 +0900177 return nil, &OpError{"listen", net, nil, errMissingAddress}
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400178 }
179 l, err := listenPlan9(net, laddr)
180 if err != nil {
181 return
182 }
183 _, err = l.ctl.WriteString("headers")
184 if err != nil {
185 return
186 }
187 return &UDPConn{*l.plan9Conn()}, nil
188}
189
Mikio Hara2f63afd2012-02-01 01:53:26 +0900190// ListenMulticastUDP listens for incoming multicast UDP packets
191// addressed to the group address gaddr on ifi, which specifies
192// the interface to join. ListenMulticastUDP uses default
193// multicast interface if ifi is nil.
194func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
Mikio Hara03d4c7c2012-02-17 10:59:30 +0900195 return nil, syscall.EPLAN9
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400196}