From e3635f37f6a190ebbec69c730a199f375def3b83 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 3 Jan 2017 12:40:55 -0700 Subject: [PATCH] Add settings for TCP --- schemes/tcpd/src/main.rs | 719 +++++++++++++++++++++++---------------- 1 file changed, 419 insertions(+), 300 deletions(-) diff --git a/schemes/tcpd/src/main.rs b/schemes/tcpd/src/main.rs index 64661ce..9fb5935 100644 --- a/schemes/tcpd/src/main.rs +++ b/schemes/tcpd/src/main.rs @@ -9,12 +9,13 @@ use std::cell::RefCell; use std::fs::File; use std::io::{self, Read, Write}; use std::{mem, slice, str}; +use std::ops::{Deref, DerefMut}; use std::os::unix::io::FromRawFd; use std::rc::Rc; use event::EventQueue; use netutils::{n16, n32, Ipv4, Ipv4Addr, Ipv4Header, Tcp, TcpHeader, Checksum, TCP_FIN, TCP_SYN, TCP_RST, TCP_PSH, TCP_ACK}; -use syscall::data::Packet; +use syscall::data::{Packet, TimeSpec}; use syscall::error::{Error, Result, EACCES, EADDRINUSE, EBADF, EIO, EINVAL, EISCONN, EMSGSIZE, ENOTCONN, EWOULDBLOCK}; use syscall::flag::{EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_CREAT, O_RDWR, O_NONBLOCK}; use syscall::scheme::SchemeMut; @@ -41,11 +42,14 @@ enum State { Closed } -struct Handle { +struct TcpHandle { local: (Ipv4Addr, u16), remote: (Ipv4Addr, u16), flags: usize, events: usize, + read_timeout: Option, + write_timeout: Option, + ttl: u8, state: State, seq: u32, ack: u32, @@ -55,7 +59,7 @@ struct Handle { todo_write: VecDeque, } -impl Handle { +impl TcpHandle { fn is_connected(&self) -> bool { self.remote.0 != Ipv4Addr::NULL && self.remote.1 != 0 } @@ -100,7 +104,7 @@ impl Handle { len: n16::new((data.len() + mem::size_of::()) as u16), id: n16::new(id), flags_fragment: n16::new(0), - ttl: 127, + ttl: self.ttl, proto: 0x06, checksum: Checksum { data: 0 }, src: self.local.0, @@ -112,6 +116,18 @@ impl Handle { } } +#[derive(Copy, Clone)] +enum SettingKind { + Ttl, + ReadTimeout, + WriteTimeout +} + +enum Handle { + Tcp(TcpHandle), + Setting(usize, SettingKind), +} + struct Tcpd { scheme_file: File, tcp_file: File, @@ -144,21 +160,23 @@ impl Tcpd { self.handle(&mut packet); if packet.a == (-EWOULDBLOCK) as usize { if let Some(mut handle) = self.handles.get_mut(&packet.b) { - match a { - syscall::number::SYS_DUP => { - packet.a = a; - handle.todo_dup.push_back(packet); - }, - syscall::number::SYS_READ => { - packet.a = a; - handle.todo_read.push_back(packet); - }, - syscall::number::SYS_WRITE => { - packet.a = a; - handle.todo_write.push_back(packet); - }, - _ => { - self.scheme_file.write(&packet)?; + if let Handle::Tcp(ref mut handle) = *handle { + match a { + syscall::number::SYS_DUP => { + packet.a = a; + handle.todo_dup.push_back(packet); + }, + syscall::number::SYS_READ => { + packet.a = a; + handle.todo_read.push_back(packet); + }, + syscall::number::SYS_WRITE => { + packet.a = a; + handle.todo_write.push_back(packet); + }, + _ => { + self.scheme_file.write(&packet)?; + } } } } @@ -182,46 +200,61 @@ impl Tcpd { let mut closing = Vec::new(); let mut found_connection = false; for (id, handle) in self.handles.iter_mut() { - if handle.state != State::Listen && handle.matches(&ip, &tcp) { - found_connection = true; + if let Handle::Tcp(ref mut handle) = *handle { + if handle.state != State::Listen && handle.matches(&ip, &tcp) { + found_connection = true; - match handle.state { - State::SynReceived => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq { - handle.state = State::Established; - }, - State::SynSent => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_SYN | TCP_ACK && tcp.header.ack_num.get() == handle.seq { - handle.state = State::Established; - handle.ack = tcp.header.sequence.get() + 1; - - let tcp = handle.create_tcp(TCP_ACK, Vec::new()); - let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes())?; - }, - State::Established => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq { - handle.ack = tcp.header.sequence.get(); - - if ! tcp.data.is_empty() { - handle.data.push_back((ip.clone(), tcp.clone())); - handle.ack += tcp.data.len() as u32; + match handle.state { + State::SynReceived => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq { + handle.state = State::Established; + }, + State::SynSent => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_SYN | TCP_ACK && tcp.header.ack_num.get() == handle.seq { + handle.state = State::Established; + handle.ack = tcp.header.sequence.get() + 1; let tcp = handle.create_tcp(TCP_ACK, Vec::new()); let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); self.tcp_file.write(&ip.to_bytes())?; - } else if tcp.header.flags.get() & TCP_FIN == TCP_FIN { - handle.state = State::CloseWait; + }, + State::Established => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq { + handle.ack = tcp.header.sequence.get(); - handle.ack += 1; + if ! tcp.data.is_empty() { + handle.data.push_back((ip.clone(), tcp.clone())); + handle.ack += tcp.data.len() as u32; - let tcp = handle.create_tcp(TCP_ACK, Vec::new()); - let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes())?; - } - }, - //TODO: Time wait - State::FinWait1 => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq { - handle.ack = tcp.header.sequence.get() + 1; + let tcp = handle.create_tcp(TCP_ACK, Vec::new()); + let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); + self.tcp_file.write(&ip.to_bytes())?; + } else if tcp.header.flags.get() & TCP_FIN == TCP_FIN { + handle.state = State::CloseWait; + + handle.ack += 1; + + let tcp = handle.create_tcp(TCP_ACK, Vec::new()); + let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); + self.tcp_file.write(&ip.to_bytes())?; + } + }, + //TODO: Time wait + State::FinWait1 => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq { + handle.ack = tcp.header.sequence.get() + 1; + + if tcp.header.flags.get() & TCP_FIN == TCP_FIN { + handle.state = State::TimeWait; + + let tcp = handle.create_tcp(TCP_ACK, Vec::new()); + let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); + self.tcp_file.write(&ip.to_bytes())?; + + closing.push(*id); + } else { + handle.state = State::FinWait2; + } + }, + State::FinWait2 => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK | TCP_FIN) == TCP_ACK | TCP_FIN && tcp.header.ack_num.get() == handle.seq { + handle.ack = tcp.header.sequence.get() + 1; - if tcp.header.flags.get() & TCP_FIN == TCP_FIN { handle.state = State::TimeWait; let tcp = handle.create_tcp(TCP_ACK, Vec::new()); @@ -229,89 +262,76 @@ impl Tcpd { self.tcp_file.write(&ip.to_bytes())?; closing.push(*id); + }, + State::LastAck => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq { + handle.state = State::Closed; + closing.push(*id); + }, + _ => () + } + + while ! handle.todo_read.is_empty() && (! handle.data.is_empty() || handle.read_closed()) { + let mut packet = handle.todo_read.pop_front().unwrap(); + let buf = unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }; + if let Some((_ip, tcp)) = handle.data.pop_front() { + let mut i = 0; + while i < buf.len() && i < tcp.data.len() { + buf[i] = tcp.data[i]; + i += 1; + } + packet.a = i; } else { - handle.state = State::FinWait2; + packet.a = 0; } - }, - State::FinWait2 => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK | TCP_FIN) == TCP_ACK | TCP_FIN && tcp.header.ack_num.get() == handle.seq { - handle.ack = tcp.header.sequence.get() + 1; - handle.state = State::TimeWait; + self.scheme_file.write(&packet)?; + } - let tcp = handle.create_tcp(TCP_ACK, Vec::new()); + if ! handle.todo_write.is_empty() && handle.state == State::Established { + let mut packet = handle.todo_write.pop_front().unwrap(); + let buf = unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }; + + let tcp = handle.create_tcp(TCP_ACK | TCP_PSH, buf.to_vec()); let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes())?; - - closing.push(*id); - }, - State::LastAck => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq { - handle.state = State::Closed; - closing.push(*id); - }, - _ => () - } - - while ! handle.todo_read.is_empty() && (! handle.data.is_empty() || handle.read_closed()) { - let mut packet = handle.todo_read.pop_front().unwrap(); - let buf = unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }; - if let Some((_ip, tcp)) = handle.data.pop_front() { - let mut i = 0; - while i < buf.len() && i < tcp.data.len() { - buf[i] = tcp.data[i]; - i += 1; + let result = self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))); + if result.is_ok() { + handle.seq += buf.len() as u32; } - packet.a = i; - } else { - packet.a = 0; + packet.a = Error::mux(result.and(Ok(buf.len()))); + + self.scheme_file.write(&packet)?; } - self.scheme_file.write(&packet)?; - } - - if ! handle.todo_write.is_empty() && handle.state == State::Established { - let mut packet = handle.todo_write.pop_front().unwrap(); - let buf = unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }; - - let tcp = handle.create_tcp(TCP_ACK | TCP_PSH, buf.to_vec()); - let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - let result = self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))); - if result.is_ok() { - handle.seq += buf.len() as u32; - } - packet.a = Error::mux(result.and(Ok(buf.len()))); - - self.scheme_file.write(&packet)?; - } - - if handle.events & EVENT_READ == EVENT_READ { - if let Some(&(ref _ip, ref tcp)) = handle.data.get(0) { - self.scheme_file.write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *id, - c: EVENT_READ, - d: tcp.data.len() - })?; + if handle.events & EVENT_READ == EVENT_READ { + if let Some(&(ref _ip, ref tcp)) = handle.data.get(0) { + self.scheme_file.write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: *id, + c: EVENT_READ, + d: tcp.data.len() + })?; + } } } } } for file in closing { - let handle = self.handles.remove(&file).unwrap(); + if let Handle::Tcp(handle) = self.handles.remove(&file).unwrap() { + let remove = if let Some(mut port) = self.ports.get_mut(&handle.local.1) { + *port = *port + 1; + *port == 0 + } else { + false + }; - let remove = if let Some(mut port) = self.ports.get_mut(&handle.local.1) { - *port = *port + 1; - *port == 0 - } else { - false - }; - - if remove { - self.ports.remove(&handle.local.1); + if remove { + self.ports.remove(&handle.local.1); + } } } @@ -319,51 +339,56 @@ impl Tcpd { let mut new_handles = Vec::new(); for (_id, handle) in self.handles.iter_mut() { - if handle.state == State::Listen && handle.matches(&ip, &tcp) { - handle.data.push_back((ip.clone(), tcp.clone())); + if let Handle::Tcp(ref mut handle) = *handle { + if handle.state == State::Listen && handle.matches(&ip, &tcp) { + handle.data.push_back((ip.clone(), tcp.clone())); - while ! handle.todo_dup.is_empty() && ! handle.data.is_empty() { - let mut packet = handle.todo_dup.pop_front().unwrap(); - let (ip, tcp) = handle.data.pop_front().unwrap(); + while ! handle.todo_dup.is_empty() && ! handle.data.is_empty() { + let mut packet = handle.todo_dup.pop_front().unwrap(); + let (ip, tcp) = handle.data.pop_front().unwrap(); - let mut new_handle = Handle { - local: handle.local, - remote: (ip.header.src, tcp.header.src.get()), - flags: handle.flags, - events: 0, - state: State::SynReceived, - seq: self.rng.gen(), - ack: tcp.header.sequence.get() + 1, - data: VecDeque::new(), - todo_dup: VecDeque::new(), - todo_read: VecDeque::new(), - todo_write: VecDeque::new(), - }; + let mut new_handle = TcpHandle { + local: handle.local, + remote: (ip.header.src, tcp.header.src.get()), + flags: handle.flags, + events: 0, + read_timeout: handle.read_timeout, + write_timeout: handle.write_timeout, + ttl: handle.ttl, + state: State::SynReceived, + seq: self.rng.gen(), + ack: tcp.header.sequence.get() + 1, + data: VecDeque::new(), + todo_dup: VecDeque::new(), + todo_read: VecDeque::new(), + todo_write: VecDeque::new(), + }; - let tcp = new_handle.create_tcp(TCP_SYN | TCP_ACK, Vec::new()); - let ip = new_handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes())?; + let tcp = new_handle.create_tcp(TCP_SYN | TCP_ACK, Vec::new()); + let ip = new_handle.create_ip(self.rng.gen(), tcp.to_bytes()); + self.tcp_file.write(&ip.to_bytes())?; - new_handle.seq += 1; + new_handle.seq += 1; - handle.data.retain(|&(ref ip, ref tcp)| { - if new_handle.matches(ip, tcp) { - false - } else { - true + handle.data.retain(|&(ref ip, ref tcp)| { + if new_handle.matches(ip, tcp) { + false + } else { + true + } + }); + + if let Some(mut port) = self.ports.get_mut(&handle.local.1) { + *port = *port + 1; } - }); - if let Some(mut port) = self.ports.get_mut(&handle.local.1) { - *port = *port + 1; + let id = self.next_id; + self.next_id += 1; + + packet.a = id; + + new_handles.push((packet, Handle::Tcp(new_handle))); } - - let id = self.next_id; - self.next_id += 1; - - packet.a = id; - - new_handles.push((packet, new_handle)); } } } @@ -401,11 +426,14 @@ impl SchemeMut for Tcpd { return Err(Error::new(EADDRINUSE)); } - let mut handle = Handle { + let mut handle = TcpHandle { local: local, remote: remote, flags: flags, events: 0, + read_timeout: None, + write_timeout: None, + ttl: 64, state: State::Listen, seq: 0, ack: 0, @@ -432,93 +460,105 @@ impl SchemeMut for Tcpd { let id = self.next_id; self.next_id += 1; - self.handles.insert(id, handle); + self.handles.insert(id, Handle::Tcp(handle)); Ok(id) } fn dup(&mut self, file: usize, buf: &[u8]) -> Result { - let path = str::from_utf8(buf).or(Err(Error::new(EINVAL)))?; + let handle = match *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + Handle::Tcp(ref mut handle) => { + let mut new_handle = TcpHandle { + local: handle.local, + remote: handle.remote, + flags: handle.flags, + events: 0, + read_timeout: handle.read_timeout, + write_timeout: handle.write_timeout, + ttl: handle.ttl, + state: handle.state, + seq: handle.seq, + ack: handle.ack, + data: VecDeque::new(), + todo_dup: VecDeque::new(), + todo_read: VecDeque::new(), + todo_write: VecDeque::new(), + }; - let handle = { - let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?; + let path = str::from_utf8(buf).or(Err(Error::new(EINVAL)))?; - let mut new_handle = Handle { - local: handle.local, - remote: handle.remote, - flags: handle.flags, - events: 0, - state: handle.state, - seq: handle.seq, - ack: handle.ack, - data: VecDeque::new(), - todo_dup: VecDeque::new(), - todo_read: VecDeque::new(), - todo_write: VecDeque::new(), - }; + if path == "ttl" { + Handle::Setting(file, SettingKind::Ttl) + } else if path == "read_timeout" { + Handle::Setting(file, SettingKind::ReadTimeout) + } else if path == "write_timeout" { + Handle::Setting(file, SettingKind::WriteTimeout) + } else if path == "listen" { + if handle.is_connected() { + return Err(Error::new(EISCONN)); + } else if let Some((ip, tcp)) = handle.data.pop_front() { + new_handle.remote = (ip.header.src, tcp.header.src.get()); - if path == "listen" { - if handle.is_connected() { - return Err(Error::new(EISCONN)); - } else if let Some((ip, tcp)) = handle.data.pop_front() { - new_handle.remote = (ip.header.src, tcp.header.src.get()); + new_handle.seq = self.rng.gen(); + new_handle.ack = tcp.header.sequence.get() + 1; + new_handle.state = State::SynReceived; - new_handle.seq = self.rng.gen(); - new_handle.ack = tcp.header.sequence.get() + 1; - new_handle.state = State::SynReceived; + let tcp = new_handle.create_tcp(TCP_SYN | TCP_ACK, Vec::new()); + let ip = new_handle.create_ip(self.rng.gen(), tcp.to_bytes()); + self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))).and(Ok(buf.len()))?; - let tcp = new_handle.create_tcp(TCP_SYN | TCP_ACK, Vec::new()); - let ip = new_handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))).and(Ok(buf.len()))?; - - new_handle.seq += 1; - } else { - return Err(Error::new(EWOULDBLOCK)); - } - - handle.data.retain(|&(ref ip, ref tcp)| { - if new_handle.matches(ip, tcp) { - false + new_handle.seq += 1; } else { - true + return Err(Error::new(EWOULDBLOCK)); } - }); - } else if path.is_empty() { - new_handle.data = handle.data.clone(); - } else if handle.is_connected() { - return Err(Error::new(EISCONN)); - } else { - new_handle.remote = parse_socket(path); - - if new_handle.is_connected() { - new_handle.seq = self.rng.gen(); - new_handle.ack = 0; - new_handle.state = State::SynSent; handle.data.retain(|&(ref ip, ref tcp)| { if new_handle.matches(ip, tcp) { - new_handle.data.push_back((ip.clone(), tcp.clone())); false } else { true } }); - let tcp = new_handle.create_tcp(TCP_SYN, Vec::new()); - let ip = new_handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))).and(Ok(buf.len()))?; + Handle::Tcp(new_handle) + } else if path.is_empty() { + new_handle.data = handle.data.clone(); + + Handle::Tcp(new_handle) + } else if handle.is_connected() { + return Err(Error::new(EISCONN)); } else { - return Err(Error::new(EINVAL)); + new_handle.remote = parse_socket(path); + + if new_handle.is_connected() { + new_handle.seq = self.rng.gen(); + new_handle.ack = 0; + new_handle.state = State::SynSent; + + handle.data.retain(|&(ref ip, ref tcp)| { + if new_handle.matches(ip, tcp) { + new_handle.data.push_back((ip.clone(), tcp.clone())); + false + } else { + true + } + }); + + let tcp = new_handle.create_tcp(TCP_SYN, Vec::new()); + let ip = new_handle.create_ip(self.rng.gen(), tcp.to_bytes()); + self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))).and(Ok(buf.len()))?; + + Handle::Tcp(new_handle) + } else { + return Err(Error::new(EINVAL)); + } } + }, + Handle::Setting(file, kind) => { + Handle::Setting(file, kind) } - - new_handle }; - if let Some(mut port) = self.ports.get_mut(&handle.local.1) { - *port = *port + 1; - } - let id = self.next_id; self.next_id += 1; @@ -528,82 +568,159 @@ impl SchemeMut for Tcpd { } fn read(&mut self, file: usize, buf: &mut [u8]) -> Result { - let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?; + let (file, kind) = match *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + Handle::Tcp(ref mut handle) => { + if ! handle.is_connected() { + return Err(Error::new(ENOTCONN)); + } else if let Some((_ip, tcp)) = handle.data.pop_front() { + let mut i = 0; + while i < buf.len() && i < tcp.data.len() { + buf[i] = tcp.data[i]; + i += 1; + } - if ! handle.is_connected() { - Err(Error::new(ENOTCONN)) - } else if let Some((_ip, tcp)) = handle.data.pop_front() { - let mut i = 0; - while i < buf.len() && i < tcp.data.len() { - buf[i] = tcp.data[i]; - i += 1; + return Ok(i); + } else if handle.flags & O_NONBLOCK == O_NONBLOCK || handle.read_closed() { + return Ok(0); + } else { + return Err(Error::new(EWOULDBLOCK)); + } + }, + Handle::Setting(file, kind) => { + (file, kind) } + }; - Ok(i) - } else if handle.flags & O_NONBLOCK == O_NONBLOCK || handle.read_closed() { - Ok(0) + if let Handle::Tcp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + let read_timeout = |timeout: &Option, buf: &mut [u8]| -> Result { + if let Some(ref timespec) = *timeout { + timespec.deref().read(buf).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))) + } else { + Ok(0) + } + }; + + match kind { + SettingKind::Ttl => { + if let Some(mut ttl) = buf.get_mut(0) { + *ttl = handle.ttl; + Ok(1) + } else { + Ok(0) + } + }, + SettingKind::ReadTimeout => { + read_timeout(&handle.read_timeout, buf) + }, + SettingKind::WriteTimeout => { + read_timeout(&handle.write_timeout, buf) + } + } } else { - Err(Error::new(EWOULDBLOCK)) + Err(Error::new(EBADF)) } } fn write(&mut self, file: usize, buf: &[u8]) -> Result { - let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?; + let (file, kind) = match *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + Handle::Tcp(ref mut handle) => { + if ! handle.is_connected() { + return Err(Error::new(ENOTCONN)); + } else if buf.len() >= 65507 { + return Err(Error::new(EMSGSIZE)); + } else { + match handle.state { + State::Established => { + let tcp = handle.create_tcp(TCP_ACK | TCP_PSH, buf.to_vec()); + let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); + self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; + handle.seq += buf.len() as u32; + return Ok(buf.len()); + }, + _ => { + return Err(Error::new(EWOULDBLOCK)); + } + } + } + }, + Handle::Setting(file, kind) => { + (file, kind) + } + }; - if ! handle.is_connected() { - Err(Error::new(ENOTCONN)) - } else if buf.len() >= 65507 { - Err(Error::new(EMSGSIZE)) - } else { - match handle.state { - State::Established => { - let tcp = handle.create_tcp(TCP_ACK | TCP_PSH, buf.to_vec()); - let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; - handle.seq += buf.len() as u32; - Ok(buf.len()) + if let Handle::Tcp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + let write_timeout = |timeout: &mut Option, buf: &[u8]| -> Result { + if buf.len() >= mem::size_of::() { + let mut timespec = TimeSpec::default(); + let count = timespec.deref_mut().write(buf).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; + *timeout = Some(timespec); + Ok(count) + } else { + *timeout = None; + Ok(0) + } + }; + + match kind { + SettingKind::Ttl => { + if let Some(ttl) = buf.get(0) { + handle.ttl = *ttl; + Ok(1) + } else { + Ok(0) + } }, - _ => { - Err(Error::new(EWOULDBLOCK)) + SettingKind::ReadTimeout => { + write_timeout(&mut handle.read_timeout, buf) + }, + SettingKind::WriteTimeout => { + write_timeout(&mut handle.write_timeout, buf) } } + } else { + Err(Error::new(EBADF)) } } fn fcntl(&mut self, file: usize, cmd: usize, arg: usize) -> Result { - let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?; - - match cmd { - F_GETFL => Ok(handle.flags), - F_SETFL => { - handle.flags = arg & ! O_ACCMODE; - Ok(0) - }, - _ => Err(Error::new(EINVAL)) + if let Handle::Tcp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + match cmd { + F_GETFL => Ok(handle.flags), + F_SETFL => { + handle.flags = arg & ! O_ACCMODE; + Ok(0) + }, + _ => Err(Error::new(EINVAL)) + } + } else { + Err(Error::new(EBADF)) } } fn fevent(&mut self, file: usize, flags: usize) -> Result { - let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?; - - handle.events = flags; - - Ok(file) + if let Handle::Tcp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + handle.events = flags; + Ok(file) + } else { + Err(Error::new(EBADF)) + } } - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + fn fpath(&mut self, file: usize, buf: &mut [u8]) -> Result { + if let Handle::Tcp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + let path_string = format!("udp:{}:{}/{}:{}", handle.remote.0.to_string(), handle.remote.1, handle.local.0.to_string(), handle.local.1); + let path = path_string.as_bytes(); - let path_string = format!("tcp:{}:{}/{}:{}", handle.remote.0.to_string(), handle.remote.1, handle.local.0.to_string(), handle.local.1); - let path = path_string.as_bytes(); + let mut i = 0; + while i < buf.len() && i < path.len() { + buf[i] = path[i]; + i += 1; + } - let mut i = 0; - while i < buf.len() && i < path.len() { - buf[i] = path[i]; - i += 1; + Ok(i) + } else { + Err(Error::new(EBADF)) } - - Ok(i) } fn fsync(&mut self, file: usize) -> Result { @@ -614,49 +731,51 @@ impl SchemeMut for Tcpd { fn close(&mut self, file: usize) -> Result { let closed = { - let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?; + if let Handle::Tcp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + handle.data.clear(); - handle.data.clear(); + match handle.state { + State::SynReceived | State::Established => { + handle.state = State::FinWait1; - match handle.state { - State::SynReceived | State::Established => { - handle.state = State::FinWait1; + let tcp = handle.create_tcp(TCP_FIN | TCP_ACK, Vec::new()); + let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); + self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; - let tcp = handle.create_tcp(TCP_FIN | TCP_ACK, Vec::new()); - let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; + handle.seq += 1; - handle.seq += 1; + false + }, + State::CloseWait => { + handle.state = State::LastAck; - false - }, - State::CloseWait => { - handle.state = State::LastAck; + let tcp = handle.create_tcp(TCP_FIN | TCP_ACK, Vec::new()); + let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); + self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; - let tcp = handle.create_tcp(TCP_FIN | TCP_ACK, Vec::new()); - let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; + handle.seq += 1; - handle.seq += 1; - - false - }, - _ => true + false + }, + _ => true + } + } else { + true } }; if closed { - let handle = self.handles.remove(&file).ok_or(Error::new(EBADF))?; + if let Handle::Tcp(handle) = self.handles.remove(&file).ok_or(Error::new(EBADF))? { + let remove = if let Some(mut port) = self.ports.get_mut(&handle.local.1) { + *port = *port + 1; + *port == 0 + } else { + false + }; - let remove = if let Some(mut port) = self.ports.get_mut(&handle.local.1) { - *port = *port + 1; - *port == 0 - } else { - false - }; - - if remove { - self.ports.remove(&handle.local.1); + if remove { + self.ports.remove(&handle.local.1); + } } }