use std::net::{SocketAddr, ToSocketAddrs, TcpListener, TcpStream};
use std::io;
use std::convert::Into;
#[cfg(feature="sync-ssl")]
use native_tls::{TlsStream, TlsAcceptor};
use server::{WsServer, OptionalTlsAcceptor, NoTlsAcceptor, InvalidConnection};
use server::upgrade::sync::{Upgrade, IntoWs, Buffer};
pub use server::upgrade::{Request, HyperIntoWsError};
#[cfg(feature="async")]
use tokio_core::reactor::Handle;
#[cfg(feature="async")]
use tokio_core::net::TcpListener as AsyncTcpListener;
#[cfg(feature="async")]
use server::async;
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<async::Server<S>> {
let addr = self.listener.local_addr()?;
Ok(WsServer {
listener: AsyncTcpListener::from_listener(self.listener, &addr, 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: e.into(),
})
}
};
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.into(),
})
}
}
}
}
#[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.into(),
})
}
}
}
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 => {}
_ => panic!("unexpected error {}"),
}
}
}
}
}