Skip to content

Commit b2fbd34

Browse files
committed
core::rt: Begin implementing TcpStream
This ended up touching a lot of code related to error handling.
1 parent 0b4d4ed commit b2fbd34

File tree

11 files changed

+282
-57
lines changed

11 files changed

+282
-57
lines changed

src/libcore/macros.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ macro_rules! rtdebug (
3030
($( $arg:expr),+) => ( $(let _ = $arg)*; )
3131
)
3232

33+
macro_rules! rtassert (
34+
( $arg:expr ) => ( {
35+
if !$arg {
36+
abort!("assertion failed: %s", stringify!($arg));
37+
}
38+
} )
39+
)
40+
3341
macro_rules! abort(
3442
($( $msg:expr),+) => ( {
3543
rtdebug!($($msg),+);

src/libcore/rt/io/mod.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,9 @@ pub use self::stdio::println;
252252

253253
pub use self::file::FileStream;
254254
pub use self::net::ip::IpAddr;
255+
#[cfg(not(stage0))]
255256
pub use self::net::tcp::TcpListener;
257+
#[cfg(not(stage0))]
256258
pub use self::net::tcp::TcpStream;
257259
pub use self::net::udp::UdpStream;
258260

@@ -266,6 +268,7 @@ pub mod file;
266268

267269
/// Synchronous, non-blocking network I/O.
268270
pub mod net {
271+
#[cfg(not(stage0))]
269272
pub mod tcp;
270273
pub mod udp;
271274
pub mod ip;
@@ -326,12 +329,14 @@ pub struct IoError {
326329

327330
#[deriving(Eq)]
328331
pub enum IoErrorKind {
332+
PreviousIoError,
333+
OtherIoError,
334+
EndOfFile,
329335
FileNotFound,
330-
FilePermission,
336+
PermissionDenied,
331337
ConnectionFailed,
332338
Closed,
333-
OtherIoError,
334-
PreviousIoError
339+
ConnectionRefused,
335340
}
336341

337342
// XXX: Can't put doc comments on macros

src/libcore/rt/io/net/tcp.rs

Lines changed: 140 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,63 +8,179 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use prelude::*;
12-
use super::super::*;
13-
use super::ip::IpAddr;
11+
use option::{Option, Some, None};
12+
use result::{Result, Ok, Err};
13+
use ops::Drop;
14+
use rt::sched::local_sched::unsafe_borrow_io;
15+
use rt::io::net::ip::IpAddr;
16+
use rt::io::{Reader, Writer, Listener};
17+
use rt::io::io_error;
18+
use rt::rtio;
19+
use rt::rtio::{IoFactory, TcpListener, Stream};
1420

15-
pub struct TcpStream;
21+
pub struct TcpStream {
22+
rtstream: ~rtio::StreamObject
23+
}
1624

1725
impl TcpStream {
18-
pub fn connect(_addr: IpAddr) -> Option<TcpStream> {
19-
fail!()
26+
fn new(s: ~rtio::StreamObject) -> TcpStream {
27+
TcpStream {
28+
rtstream: s
29+
}
30+
}
31+
32+
pub fn connect(addr: IpAddr) -> Option<TcpStream> {
33+
let stream = unsafe {
34+
rtdebug!("borrowing io to connect");
35+
let io = unsafe_borrow_io();
36+
rtdebug!("about to connect");
37+
io.connect(addr)
38+
};
39+
40+
match stream {
41+
Ok(s) => {
42+
Some(TcpStream::new(s))
43+
}
44+
Err(ioerr) => {
45+
rtdebug!("failed to connect: %?", ioerr);
46+
io_error::cond.raise(ioerr);
47+
return None;
48+
}
49+
}
2050
}
2151
}
2252

2353
impl Reader for TcpStream {
24-
fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() }
54+
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
55+
let bytes_read = self.rtstream.read(buf);
56+
match bytes_read {
57+
Ok(read) => Some(read),
58+
Err(_) => {
59+
abort!("TODO");
60+
}
61+
}
62+
}
2563

2664
fn eof(&mut self) -> bool { fail!() }
2765
}
2866

2967
impl Writer for TcpStream {
30-
fn write(&mut self, _buf: &[u8]) { fail!() }
68+
fn write(&mut self, buf: &[u8]) {
69+
let res = self.rtstream.write(buf);
70+
match res {
71+
Ok(_) => (),
72+
Err(_) => {
73+
abort!("TODO");
74+
}
75+
}
76+
}
3177

3278
fn flush(&mut self) { fail!() }
3379
}
3480

35-
pub struct TcpListener;
81+
impl Drop for TcpStream {
82+
fn finalize(&self) {
83+
self.rtstream.close();
84+
}
85+
}
86+
87+
pub struct TcpListener {
88+
rtlistener: ~rtio::TcpListenerObject
89+
}
3690

3791
impl TcpListener {
38-
pub fn bind(_addr: IpAddr) -> Option<TcpListener> {
39-
fail!()
92+
pub fn bind(addr: IpAddr) -> Option<TcpListener> {
93+
let listener = unsafe { unsafe_borrow_io().bind(addr) };
94+
match listener {
95+
Ok(l) => {
96+
Some(TcpListener {
97+
rtlistener: l
98+
})
99+
}
100+
Err(ioerr) => {
101+
io_error::cond.raise(ioerr);
102+
return None;
103+
}
104+
}
40105
}
41106
}
42107

43108
impl Listener<TcpStream> for TcpListener {
44-
fn accept(&mut self) -> Option<TcpStream> { fail!() }
109+
fn accept(&mut self) -> Option<TcpStream> {
110+
let rtstream = self.rtlistener.listen();
111+
match rtstream {
112+
Some(s) => {
113+
Some(TcpStream::new(s))
114+
}
115+
None => {
116+
abort!("TODO");
117+
}
118+
}
119+
}
120+
}
121+
122+
impl Drop for TcpListener {
123+
fn finalize(&self) {
124+
self.rtlistener.close();
125+
}
45126
}
46127

47128
#[cfg(test)]
48129
mod test {
130+
use super::*;
131+
use rt::test::*;
132+
use rt::io::net::ip::Ipv4;
133+
use rt::io::*;
134+
135+
#[test]
136+
fn bind_error() {
137+
do run_in_newsched_task {
138+
let mut called = false;
139+
do io_error::cond.trap(|e| {
140+
assert!(e.kind == PermissionDenied);
141+
called = true;
142+
}).in {
143+
let addr = Ipv4(0, 0, 0, 0, 1);
144+
let listener = TcpListener::bind(addr);
145+
assert!(listener.is_none());
146+
}
147+
assert!(called);
148+
}
149+
}
150+
151+
#[test]
152+
fn connect_error() {
153+
do run_in_newsched_task {
154+
let mut called = false;
155+
do io_error::cond.trap(|e| {
156+
assert!(e.kind == ConnectionRefused);
157+
called = true;
158+
}).in {
159+
let addr = Ipv4(0, 0, 0, 0, 1);
160+
let stream = TcpStream::connect(addr);
161+
assert!(stream.is_none());
162+
}
163+
assert!(called);
164+
}
165+
}
49166

50-
#[test] #[ignore]
167+
#[test]
51168
fn smoke_test() {
52-
/*do run_in_newsched_task {
169+
do run_in_newsched_task {
53170
let addr = next_test_ip4();
54171

55-
do spawn_immediately {
56-
let listener = TcpListener::bind(addr);
57-
do listener.accept() {
58-
let mut buf = [0];
59-
listener.read(buf);
60-
assert!(buf[0] == 99);
61-
}
172+
do spawntask_immediately {
173+
let mut listener = TcpListener::bind(addr);
174+
let mut stream = listener.accept();
175+
let mut buf = [0];
176+
stream.read(buf);
177+
assert!(buf[0] == 99);
62178
}
63179

64-
do spawn_immediately {
65-
let stream = TcpStream::connect(addr);
180+
do spawntask_immediately {
181+
let mut stream = TcpStream::connect(addr);
66182
stream.write([99]);
67183
}
68-
}*/
184+
}
69185
}
70186
}

src/libcore/rt/local_services.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,8 @@ pub unsafe fn unsafe_borrow_local_services() -> &mut LocalServices {
177177
transmute_mut_region(&mut task.local_services)
178178
}
179179
None => {
180-
fail!(~"no local services for schedulers yet")
180+
// Don't fail. Infinite recursion
181+
abort!("no local services for schedulers yet")
181182
}
182183
}
183184
}

src/libcore/rt/mod.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,23 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
/*! The Rust runtime, including the scheduler and I/O interface */
11+
/*! The Rust runtime, including the scheduler and I/O interface
12+
13+
# XXX
14+
15+
* Unsafe uses of borrowed pointers should just use unsafe pointers
16+
* Unwinding is not wired up correctly
17+
18+
*/
19+
1220

1321
#[doc(hidden)];
1422

1523
use libc::c_char;
1624

1725
#[path = "sched/mod.rs"]
1826
mod sched;
19-
mod rtio;
27+
pub mod rtio;
2028
pub mod uvll;
2129
mod uvio;
2230
#[path = "uv/mod.rs"]

src/libcore/rt/rtio.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use option::*;
1212
use result::*;
1313

14+
use rt::io::IoError;
1415
use super::io::net::ip::IpAddr;
1516

1617
// XXX: ~object doesn't work currently so these are some placeholder
@@ -28,8 +29,8 @@ pub trait EventLoop {
2829
}
2930

3031
pub trait IoFactory {
31-
fn connect(&mut self, addr: IpAddr) -> Option<~StreamObject>;
32-
fn bind(&mut self, addr: IpAddr) -> Option<~TcpListenerObject>;
32+
fn connect(&mut self, addr: IpAddr) -> Result<~StreamObject, IoError>;
33+
fn bind(&mut self, addr: IpAddr) -> Result<~TcpListenerObject, IoError>;
3334
}
3435

3536
pub trait TcpListener {

src/libcore/rt/sched/local_sched.rs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,21 @@
1313
use prelude::*;
1414
use ptr::mut_null;
1515
use libc::c_void;
16-
use cast::transmute;
16+
use cast;
17+
use cell::Cell;
1718

1819
use super::Scheduler;
1920
use super::super::rtio::IoFactoryObject;
2021
use tls = super::super::thread_local_storage;
22+
use unstable::finally::Finally;
23+
2124
#[cfg(test)] use super::super::uvio::UvEventLoop;
2225

2326
/// Give the Scheduler to thread-local storage
2427
pub fn put(sched: ~Scheduler) {
2528
unsafe {
2629
let key = tls_key();
27-
let void_sched: *mut c_void = transmute::<~Scheduler, *mut c_void>(sched);
30+
let void_sched: *mut c_void = cast::transmute(sched);
2831
tls::set(key, void_sched);
2932
}
3033
}
@@ -34,8 +37,8 @@ pub fn take() -> ~Scheduler {
3437
unsafe {
3538
let key = tls_key();
3639
let void_sched: *mut c_void = tls::get(key);
37-
assert!(void_sched.is_not_null());
38-
let sched = transmute::<*mut c_void, ~Scheduler>(void_sched);
40+
rtassert!(void_sched.is_not_null());
41+
let sched: ~Scheduler = cast::transmute(void_sched);
3942
tls::set(key, mut_null());
4043
return sched;
4144
}
@@ -55,8 +58,18 @@ pub fn exists() -> bool {
5558
/// While the scheduler is borrowed it is not available in TLS.
5659
pub fn borrow(f: &fn(&mut Scheduler)) {
5760
let mut sched = take();
58-
f(sched);
59-
put(sched);
61+
62+
// XXX: Need a different abstraction from 'finally' here to avoid unsafety
63+
unsafe {
64+
let unsafe_sched = cast::transmute_mut_region(&mut *sched);
65+
let sched = Cell(sched);
66+
67+
do (|| {
68+
f(unsafe_sched);
69+
}).finally {
70+
put(sched.take());
71+
}
72+
}
6073
}
6174

6275
/// Borrow a mutable reference to the thread-local Scheduler
@@ -68,11 +81,11 @@ pub fn borrow(f: &fn(&mut Scheduler)) {
6881
pub unsafe fn unsafe_borrow() -> &mut Scheduler {
6982
let key = tls_key();
7083
let mut void_sched: *mut c_void = tls::get(key);
71-
assert!(void_sched.is_not_null());
84+
rtassert!(void_sched.is_not_null());
7285
{
7386
let void_sched_ptr = &mut void_sched;
7487
let sched: &mut ~Scheduler = {
75-
transmute::<&mut *mut c_void, &mut ~Scheduler>(void_sched_ptr)
88+
cast::transmute::<&mut *mut c_void, &mut ~Scheduler>(void_sched_ptr)
7689
};
7790
let sched: &mut Scheduler = &mut **sched;
7891
return sched;
@@ -91,7 +104,7 @@ fn tls_key() -> tls::Key {
91104
fn maybe_tls_key() -> Option<tls::Key> {
92105
unsafe {
93106
let key: *mut c_void = rust_get_sched_tls_key();
94-
let key: &mut tls::Key = transmute(key);
107+
let key: &mut tls::Key = cast::transmute(key);
95108
let key = *key;
96109
// Check that the key has been initialized.
97110

0 commit comments

Comments
 (0)