(index<- ) ./libstd/rt/io/net/udp.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use option::{Option, Some, None};
12 use result::{Ok, Err};
13 use rt::io::net::ip::SocketAddr;
14 use rt::io::{Reader, Writer};
15 use rt::io::{io_error, read_error, EndOfFile};
16 use rt::rtio::{RtioSocket, RtioUdpSocketObject, RtioUdpSocket, IoFactory, IoFactoryObject};
17 use rt::local::Local;
18
19 pub struct UdpSocket {
20 priv obj: ~RtioUdpSocketObject
21 }
22
23 impl UdpSocket {
24 pub fn bind(addr: SocketAddr) -> Option<UdpSocket> {
25 let socket = unsafe {
26 let factory: *mut IoFactoryObject = Local::unsafe_borrow();
27 (*factory).udp_bind(addr)
28 };
29 match socket {
30 Ok(s) => Some(UdpSocket { obj: s }),
31 Err(ioerr) => {
32 io_error::cond.raise(ioerr);
33 None
34 }
35 }
36 }
37
38 pub fn recvfrom(&mut self, buf: &mut [u8]) -> Option<(uint, SocketAddr)> {
39 match self.obj.recvfrom(buf) {
40 Ok((nread, src)) => Some((nread, src)),
41 Err(ioerr) => {
42 // EOF is indicated by returning None
43 if ioerr.kind != EndOfFile {
44 read_error::cond.raise(ioerr);
45 }
46 None
47 }
48 }
49 }
50
51 pub fn sendto(&mut self, buf: &[u8], dst: SocketAddr) {
52 match self.obj.sendto(buf, dst) {
53 Ok(_) => (),
54 Err(ioerr) => io_error::cond.raise(ioerr),
55 }
56 }
57
58 pub fn connect(self, other: SocketAddr) -> UdpStream {
59 UdpStream { socket: self, connectedTo: other }
60 }
61
62 pub fn socket_name(&mut self) -> Option<SocketAddr> {
63 match self.obj.socket_name() {
64 Ok(sn) => Some(sn),
65 Err(ioerr) => {
66 rtdebug!("failed to get socket name: {:?}", ioerr);
67 io_error::cond.raise(ioerr);
68 None
69 }
70 }
71 }
72 }
73
74 pub struct UdpStream {
75 priv socket: UdpSocket,
76 priv connectedTo: SocketAddr
77 }
78
79 impl UdpStream {
80 pub fn as_socket<T>(&mut self, f: &fn(&mut UdpSocket) -> T) -> T { f(&mut self.socket) }
81
82 pub fn disconnect(self) -> UdpSocket { self.socket }
83 }
84
85 impl Reader for UdpStream {
86 fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
87 let peer = self.connectedTo;
88 do self.as_socket |sock| {
89 match sock.recvfrom(buf) {
90 Some((_nread, src)) if src != peer => Some(0),
91 Some((nread, _src)) => Some(nread),
92 None => None,
93 }
94 }
95 }
96
97 fn eof(&mut self) -> bool { fail2!() }
98 }
99
100 impl Writer for UdpStream {
101 fn write(&mut self, buf: &[u8]) {
102 do self.as_socket |sock| {
103 sock.sendto(buf, self.connectedTo);
104 }
105 }
106
107 fn flush(&mut self) { fail2!() }
108 }
109
110 #[cfg(test)]
111 mod test {
112 use super::*;
113 use rt::test::*;
114 use rt::io::net::ip::{Ipv4Addr, SocketAddr};
115 use rt::io::*;
116 use option::{Some, None};
117 use rt::comm::oneshot;
118 use cell::Cell;
119
120 #[test] #[ignore]
121 fn bind_error() {
122 do run_in_mt_newsched_task {
123 let mut called = false;
124 do io_error::cond.trap(|e| {
125 assert!(e.kind == PermissionDenied);
126 called = true;
127 }).inside {
128 let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 };
129 let socket = UdpSocket::bind(addr);
130 assert!(socket.is_none());
131 }
132 assert!(called);
133 }
134 }
135
136 #[test]
137 fn socket_smoke_test_ip4() {
138 do run_in_mt_newsched_task {
139 let server_ip = next_test_ip4();
140 let client_ip = next_test_ip4();
141 let (port, chan) = oneshot();
142 let port = Cell::new(port);
143 let chan = Cell::new(chan);
144
145 do spawntask {
146 match UdpSocket::bind(server_ip) {
147 Some(ref mut server) => {
148 chan.take().send(());
149 let mut buf = [0];
150 match server.recvfrom(buf) {
151 Some((nread, src)) => {
152 assert_eq!(nread, 1);
153 assert_eq!(buf[0], 99);
154 assert_eq!(src, client_ip);
155 }
156 None => fail2!()
157 }
158 }
159 None => fail2!()
160 }
161 }
162
163 do spawntask {
164 match UdpSocket::bind(client_ip) {
165 Some(ref mut client) => {
166 port.take().recv();
167 client.sendto([99], server_ip)
168 }
169 None => fail2!()
170 }
171 }
172 }
173 }
174
175 #[test]
176 fn socket_smoke_test_ip6() {
177 do run_in_mt_newsched_task {
178 let server_ip = next_test_ip6();
179 let client_ip = next_test_ip6();
180 let (port, chan) = oneshot();
181 let port = Cell::new(port);
182 let chan = Cell::new(chan);
183
184 do spawntask {
185 match UdpSocket::bind(server_ip) {
186 Some(ref mut server) => {
187 chan.take().send(());
188 let mut buf = [0];
189 match server.recvfrom(buf) {
190 Some((nread, src)) => {
191 assert_eq!(nread, 1);
192 assert_eq!(buf[0], 99);
193 assert_eq!(src, client_ip);
194 }
195 None => fail2!()
196 }
197 }
198 None => fail2!()
199 }
200 }
201
202 do spawntask {
203 match UdpSocket::bind(client_ip) {
204 Some(ref mut client) => {
205 port.take().recv();
206 client.sendto([99], server_ip)
207 }
208 None => fail2!()
209 }
210 }
211 }
212 }
213
214 #[test]
215 fn stream_smoke_test_ip4() {
216 do run_in_mt_newsched_task {
217 let server_ip = next_test_ip4();
218 let client_ip = next_test_ip4();
219 let (port, chan) = oneshot();
220 let port = Cell::new(port);
221 let chan = Cell::new(chan);
222
223 do spawntask {
224 match UdpSocket::bind(server_ip) {
225 Some(server) => {
226 let server = ~server;
227 let mut stream = server.connect(client_ip);
228 chan.take().send(());
229 let mut buf = [0];
230 match stream.read(buf) {
231 Some(nread) => {
232 assert_eq!(nread, 1);
233 assert_eq!(buf[0], 99);
234 }
235 None => fail2!()
236 }
237 }
238 None => fail2!()
239 }
240 }
241
242 do spawntask {
243 match UdpSocket::bind(client_ip) {
244 Some(client) => {
245 let client = ~client;
246 let mut stream = client.connect(server_ip);
247 port.take().recv();
248 stream.write([99]);
249 }
250 None => fail2!()
251 }
252 }
253 }
254 }
255
256 #[test]
257 fn stream_smoke_test_ip6() {
258 do run_in_mt_newsched_task {
259 let server_ip = next_test_ip6();
260 let client_ip = next_test_ip6();
261 let (port, chan) = oneshot();
262 let port = Cell::new(port);
263 let chan = Cell::new(chan);
264
265 do spawntask {
266 match UdpSocket::bind(server_ip) {
267 Some(server) => {
268 let server = ~server;
269 let mut stream = server.connect(client_ip);
270 chan.take().send(());
271 let mut buf = [0];
272 match stream.read(buf) {
273 Some(nread) => {
274 assert_eq!(nread, 1);
275 assert_eq!(buf[0], 99);
276 }
277 None => fail2!()
278 }
279 }
280 None => fail2!()
281 }
282 }
283
284 do spawntask {
285 match UdpSocket::bind(client_ip) {
286 Some(client) => {
287 let client = ~client;
288 let mut stream = client.connect(server_ip);
289 port.take().recv();
290 stream.write([99]);
291 }
292 None => fail2!()
293 }
294 }
295 }
296 }
297
298 #[cfg(test)]
299 fn socket_name(addr: SocketAddr) {
300 do run_in_mt_newsched_task {
301 do spawntask {
302 let server = UdpSocket::bind(addr);
303
304 assert!(server.is_some());
305 let mut server = server.unwrap();
306
307 // Make sure socket_name gives
308 // us the socket we binded to.
309 let so_name = server.socket_name();
310 assert!(so_name.is_some());
311 assert_eq!(addr, so_name.unwrap());
312
313 }
314 }
315 }
316
317 #[test]
318 fn socket_name_ip4() {
319 socket_name(next_test_ip4());
320 }
321
322 #[test]
323 fn socket_name_ip6() {
324 socket_name(next_test_ip6());
325 }
326 }