use {NonBlock, IntoNonBlock};
use io::{self, Evented, FromFd, Io};
use net::{self, nix, Socket};
use std::mem;
use std::net::SocketAddr;
use std::os::unix::io::{RawFd, AsRawFd};
pub use std::net::{TcpStream, TcpListener};
pub fn v4() -> io::Result<NonBlock<TcpSocket>> {
TcpSocket::new(nix::AddressFamily::Inet, true)
.map(NonBlock::new)
}
pub fn v6() -> io::Result<NonBlock<TcpSocket>> {
TcpSocket::new(nix::AddressFamily::Inet6, true)
.map(NonBlock::new)
}
pub fn listen(addr: &SocketAddr) -> io::Result<NonBlock<TcpListener>> {
let sock = try!(match *addr {
SocketAddr::V4(..) => v4(),
SocketAddr::V6(..) => v6(),
});
try!(sock.bind(addr));
sock.listen(1024)
}
pub fn connect(addr: &SocketAddr) -> io::Result<(NonBlock<TcpStream>, bool)> {
let sock = try!(match *addr {
SocketAddr::V4(..) => v4(),
SocketAddr::V6(..) => v6(),
});
sock.connect(addr)
}
#[derive(Debug)]
pub struct TcpSocket {
io: Io,
}
impl TcpSocket {
fn new(family: nix::AddressFamily, nonblock: bool) -> io::Result<TcpSocket> {
net::socket(family, nix::SockType::Stream, nonblock)
.map(FromFd::from_fd)
}
pub fn connect(self, addr: &SocketAddr) -> io::Result<(TcpStream, bool)> {
let io = self.io;
net::connect(&io, &net::to_nix_addr(addr))
.map(|complete| (to_tcp_stream(io), complete))
}
pub fn bind(&self, addr: &SocketAddr) -> io::Result<()> {
net::bind(&self.io, &net::to_nix_addr(addr))
}
pub fn listen(self, backlog: usize) -> io::Result<TcpListener> {
try!(net::listen(&self.io, backlog));
Ok(to_tcp_listener(self.io))
}
pub fn getpeername(&self) -> io::Result<SocketAddr> {
net::getpeername(&self.io)
.map(net::to_std_addr)
}
pub fn getsockname(&self) -> io::Result<SocketAddr> {
net::getsockname(&self.io)
.map(net::to_std_addr)
}
}
impl NonBlock<TcpSocket> {
pub fn listen(self, backlog: usize) -> io::Result<NonBlock<TcpListener>> {
self.unwrap().listen(backlog)
.map(NonBlock::new)
}
pub fn connect(self, addr: &SocketAddr) -> io::Result<(NonBlock<TcpStream>, bool)> {
self.unwrap().connect(addr)
.map(|(stream, complete)| (NonBlock::new(stream), complete))
}
}
impl Evented for TcpSocket {
}
impl AsRawFd for TcpSocket {
fn as_raw_fd(&self) -> RawFd {
self.io.as_raw_fd()
}
}
impl FromFd for TcpSocket {
fn from_fd(fd: RawFd) -> TcpSocket {
TcpSocket { io: Io::new(fd) }
}
}
impl Socket for TcpSocket {
}
impl FromFd for TcpStream {
fn from_fd(fd: RawFd) -> TcpStream {
to_tcp_stream(Io::new(fd))
}
}
impl Evented for TcpStream {
}
impl Socket for TcpStream {
}
impl IntoNonBlock for TcpStream {
fn into_non_block(self) -> io::Result<NonBlock<TcpStream>> {
try!(net::set_non_block(as_io(&self)));
Ok(NonBlock::new(self))
}
}
impl FromFd for TcpListener {
fn from_fd(fd: RawFd) -> TcpListener {
to_tcp_listener(Io::new(fd))
}
}
impl Evented for TcpListener {
}
impl Socket for TcpListener {
}
impl IntoNonBlock for TcpListener {
fn into_non_block(self) -> io::Result<NonBlock<TcpListener>> {
try!(net::set_non_block(as_io(&self)));
Ok(NonBlock::new(self))
}
}
impl NonBlock<TcpListener> {
pub fn accept(&self) -> io::Result<Option<NonBlock<TcpStream>>> {
net::accept(as_io(self), true)
.map(|fd| Some(FromFd::from_fd(fd)))
.or_else(io::to_non_block)
}
}
fn to_tcp_stream(io: Io) -> TcpStream {
unsafe { mem::transmute(io) }
}
fn to_tcp_listener(io: Io) -> TcpListener {
unsafe { mem::transmute(io) }
}
fn as_io<'a, T>(tcp: &'a T) -> &'a Io {
unsafe { mem::transmute(tcp) }
}