|
1 | 1 | use std::io::{self, BufWriter, Read, Write}; |
2 | | -use std::fmt; |
3 | | -use std::net::TcpStream; |
| 2 | +use std::net::{ToSocketAddrs, SocketAddr}; |
4 | 3 | use std::time::Duration; |
5 | 4 | use std::result; |
6 | 5 | use bytes::{BufMut, BytesMut}; |
7 | 6 | #[cfg(unix)] |
8 | 7 | use std::os::unix::net::UnixStream; |
9 | 8 | #[cfg(unix)] |
10 | | -use std::os::unix::io::{AsRawFd, RawFd}; |
| 9 | +use std::os::unix::io::{AsRawFd, RawFd, FromRawFd, IntoRawFd}; |
11 | 10 | #[cfg(windows)] |
12 | 11 | use std::os::windows::io::{AsRawSocket, RawSocket}; |
13 | 12 | use postgres_protocol::message::frontend; |
14 | 13 | use postgres_protocol::message::backend; |
| 14 | +use socket2::{Socket, SockAddr, Domain, Type}; |
15 | 15 |
|
16 | 16 | use {Result, TlsMode}; |
17 | 17 | use error; |
@@ -118,37 +118,20 @@ impl MessageStream { |
118 | 118 | } |
119 | 119 |
|
120 | 120 | fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> { |
121 | | - match self.stream.get_ref().get_ref().0 { |
122 | | - InternalStream::Tcp(ref s) => s.set_read_timeout(timeout), |
123 | | - #[cfg(unix)] |
124 | | - InternalStream::Unix(ref s) => s.set_read_timeout(timeout), |
125 | | - } |
| 121 | + self.stream.get_ref().get_ref().0.set_read_timeout(timeout) |
126 | 122 | } |
127 | 123 |
|
128 | 124 | fn set_nonblocking(&self, nonblock: bool) -> io::Result<()> { |
129 | | - match self.stream.get_ref().get_ref().0 { |
130 | | - InternalStream::Tcp(ref s) => s.set_nonblocking(nonblock), |
131 | | - #[cfg(unix)] |
132 | | - InternalStream::Unix(ref s) => s.set_nonblocking(nonblock), |
133 | | - } |
| 125 | + self.stream.get_ref().get_ref().0.set_nonblocking(nonblock) |
134 | 126 | } |
135 | 127 | } |
136 | 128 |
|
137 | 129 | /// A connection to the Postgres server. |
138 | 130 | /// |
139 | 131 | /// It implements `Read`, `Write` and `TlsStream`, as well as `AsRawFd` on |
140 | 132 | /// Unix platforms and `AsRawSocket` on Windows platforms. |
141 | | -pub struct Stream(InternalStream); |
142 | | - |
143 | | -impl fmt::Debug for Stream { |
144 | | - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
145 | | - match self.0 { |
146 | | - InternalStream::Tcp(ref s) => fmt::Debug::fmt(s, fmt), |
147 | | - #[cfg(unix)] |
148 | | - InternalStream::Unix(ref s) => fmt::Debug::fmt(s, fmt), |
149 | | - } |
150 | | - } |
151 | | -} |
| 133 | +#[derive(Debug)] |
| 134 | +pub struct Stream(Socket); |
152 | 135 |
|
153 | 136 | impl Read for Stream { |
154 | 137 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
@@ -179,69 +162,56 @@ impl TlsStream for Stream { |
179 | 162 | #[cfg(unix)] |
180 | 163 | impl AsRawFd for Stream { |
181 | 164 | fn as_raw_fd(&self) -> RawFd { |
182 | | - match self.0 { |
183 | | - InternalStream::Tcp(ref s) => s.as_raw_fd(), |
184 | | - InternalStream::Unix(ref s) => s.as_raw_fd(), |
185 | | - } |
| 165 | + self.0.as_raw_fd() |
186 | 166 | } |
187 | 167 | } |
188 | 168 |
|
189 | 169 | #[cfg(windows)] |
190 | 170 | impl AsRawSocket for Stream { |
191 | 171 | fn as_raw_socket(&self) -> RawSocket { |
192 | | - // Unix sockets aren't supported on windows, so no need to match |
193 | | - match self.0 { |
194 | | - InternalStream::Tcp(ref s) => s.as_raw_socket(), |
195 | | - } |
196 | | - } |
197 | | -} |
198 | | - |
199 | | -enum InternalStream { |
200 | | - Tcp(TcpStream), |
201 | | - #[cfg(unix)] |
202 | | - Unix(UnixStream), |
203 | | -} |
204 | | - |
205 | | -impl Read for InternalStream { |
206 | | - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
207 | | - match *self { |
208 | | - InternalStream::Tcp(ref mut s) => s.read(buf), |
209 | | - #[cfg(unix)] |
210 | | - InternalStream::Unix(ref mut s) => s.read(buf), |
211 | | - } |
| 172 | + self.0.as_raw_socket() |
212 | 173 | } |
213 | 174 | } |
214 | 175 |
|
215 | | -impl Write for InternalStream { |
216 | | - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
217 | | - match *self { |
218 | | - InternalStream::Tcp(ref mut s) => s.write(buf), |
219 | | - #[cfg(unix)] |
220 | | - InternalStream::Unix(ref mut s) => s.write(buf), |
221 | | - } |
222 | | - } |
223 | | - |
224 | | - fn flush(&mut self) -> io::Result<()> { |
225 | | - match *self { |
226 | | - InternalStream::Tcp(ref mut s) => s.flush(), |
227 | | - #[cfg(unix)] |
228 | | - InternalStream::Unix(ref mut s) => s.flush(), |
229 | | - } |
230 | | - } |
231 | | -} |
232 | | - |
233 | | -fn open_socket(params: &ConnectParams) -> Result<InternalStream> { |
| 176 | +fn open_socket(params: &ConnectParams) -> Result<Socket> { |
234 | 177 | let port = params.port(); |
235 | 178 | match *params.host() { |
236 | 179 | Host::Tcp(ref host) => { |
237 | | - Ok(TcpStream::connect(&(&**host, port)).map( |
238 | | - InternalStream::Tcp, |
239 | | - )?) |
| 180 | + let mut error = None; |
| 181 | + for addr in (&**host, port).to_socket_addrs()? { |
| 182 | + let domain = match addr { |
| 183 | + SocketAddr::V4(_) => Domain::ipv4(), |
| 184 | + SocketAddr::V6(_) => Domain::ipv6(), |
| 185 | + }; |
| 186 | + let socket = Socket::new(domain, Type::stream(), None)?; |
| 187 | + let addr = SockAddr::from(addr); |
| 188 | + let r = match params.connect_timeout() { |
| 189 | + Some(timeout) => socket.connect_timeout(&addr, timeout), |
| 190 | + None => socket.connect(&addr), |
| 191 | + }; |
| 192 | + match r { |
| 193 | + Ok(()) => return Ok(socket), |
| 194 | + Err(e) => error = Some(e), |
| 195 | + } |
| 196 | + } |
| 197 | + |
| 198 | + Err( |
| 199 | + error |
| 200 | + .unwrap_or_else(|| { |
| 201 | + io::Error::new( |
| 202 | + io::ErrorKind::InvalidInput, |
| 203 | + "could not resolve any addresses", |
| 204 | + ) |
| 205 | + }) |
| 206 | + .into(), |
| 207 | + ) |
240 | 208 | } |
241 | 209 | #[cfg(unix)] |
242 | 210 | Host::Unix(ref path) => { |
243 | 211 | let path = path.join(&format!(".s.PGSQL.{}", port)); |
244 | | - Ok(UnixStream::connect(&path).map(InternalStream::Unix)?) |
| 212 | + Ok(UnixStream::connect(&path).map(|s| unsafe { |
| 213 | + Socket::from_raw_fd(s.into_raw_fd()) |
| 214 | + })?) |
245 | 215 | } |
246 | 216 | #[cfg(not(unix))] |
247 | 217 | Host::Unix(..) => { |
|
0 commit comments