]>
Commit | Line | Data |
---|---|---|
85aaf69f SL |
1 | // Copyright 2015 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 prelude::v1::*; | |
12 | ||
13 | use io; | |
14 | use libc::consts::os::extra::INVALID_SOCKET; | |
15 | use libc::{self, c_int, c_void}; | |
16 | use mem; | |
c34b1796 | 17 | use net::SocketAddr; |
9346a6ac AL |
18 | use num::One; |
19 | use ops::Neg; | |
85aaf69f | 20 | use rt; |
62682a34 SL |
21 | use sync::Once; |
22 | use sys; | |
85aaf69f | 23 | use sys::c; |
c34b1796 | 24 | use sys_common::{AsInner, FromInner}; |
62682a34 SL |
25 | use sys_common::net::{setsockopt, getsockopt}; |
26 | use time::Duration; | |
85aaf69f SL |
27 | |
28 | pub type wrlen_t = i32; | |
29 | ||
30 | pub struct Socket(libc::SOCKET); | |
31 | ||
c34b1796 AL |
32 | /// Checks whether the Windows socket interface has been started already, and |
33 | /// if not, starts it. | |
85aaf69f | 34 | pub fn init() { |
62682a34 | 35 | static START: Once = Once::new(); |
85aaf69f SL |
36 | |
37 | START.call_once(|| unsafe { | |
38 | let mut data: c::WSADATA = mem::zeroed(); | |
39 | let ret = c::WSAStartup(0x202, // version 2.2 | |
40 | &mut data); | |
41 | assert_eq!(ret, 0); | |
42 | ||
c34b1796 | 43 | let _ = rt::at_exit(|| { c::WSACleanup(); }); |
85aaf69f SL |
44 | }); |
45 | } | |
46 | ||
c34b1796 | 47 | /// Returns the last error from the Windows socket interface. |
85aaf69f | 48 | fn last_error() -> io::Error { |
9346a6ac | 49 | io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() }) |
85aaf69f SL |
50 | } |
51 | ||
c34b1796 AL |
52 | /// Checks if the signed integer is the Windows constant `SOCKET_ERROR` (-1) |
53 | /// and if so, returns the last error from the Windows socket interface. . This | |
54 | /// function must be called before another call to the socket API is made. | |
9346a6ac AL |
55 | pub fn cvt<T: One + Neg<Output=T> + PartialEq>(t: T) -> io::Result<T> { |
56 | let one: T = T::one(); | |
85aaf69f SL |
57 | if t == -one { |
58 | Err(last_error()) | |
59 | } else { | |
60 | Ok(t) | |
61 | } | |
62 | } | |
63 | ||
c34b1796 AL |
64 | /// Provides the functionality of `cvt` for the return values of `getaddrinfo` |
65 | /// and similar, meaning that they return an error if the return value is 0. | |
85aaf69f SL |
66 | pub fn cvt_gai(err: c_int) -> io::Result<()> { |
67 | if err == 0 { return Ok(()) } | |
68 | cvt(err).map(|_| ()) | |
69 | } | |
70 | ||
c34b1796 AL |
71 | /// Provides the functionality of `cvt` for a closure. |
72 | #[allow(deprecated)] | |
9346a6ac AL |
73 | pub fn cvt_r<T, F>(mut f: F) -> io::Result<T> |
74 | where F: FnMut() -> T, T: One + Neg<Output=T> + PartialEq | |
75 | { | |
85aaf69f SL |
76 | cvt(f()) |
77 | } | |
78 | ||
79 | impl Socket { | |
80 | pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> { | |
c34b1796 AL |
81 | let fam = match *addr { |
82 | SocketAddr::V4(..) => libc::AF_INET, | |
83 | SocketAddr::V6(..) => libc::AF_INET6, | |
85aaf69f | 84 | }; |
9346a6ac AL |
85 | let socket = unsafe { |
86 | c::WSASocketW(fam, ty, 0, 0 as *mut _, 0, | |
87 | c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT) | |
88 | }; | |
89 | match socket { | |
85aaf69f SL |
90 | INVALID_SOCKET => Err(last_error()), |
91 | n => Ok(Socket(n)), | |
92 | } | |
93 | } | |
94 | ||
95 | pub fn accept(&self, storage: *mut libc::sockaddr, | |
96 | len: *mut libc::socklen_t) -> io::Result<Socket> { | |
97 | match unsafe { libc::accept(self.0, storage, len) } { | |
98 | INVALID_SOCKET => Err(last_error()), | |
99 | n => Ok(Socket(n)), | |
100 | } | |
101 | } | |
102 | ||
103 | pub fn duplicate(&self) -> io::Result<Socket> { | |
104 | unsafe { | |
105 | let mut info: c::WSAPROTOCOL_INFO = mem::zeroed(); | |
106 | try!(cvt(c::WSADuplicateSocketW(self.0, | |
107 | c::GetCurrentProcessId(), | |
108 | &mut info))); | |
109 | match c::WSASocketW(info.iAddressFamily, | |
110 | info.iSocketType, | |
111 | info.iProtocol, | |
9346a6ac AL |
112 | &mut info, 0, |
113 | c::WSA_FLAG_OVERLAPPED | | |
114 | c::WSA_FLAG_NO_HANDLE_INHERIT) { | |
85aaf69f SL |
115 | INVALID_SOCKET => Err(last_error()), |
116 | n => Ok(Socket(n)), | |
117 | } | |
118 | } | |
119 | } | |
120 | ||
121 | pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { | |
122 | // On unix when a socket is shut down all further reads return 0, so we | |
123 | // do the same on windows to map a shut down socket to returning EOF. | |
124 | unsafe { | |
125 | match libc::recv(self.0, buf.as_mut_ptr() as *mut c_void, | |
126 | buf.len() as i32, 0) { | |
127 | -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0), | |
128 | -1 => Err(last_error()), | |
129 | n => Ok(n as usize) | |
130 | } | |
131 | } | |
132 | } | |
62682a34 SL |
133 | |
134 | pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> { | |
135 | let timeout = match dur { | |
136 | Some(dur) => { | |
137 | let timeout = sys::dur2timeout(dur); | |
138 | if timeout == 0 { | |
139 | return Err(io::Error::new(io::ErrorKind::InvalidInput, | |
140 | "cannot set a 0 duration timeout")); | |
141 | } | |
142 | timeout | |
143 | } | |
144 | None => 0 | |
145 | }; | |
146 | setsockopt(self, libc::SOL_SOCKET, kind, timeout) | |
147 | } | |
148 | ||
149 | pub fn timeout(&self, kind: libc::c_int) -> io::Result<Option<Duration>> { | |
150 | let raw: libc::DWORD = try!(getsockopt(self, libc::SOL_SOCKET, kind)); | |
151 | if raw == 0 { | |
152 | Ok(None) | |
153 | } else { | |
154 | let secs = raw / 1000; | |
155 | let nsec = (raw % 1000) * 1000000; | |
156 | Ok(Some(Duration::new(secs as u64, nsec as u32))) | |
157 | } | |
158 | } | |
85aaf69f SL |
159 | } |
160 | ||
161 | impl Drop for Socket { | |
162 | fn drop(&mut self) { | |
c34b1796 | 163 | let _ = unsafe { libc::closesocket(self.0) }; |
85aaf69f SL |
164 | } |
165 | } | |
166 | ||
167 | impl AsInner<libc::SOCKET> for Socket { | |
168 | fn as_inner(&self) -> &libc::SOCKET { &self.0 } | |
169 | } | |
c34b1796 AL |
170 | |
171 | impl FromInner<libc::SOCKET> for Socket { | |
172 | fn from_inner(sock: libc::SOCKET) -> Socket { Socket(sock) } | |
173 | } |