Skip to content

Commit 6e0a860

Browse files
committed
Pull IO stuff out to a separate module.
1 parent ff587b3 commit 6e0a860

4 files changed

Lines changed: 171 additions & 156 deletions

File tree

src/error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ make_errors!(
359359
/// Reasons a new Postgres connection could fail
360360
pub enum PostgresConnectError {
361361
/// The provided URL could not be parsed
362-
InvalidUrl,
362+
InvalidUrl(~str),
363363
/// The URL was missing a user
364364
MissingUser,
365365
/// DNS lookup failed
@@ -384,7 +384,7 @@ pub enum PostgresConnectError {
384384
impl fmt::Show for PostgresConnectError {
385385
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
386386
match *self {
387-
InvalidUrl => fmt.buf.write_str("Invalid URL"),
387+
InvalidUrl(ref err) => write!(fmt.buf, "Invalid URL: {}", err),
388388
MissingUser => fmt.buf.write_str("User missing in URL"),
389389
DnsError(ref err) => write!(fmt.buf, "DNS lookup failed: {}", err),
390390
SocketError(ref err) =>

src/io.rs

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
use openssl::ssl::SslStream;
2+
use std::io::net;
3+
use std::io::net::ip::{Port, SocketAddr};
4+
use std::io::net::tcp::TcpStream;
5+
use std::io::net::unix::UnixStream;
6+
use std::io::{Stream, IoResult};
7+
8+
use {PostgresConnectParams,
9+
SslMode,
10+
NoSsl,
11+
PreferSsl,
12+
RequireSsl,
13+
TargetTcp,
14+
TargetUnix};
15+
use error::{PostgresConnectError,
16+
PgConnectStreamError,
17+
DnsError,
18+
NoSslSupport,
19+
SslError,
20+
SocketError};
21+
use message;
22+
use message::{SslRequest, WriteMessage};
23+
24+
static DEFAULT_PORT: Port = 5432;
25+
26+
fn open_tcp_socket(host: &str, port: Port) -> Result<TcpStream,
27+
PostgresConnectError> {
28+
let addrs = match net::get_host_addresses(host) {
29+
Ok(addrs) => addrs,
30+
Err(err) => return Err(DnsError(err))
31+
};
32+
33+
let mut err = None;
34+
for &addr in addrs.iter() {
35+
match TcpStream::connect(SocketAddr { ip: addr, port: port }) {
36+
Ok(socket) => return Ok(socket),
37+
Err(e) => err = Some(e)
38+
}
39+
}
40+
41+
Err(SocketError(err.unwrap()))
42+
}
43+
44+
fn open_unix_socket(path: &Path, port: Port) -> Result<UnixStream,
45+
PostgresConnectError> {
46+
let mut socket = path.clone();
47+
socket.push(format!(".s.PGSQL.{}", port));
48+
49+
match UnixStream::connect(&socket) {
50+
Ok(unix) => Ok(unix),
51+
Err(err) => Err(SocketError(err))
52+
}
53+
}
54+
55+
pub enum MaybeSslStream<S> {
56+
SslStream(SslStream<S>),
57+
NormalStream(S),
58+
}
59+
60+
impl<S: Stream> Reader for MaybeSslStream<S> {
61+
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
62+
match *self {
63+
SslStream(ref mut s) => s.read(buf),
64+
NormalStream(ref mut s) => s.read(buf),
65+
}
66+
}
67+
}
68+
69+
impl<S: Stream> Writer for MaybeSslStream<S> {
70+
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
71+
match *self {
72+
SslStream(ref mut s) => s.write(buf),
73+
NormalStream(ref mut s) => s.write(buf),
74+
}
75+
}
76+
77+
fn flush(&mut self) -> IoResult<()> {
78+
match *self {
79+
SslStream(ref mut s) => s.flush(),
80+
NormalStream(ref mut s) => s.flush(),
81+
}
82+
}
83+
}
84+
85+
pub enum InternalStream {
86+
TcpStream(TcpStream),
87+
UnixStream(UnixStream),
88+
}
89+
90+
impl Reader for InternalStream {
91+
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
92+
match *self {
93+
TcpStream(ref mut s) => s.read(buf),
94+
UnixStream(ref mut s) => s.read(buf),
95+
}
96+
}
97+
}
98+
99+
impl Writer for InternalStream {
100+
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
101+
match *self {
102+
TcpStream(ref mut s) => s.write(buf),
103+
UnixStream(ref mut s) => s.write(buf),
104+
}
105+
}
106+
107+
fn flush(&mut self) -> IoResult<()> {
108+
match *self {
109+
TcpStream(ref mut s) => s.flush(),
110+
UnixStream(ref mut s) => s.flush(),
111+
}
112+
}
113+
}
114+
115+
fn open_socket(params: &PostgresConnectParams)
116+
-> Result<InternalStream, PostgresConnectError> {
117+
let port = params.port.unwrap_or(DEFAULT_PORT);
118+
match params.target {
119+
TargetTcp(ref host) => open_tcp_socket(host.as_slice(), port)
120+
.map(|s| TcpStream(s)),
121+
TargetUnix(ref path) => open_unix_socket(path, port)
122+
.map(|s| UnixStream(s)),
123+
}
124+
}
125+
126+
pub fn initialize_stream(params: &PostgresConnectParams, ssl: &SslMode)
127+
-> Result<MaybeSslStream<InternalStream>,
128+
PostgresConnectError> {
129+
let mut socket = try!(open_socket(params));
130+
131+
let (ssl_required, ctx) = match *ssl {
132+
NoSsl => return Ok(NormalStream(socket)),
133+
PreferSsl(ref ctx) => (false, ctx),
134+
RequireSsl(ref ctx) => (true, ctx)
135+
};
136+
137+
try_pg_conn!(socket.write_message(&SslRequest { code: message::SSL_CODE }));
138+
try_pg_conn!(socket.flush());
139+
140+
if try_pg_conn!(socket.read_u8()) == 'N' as u8 {
141+
if ssl_required {
142+
return Err(NoSslSupport);
143+
} else {
144+
return Ok(NormalStream(socket));
145+
}
146+
}
147+
148+
match SslStream::try_new(ctx, socket) {
149+
Ok(stream) => Ok(SslStream(stream)),
150+
Err(err) => Err(SslError(err))
151+
}
152+
}
153+

0 commit comments

Comments
 (0)