|
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