use crate::server::upgrade::sync::{Buffer, IntoWs, Upgrade};
pub use crate::server::upgrade::{HyperIntoWsError, Request};
use crate::server::{InvalidConnection, NoTlsAcceptor, OptionalTlsAcceptor, WsServer};
#[cfg(feature = "sync-ssl")]
use native_tls::{TlsAcceptor, TlsStream};
use std::convert::Into;
use std::io;
use std::net::{SocketAddr, TcpListener, TcpStream, ToSocketAddrs};
#[cfg(feature = "async")]
use crate::server::r#async;
#[cfg(feature = "async")]
use tokio_reactor::Handle;
#[cfg(feature = "async")]
use tokio_tcp::TcpListener as AsyncTcpListener;
pub type AcceptResult<S> = Result<Upgrade<S>, InvalidConnection<S, Buffer>>;
pub type Server<S> = WsServer<S, TcpListener>;
impl<S> WsServer<S, TcpListener>
where
S: OptionalTlsAcceptor,
{
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.listener.local_addr()
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
self.listener.set_nonblocking(nonblocking)
}
#[cfg(feature = "async")]
pub fn into_async(self, handle: &Handle) -> io::Result<r#async::Server<S>> {
Ok(WsServer {
listener: AsyncTcpListener::from_std(self.listener, handle)?,
ssl_acceptor: self.ssl_acceptor,
})
}
}
#[cfg(feature = "sync-ssl")]
impl WsServer<TlsAcceptor, TcpListener> {
pub fn bind_secure<A>(addr: A, acceptor: TlsAcceptor) -> io::Result<Self>
where
A: ToSocketAddrs,
{
Ok(Server {
listener: TcpListener::bind(&addr)?,
ssl_acceptor: acceptor,
})
}
pub fn accept(&mut self) -> AcceptResult<TlsStream<TcpStream>> {
let stream = match self.listener.accept() {
Ok(s) => s.0,
Err(e) => {
return Err(InvalidConnection {
stream: None,
parsed: None,
buffer: None,
error: HyperIntoWsError::Io(e),
});
}
};
let stream = match self.ssl_acceptor.accept(stream) {
Ok(s) => s,
Err(err) => {
return Err(InvalidConnection {
stream: None,
parsed: None,
buffer: None,
error: io::Error::new(io::ErrorKind::Other, err).into(),
});
}
};
match stream.into_ws() {
Ok(u) => Ok(u),
Err((s, r, b, e)) => Err(InvalidConnection {
stream: Some(s),
parsed: r,
buffer: b,
error: e,
}),
}
}
}
#[cfg(feature = "sync-ssl")]
impl Iterator for WsServer<TlsAcceptor, TcpListener> {
type Item = AcceptResult<TlsStream<TcpStream>>;
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
Some(self.accept())
}
}
impl WsServer<NoTlsAcceptor, TcpListener> {
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<Self> {
Ok(Server {
listener: TcpListener::bind(&addr)?,
ssl_acceptor: NoTlsAcceptor,
})
}
pub fn accept(&mut self) -> AcceptResult<TcpStream> {
let stream = match self.listener.accept() {
Ok(s) => s.0,
Err(e) => {
return Err(InvalidConnection {
stream: None,
parsed: None,
buffer: None,
error: e.into(),
});
}
};
match stream.into_ws() {
Ok(u) => Ok(u),
Err((s, r, b, e)) => Err(InvalidConnection {
stream: Some(s),
parsed: r,
buffer: b,
error: e,
}),
}
}
pub fn try_clone(&self) -> io::Result<Self> {
let inner = self.listener.try_clone()?;
Ok(Server {
listener: inner,
ssl_acceptor: self.ssl_acceptor.clone(),
})
}
}
impl Iterator for WsServer<NoTlsAcceptor, TcpListener> {
type Item = AcceptResult<TcpStream>;
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
Some(self.accept())
}
}
mod tests {
#[test]
fn set_nonblocking() {
use super::*;
let mut server = Server::bind("127.0.0.1:0").unwrap();
server.set_nonblocking(true).unwrap();
let result = server.accept();
match result {
Ok(_) => panic!("expected error"),
Err(e) => match e.error {
HyperIntoWsError::Io(ref e) if e.kind() == io::ErrorKind::WouldBlock => {}
e => panic!("unexpected error {}", e),
},
}
}
}