Skip to content

Commit 68bf86e

Browse files
committed
Initial work towards rust issue #14926
1 parent ad7508e commit 68bf86e

File tree

3 files changed

+107
-0
lines changed

3 files changed

+107
-0
lines changed

src/libnative/io/net.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,13 @@ impl rtio::RtioUdpSocket for UdpSocket {
727727
write_deadline: 0,
728728
} as Box<rtio::RtioUdpSocket + Send>
729729
}
730+
731+
fn close_write(&mut self) -> IoResult<()> {
732+
super::mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_WR) })
733+
}
734+
fn close_read(&mut self) -> IoResult<()> {
735+
super::mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_RD) })
736+
}
730737

731738
fn set_timeout(&mut self, timeout: Option<u64>) {
732739
let deadline = timeout.map(|a| ::io::timer::now() + a).unwrap_or(0);

src/librustrt/rtio.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,8 @@ pub trait RtioUdpSocket : RtioSocket {
285285
fn ignore_broadcasts(&mut self) -> IoResult<()>;
286286

287287
fn clone(&self) -> Box<RtioUdpSocket + Send>;
288+
fn close_write(&mut self) -> IoResult<()>;
289+
fn close_read(&mut self) -> IoResult<()>;
288290
fn set_timeout(&mut self, timeout_ms: Option<u64>);
289291
fn set_read_timeout(&mut self, timeout_ms: Option<u64>);
290292
fn set_write_timeout(&mut self, timeout_ms: Option<u64>);

src/libstd/io/net/udp.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,51 @@ impl UdpSocket {
104104
}
105105
}
106106

107+
/// Closes the reading half of this socket.
108+
///
109+
/// This method will close the reading portion of this socket, causing
110+
/// all pending and future reads to immediately return with an error.
111+
///
112+
/// # Example
113+
///
114+
/// ```no_run
115+
/// # #![allow(unused_must_use)]
116+
/// use std::io::timer;
117+
/// use std::io::net::udp::UdpSocket;
118+
///
119+
/// let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 };
120+
/// let mut sock = UdpSocket::bind(addr).unwrap();
121+
/// let sock2 = sock.clone();
122+
///
123+
/// spawn(proc() {
124+
/// // close the reading half of the socket after 1 second
125+
/// timer::sleep(1000);
126+
/// let mut sock = sock2;
127+
/// sock.close_read();
128+
/// });
129+
///
130+
/// // wait for some data, will get canceled after one second
131+
/// let mut buf = [0];
132+
/// let _ = sock.recvfrom(buf);
133+
/// ```
134+
///
135+
/// Note that this method affects all cloned handles associated with this
136+
/// socket, not just this one handle.
137+
pub fn close_read(&mut self) -> IoResult<()> {
138+
self.obj.close_read().map_err(IoError::from_rtio_error)
139+
}
140+
141+
/// Closes the writing half of this socket.
142+
///
143+
/// This method will close the writing portion of this socket, causing
144+
/// all future writes to immediately return with an error.
145+
///
146+
/// Note that this method affects all cloned handles associated with this
147+
/// socket, not just this one handle.
148+
pub fn close_write(&mut self) -> IoResult<()> {
149+
self.obj.close_write().map_err(IoError::from_rtio_error)
150+
}
151+
107152
/// Returns the socket address that this socket was created from.
108153
pub fn socket_name(&mut self) -> IoResult<SocketAddr> {
109154
match self.obj.socket_name() {
@@ -526,6 +571,59 @@ mod test {
526571
serv_rx.recv();
527572
})
528573

574+
575+
iotest!(fn close_readwrite_smoke() {
576+
let addr = next_test_ip4();
577+
let addr2 = next_test_ip4();
578+
let server = UdpSocket::bind(addr).unwrap();
579+
let client1 = UdpSocket::bind(addr2).unwrap();
580+
let client2 = client1.clone();
581+
let mut b = [0];
582+
583+
// closing should prevent reads/writes
584+
client1.close_write().unwrap();
585+
assert!(client1.sendto(addr, [0]).is_err());
586+
client1.close_read().unwrap();
587+
assert!(client1.recvfrom(b).is_err());
588+
589+
// closing should affect previous handles
590+
assert!(client2.write(addr, [0]).is_err());
591+
assert!(client2.recvfrom(b).is_err());
592+
593+
// closing should affect new handles
594+
let mut client3 = s.clone();
595+
assert!(client3.sendto(addr, [0]).is_err());
596+
assert!(client3.recvfrom(b).is_err());
597+
598+
// make sure these don't die
599+
let _ = client2.close_read();
600+
let _ = client2.close_write();
601+
let _ = client3.close_read();
602+
let _ = client3.close_write();
603+
})
604+
605+
iotest!(fn close_read_wakes_up() {
606+
let addr = next_test_ip4();
607+
let addr2 = next_test_ip4();
608+
let server = UdpSocket::bind(addr).unwrap();
609+
let client1 = UdpSocket::bind(addr2).unwrap();
610+
let client2 = client1.clone();
611+
let mut b = [0];
612+
613+
let (tx, rx) = channel();
614+
spawn(proc() {
615+
let mut client2 = client2;
616+
assert!(client2.recvfrom([0]).is_err());
617+
tx.send(());
618+
});
619+
620+
// this should wake up the child task
621+
client1.close_read().unwrap();
622+
623+
// this test will never finish if the child doesn't wake up
624+
rx.recv();
625+
})
626+
529627
iotest!(fn recvfrom_timeout() {
530628
let addr1 = next_test_ip4();
531629
let addr2 = next_test_ip4();

0 commit comments

Comments
 (0)