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