(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(addrSocketAddr) -> 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], dstSocketAddr) {
  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, otherSocketAddr) -> 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  }