]> git.lizzy.rs Git - rust.git/blob - src/libnative/io/mod.rs
libnative: Implement get_host_addresses.
[rust.git] / src / libnative / io / mod.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 //! Native thread-blocking I/O implementation
12 //!
13 //! This module contains the implementation of native thread-blocking
14 //! implementations of I/O on all platforms. This module is not intended to be
15 //! used directly, but rather the rust runtime will fall back to using it if
16 //! necessary.
17 //!
18 //! Rust code normally runs inside of green tasks with a local scheduler using
19 //! asynchronous I/O to cooperate among tasks. This model is not always
20 //! available, however, and that's where these native implementations come into
21 //! play. The only dependencies of these modules are the normal system libraries
22 //! that you would find on the respective platform.
23
24 use std::c_str::CString;
25 use std::comm::SharedChan;
26 use std::io;
27 use std::io::IoError;
28 use std::io::net::ip::SocketAddr;
29 use std::io::process::ProcessConfig;
30 use std::io::signal::Signum;
31 use std::libc::c_int;
32 use std::libc;
33 use std::os;
34 use std::rt::rtio;
35 use std::rt::rtio::{RtioTcpStream, RtioTcpListener, RtioUdpSocket,
36                     RtioUnixListener, RtioPipe, RtioFileStream, RtioProcess,
37                     RtioSignal, RtioTTY, CloseBehavior, RtioTimer};
38 use ai = std::io::net::addrinfo;
39
40 // Local re-exports
41 pub use self::file::FileDesc;
42 pub use self::process::Process;
43
44 // Native I/O implementations
45 pub mod addrinfo;
46 pub mod file;
47 pub mod net;
48 pub mod process;
49
50 type IoResult<T> = Result<T, IoError>;
51
52 fn unimpl() -> IoError {
53     IoError {
54         kind: io::IoUnavailable,
55         desc: "unimplemented I/O interface",
56         detail: None,
57     }
58 }
59
60 fn translate_error(errno: i32, detail: bool) -> IoError {
61     #[cfg(windows)]
62     fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) {
63         match errno {
64             libc::EOF => (io::EndOfFile, "end of file"),
65             libc::WSAECONNREFUSED => (io::ConnectionRefused, "connection refused"),
66             libc::WSAECONNRESET => (io::ConnectionReset, "connection reset"),
67             libc::WSAEACCES => (io::PermissionDenied, "permission denied"),
68             libc::WSAEWOULDBLOCK =>
69                 (io::ResourceUnavailable, "resource temporarily unavailable"),
70             libc::WSAENOTCONN => (io::NotConnected, "not connected"),
71             libc::WSAECONNABORTED => (io::ConnectionAborted, "connection aborted"),
72             libc::WSAEADDRNOTAVAIL => (io::ConnectionRefused, "address not available"),
73             libc::WSAEADDRINUSE => (io::ConnectionRefused, "address in use"),
74
75             x => {
76                 debug!("ignoring {}: {}", x, os::last_os_error());
77                 (io::OtherIoError, "unknown error")
78             }
79         }
80     }
81
82     #[cfg(not(windows))]
83     fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) {
84         // XXX: this should probably be a bit more descriptive...
85         match errno {
86             libc::EOF => (io::EndOfFile, "end of file"),
87             libc::ECONNREFUSED => (io::ConnectionRefused, "connection refused"),
88             libc::ECONNRESET => (io::ConnectionReset, "connection reset"),
89             libc::EPERM | libc::EACCES =>
90                 (io::PermissionDenied, "permission denied"),
91             libc::EPIPE => (io::BrokenPipe, "broken pipe"),
92             libc::ENOTCONN => (io::NotConnected, "not connected"),
93             libc::ECONNABORTED => (io::ConnectionAborted, "connection aborted"),
94             libc::EADDRNOTAVAIL => (io::ConnectionRefused, "address not available"),
95             libc::EADDRINUSE => (io::ConnectionRefused, "address in use"),
96
97             // These two constants can have the same value on some systems, but
98             // different values on others, so we can't use a match clause
99             x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
100                 (io::ResourceUnavailable, "resource temporarily unavailable"),
101
102             x => {
103                 debug!("ignoring {}: {}", x, os::last_os_error());
104                 (io::OtherIoError, "unknown error")
105             }
106         }
107     }
108
109     let (kind, desc) = get_err(errno);
110     IoError {
111         kind: kind,
112         desc: desc,
113         detail: if detail {Some(os::last_os_error())} else {None},
114     }
115 }
116
117 fn last_error() -> IoError { translate_error(os::errno() as i32, true) }
118
119 // unix has nonzero values as errors
120 fn mkerr_libc(ret: libc::c_int) -> IoResult<()> {
121     if ret != 0 {
122         Err(last_error())
123     } else {
124         Ok(())
125     }
126 }
127
128 // windows has zero values as errors
129 #[cfg(windows)]
130 fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> {
131     if ret == 0 {
132         Err(last_error())
133     } else {
134         Ok(())
135     }
136 }
137
138 #[cfg(windows)]
139 #[inline]
140 fn retry(f: || -> libc::c_int) -> libc::c_int {
141     loop {
142         match f() {
143             -1 if os::errno() as int == libc::WSAEINTR as int => {}
144             n => return n,
145         }
146     }
147 }
148
149 #[cfg(unix)]
150 #[inline]
151 fn retry(f: || -> libc::c_int) -> libc::c_int {
152     loop {
153         match f() {
154             -1 if os::errno() as int == libc::EINTR as int => {}
155             n => return n,
156         }
157     }
158 }
159
160 /// Implementation of rt::rtio's IoFactory trait to generate handles to the
161 /// native I/O functionality.
162 pub struct IoFactory {
163     priv cannot_construct_outside_of_this_module: ()
164 }
165
166 impl IoFactory {
167     pub fn new() -> IoFactory {
168         net::init();
169         IoFactory { cannot_construct_outside_of_this_module: () }
170     }
171 }
172
173 impl rtio::IoFactory for IoFactory {
174     // networking
175     fn tcp_connect(&mut self, addr: SocketAddr) -> IoResult<~RtioTcpStream> {
176         net::TcpStream::connect(addr).map(|s| ~s as ~RtioTcpStream)
177     }
178     fn tcp_bind(&mut self, addr: SocketAddr) -> IoResult<~RtioTcpListener> {
179         net::TcpListener::bind(addr).map(|s| ~s as ~RtioTcpListener)
180     }
181     fn udp_bind(&mut self, addr: SocketAddr) -> IoResult<~RtioUdpSocket> {
182         net::UdpSocket::bind(addr).map(|u| ~u as ~RtioUdpSocket)
183     }
184     fn unix_bind(&mut self, _path: &CString) -> IoResult<~RtioUnixListener> {
185         Err(unimpl())
186     }
187     fn unix_connect(&mut self, _path: &CString) -> IoResult<~RtioPipe> {
188         Err(unimpl())
189     }
190     fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
191                           hint: Option<ai::Hint>) -> IoResult<~[ai::Info]> {
192         addrinfo::GetAddrInfoRequest::run(host, servname, hint)
193     }
194
195     // filesystem operations
196     fn fs_from_raw_fd(&mut self, fd: c_int,
197                       close: CloseBehavior) -> ~RtioFileStream {
198         let close = match close {
199             rtio::CloseSynchronously | rtio::CloseAsynchronously => true,
200             rtio::DontClose => false
201         };
202         ~file::FileDesc::new(fd, close) as ~RtioFileStream
203     }
204     fn fs_open(&mut self, path: &CString, fm: io::FileMode, fa: io::FileAccess)
205         -> IoResult<~RtioFileStream> {
206         file::open(path, fm, fa).map(|fd| ~fd as ~RtioFileStream)
207     }
208     fn fs_unlink(&mut self, path: &CString) -> IoResult<()> {
209         file::unlink(path)
210     }
211     fn fs_stat(&mut self, path: &CString) -> IoResult<io::FileStat> {
212         file::stat(path)
213     }
214     fn fs_mkdir(&mut self, path: &CString,
215                 mode: io::FilePermission) -> IoResult<()> {
216         file::mkdir(path, mode)
217     }
218     fn fs_chmod(&mut self, path: &CString,
219                 mode: io::FilePermission) -> IoResult<()> {
220         file::chmod(path, mode)
221     }
222     fn fs_rmdir(&mut self, path: &CString) -> IoResult<()> {
223         file::rmdir(path)
224     }
225     fn fs_rename(&mut self, path: &CString, to: &CString) -> IoResult<()> {
226         file::rename(path, to)
227     }
228     fn fs_readdir(&mut self, path: &CString, _flags: c_int) -> IoResult<~[Path]> {
229         file::readdir(path)
230     }
231     fn fs_lstat(&mut self, path: &CString) -> IoResult<io::FileStat> {
232         file::lstat(path)
233     }
234     fn fs_chown(&mut self, path: &CString, uid: int, gid: int) -> IoResult<()> {
235         file::chown(path, uid, gid)
236     }
237     fn fs_readlink(&mut self, path: &CString) -> IoResult<Path> {
238         file::readlink(path)
239     }
240     fn fs_symlink(&mut self, src: &CString, dst: &CString) -> IoResult<()> {
241         file::symlink(src, dst)
242     }
243     fn fs_link(&mut self, src: &CString, dst: &CString) -> IoResult<()> {
244         file::link(src, dst)
245     }
246     fn fs_utime(&mut self, src: &CString, atime: u64,
247                 mtime: u64) -> IoResult<()> {
248         file::utime(src, atime, mtime)
249     }
250
251     // misc
252     fn timer_init(&mut self) -> IoResult<~RtioTimer> {
253         Err(unimpl())
254     }
255     fn spawn(&mut self, config: ProcessConfig)
256             -> IoResult<(~RtioProcess, ~[Option<~RtioPipe>])> {
257         process::Process::spawn(config).map(|(p, io)| {
258             (~p as ~RtioProcess,
259              io.move_iter().map(|p| p.map(|p| ~p as ~RtioPipe)).collect())
260         })
261     }
262     fn pipe_open(&mut self, fd: c_int) -> IoResult<~RtioPipe> {
263         Ok(~file::FileDesc::new(fd, true) as ~RtioPipe)
264     }
265     fn tty_open(&mut self, fd: c_int, _readable: bool) -> IoResult<~RtioTTY> {
266         if unsafe { libc::isatty(fd) } != 0 {
267             Ok(~file::FileDesc::new(fd, true) as ~RtioTTY)
268         } else {
269             Err(IoError {
270                 kind: io::MismatchedFileTypeForOperation,
271                 desc: "file descriptor is not a TTY",
272                 detail: None,
273             })
274         }
275     }
276     fn signal(&mut self, _signal: Signum, _channel: SharedChan<Signum>)
277         -> IoResult<~RtioSignal> {
278         Err(unimpl())
279     }
280 }