Orbital (#16)
* Port previous ethernet scheme * Add ipd * Fix initfs rebuilds, use QEMU user networking addresses in ipd * Add tcp/udp, netutils, dns, and network config * Add fsync to network driver * Add dns, router, subnet by default * Fix e1000 driver. Make ethernet and IP non-blocking to avoid deadlocks * Add orbital server, WIP * Add futex * Add orbutils and orbital * Update libstd, orbutils, and orbital Move ANSI key encoding to vesad * Add orbital assets * Update orbital * Update to add login manager * Add blocking primitives, block for most things except waitpid, update orbital * Wait in waitpid and IRQ, improvements for other waits * Fevent in root scheme * WIP: Switch to using fevent * Reorganize * Event based e1000d driver * Superuser-only access to some network schemes, display, and disk * Superuser root and irq schemes * Fix orbital
This commit is contained in:
parent
372d44f88c
commit
224c43f761
92 changed files with 3415 additions and 473 deletions
7
schemes/ethernetd/Cargo.toml
Normal file
7
schemes/ethernetd/Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "ethernetd"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
resource_scheme = { path = "../../crates/resource_scheme/" }
|
||||
syscall = { path = "../../syscall/" }
|
105
schemes/ethernetd/src/common.rs
Normal file
105
schemes/ethernetd/src/common.rs
Normal file
|
@ -0,0 +1,105 @@
|
|||
use std::{mem, slice, u8, u16};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(packed)]
|
||||
pub struct n16(u16);
|
||||
|
||||
impl n16 {
|
||||
pub fn new(value: u16) -> Self {
|
||||
n16(value.to_be())
|
||||
}
|
||||
|
||||
pub fn get(&self) -> u16 {
|
||||
u16::from_be(self.0)
|
||||
}
|
||||
|
||||
pub fn set(&mut self, value: u16) {
|
||||
self.0 = value.to_be();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct MacAddr {
|
||||
pub bytes: [u8; 6],
|
||||
}
|
||||
|
||||
impl MacAddr {
|
||||
pub fn equals(&self, other: Self) -> bool {
|
||||
for i in 0..6 {
|
||||
if self.bytes[i] != other.bytes[i] {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn from_str(string: &str) -> Self {
|
||||
let mut addr = MacAddr { bytes: [0, 0, 0, 0, 0, 0] };
|
||||
|
||||
let mut i = 0;
|
||||
for part in string.split('.') {
|
||||
let octet = u8::from_str_radix(part, 16).unwrap_or(0);
|
||||
match i {
|
||||
0 => addr.bytes[0] = octet,
|
||||
1 => addr.bytes[1] = octet,
|
||||
2 => addr.bytes[2] = octet,
|
||||
3 => addr.bytes[3] = octet,
|
||||
4 => addr.bytes[4] = octet,
|
||||
5 => addr.bytes[5] = octet,
|
||||
_ => break,
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
addr
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
let mut string = String::new();
|
||||
for i in 0..6 {
|
||||
if i > 0 {
|
||||
string.push('.');
|
||||
}
|
||||
string.push_str(&format!("{:X}", self.bytes[i]));
|
||||
}
|
||||
string
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(packed)]
|
||||
pub struct EthernetIIHeader {
|
||||
pub dst: MacAddr,
|
||||
pub src: MacAddr,
|
||||
pub ethertype: n16,
|
||||
}
|
||||
|
||||
pub struct EthernetII {
|
||||
pub header: EthernetIIHeader,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl EthernetII {
|
||||
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
|
||||
if bytes.len() >= mem::size_of::<EthernetIIHeader>() {
|
||||
unsafe {
|
||||
return Some(EthernetII {
|
||||
header: *(bytes.as_ptr() as *const EthernetIIHeader),
|
||||
data: bytes[mem::size_of::<EthernetIIHeader>() ..].to_vec(),
|
||||
});
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
unsafe {
|
||||
let header_ptr: *const EthernetIIHeader = &self.header;
|
||||
let mut ret = Vec::from(slice::from_raw_parts(header_ptr as *const u8,
|
||||
mem::size_of::<EthernetIIHeader>()));
|
||||
ret.extend_from_slice(&self.data);
|
||||
ret
|
||||
}
|
||||
}
|
||||
}
|
28
schemes/ethernetd/src/main.rs
Normal file
28
schemes/ethernetd/src/main.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
extern crate resource_scheme;
|
||||
extern crate syscall;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::thread;
|
||||
|
||||
use resource_scheme::ResourceScheme;
|
||||
use syscall::Packet;
|
||||
|
||||
use scheme::EthernetScheme;
|
||||
|
||||
pub mod common;
|
||||
pub mod resource;
|
||||
pub mod scheme;
|
||||
|
||||
fn main() {
|
||||
thread::spawn(move || {
|
||||
let mut socket = File::create(":ethernet").expect("ethernetd: failed to create ethernet scheme");
|
||||
let scheme = EthernetScheme;
|
||||
loop {
|
||||
let mut packet = Packet::default();
|
||||
socket.read(&mut packet).expect("ethernetd: failed to read events from ethernet scheme");
|
||||
scheme.handle(&mut packet);
|
||||
socket.write(&packet).expect("ethernetd: failed to write responses to ethernet scheme");
|
||||
}
|
||||
});
|
||||
}
|
97
schemes/ethernetd/src/resource.rs
Normal file
97
schemes/ethernetd/src/resource.rs
Normal file
|
@ -0,0 +1,97 @@
|
|||
use std::{cmp, mem};
|
||||
|
||||
use resource_scheme::Resource;
|
||||
use syscall;
|
||||
use syscall::error::*;
|
||||
|
||||
use common::{n16, MacAddr, EthernetIIHeader, EthernetII};
|
||||
|
||||
/// A ethernet resource
|
||||
pub struct EthernetResource {
|
||||
/// The network
|
||||
pub network: usize,
|
||||
/// The data
|
||||
pub data: Vec<u8>,
|
||||
/// The MAC addresss
|
||||
pub peer_addr: MacAddr,
|
||||
/// The ethernet type
|
||||
pub ethertype: u16,
|
||||
}
|
||||
|
||||
impl Resource for EthernetResource {
|
||||
fn dup(&self) -> Result<Box<Self>> {
|
||||
let network = try!(syscall::dup(self.network));
|
||||
Ok(Box::new(EthernetResource {
|
||||
network: network,
|
||||
data: self.data.clone(),
|
||||
peer_addr: self.peer_addr,
|
||||
ethertype: self.ethertype,
|
||||
}))
|
||||
}
|
||||
|
||||
fn path(&self, buf: &mut [u8]) -> Result<usize> {
|
||||
let path_string = format!("ethernet:{}/{:X}", self.peer_addr.to_string(), self.ethertype);
|
||||
let path = path_string.as_bytes();
|
||||
|
||||
for (b, p) in buf.iter_mut().zip(path.iter()) {
|
||||
*b = *p;
|
||||
}
|
||||
|
||||
Ok(cmp::min(buf.len(), path.len()))
|
||||
}
|
||||
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
if !self.data.is_empty() {
|
||||
let mut data: Vec<u8> = Vec::new();
|
||||
mem::swap(&mut self.data, &mut data);
|
||||
|
||||
for (b, d) in buf.iter_mut().zip(data.iter()) {
|
||||
*b = *d;
|
||||
}
|
||||
|
||||
return Ok(cmp::min(buf.len(), data.len()));
|
||||
}
|
||||
|
||||
let mut bytes = [0; 65536];
|
||||
let count = try!(syscall::read(self.network, &mut bytes));
|
||||
|
||||
if let Some(frame) = EthernetII::from_bytes(&bytes[..count]) {
|
||||
if frame.header.ethertype.get() == self.ethertype {
|
||||
for (b, d) in buf.iter_mut().zip(frame.data.iter()) {
|
||||
*b = *d;
|
||||
}
|
||||
|
||||
return Ok(cmp::min(buf.len(), frame.data.len()));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
let data = Vec::from(buf);
|
||||
|
||||
match syscall::write(self.network, &EthernetII {
|
||||
header: EthernetIIHeader {
|
||||
src: MacAddr { bytes: [0x50, 0x51, 0x52, 0x53, 0x54, 0x55] },
|
||||
dst: self.peer_addr,
|
||||
ethertype: n16::new(self.ethertype),
|
||||
},
|
||||
data: data,
|
||||
}
|
||||
.to_bytes()) {
|
||||
Ok(_) => Ok(buf.len()),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
fn sync(&mut self) -> Result<usize> {
|
||||
syscall::fsync(self.network)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for EthernetResource {
|
||||
fn drop(&mut self) {
|
||||
let _ = syscall::close(self.network);
|
||||
}
|
||||
}
|
65
schemes/ethernetd/src/scheme.rs
Normal file
65
schemes/ethernetd/src/scheme.rs
Normal file
|
@ -0,0 +1,65 @@
|
|||
use std::{str, u16};
|
||||
|
||||
use resource_scheme::ResourceScheme;
|
||||
use syscall;
|
||||
use syscall::error::{Error, Result, EACCES, ENOENT, EINVAL};
|
||||
use syscall::flag::O_RDWR;
|
||||
|
||||
use common::{MacAddr, EthernetII};
|
||||
use resource::EthernetResource;
|
||||
|
||||
pub struct EthernetScheme;
|
||||
|
||||
impl ResourceScheme<EthernetResource> for EthernetScheme {
|
||||
fn open_resource(&self, url: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result<Box<EthernetResource>> {
|
||||
if uid == 0 {
|
||||
let path = try!(str::from_utf8(url).or(Err(Error::new(EINVAL))));
|
||||
let mut parts = path.split("/");
|
||||
if let Some(host_string) = parts.next() {
|
||||
if let Some(ethertype_string) = parts.next() {
|
||||
if let Ok(network) = syscall::open("network:", O_RDWR) {
|
||||
let ethertype = u16::from_str_radix(ethertype_string, 16).unwrap_or(0) as u16;
|
||||
|
||||
if !host_string.is_empty() {
|
||||
return Ok(Box::new(EthernetResource {
|
||||
network: network,
|
||||
data: Vec::new(),
|
||||
peer_addr: MacAddr::from_str(host_string),
|
||||
ethertype: ethertype,
|
||||
}));
|
||||
} else {
|
||||
loop {
|
||||
let mut bytes = [0; 65536];
|
||||
match syscall::read(network, &mut bytes) {
|
||||
Ok(count) => {
|
||||
if let Some(frame) = EthernetII::from_bytes(&bytes[..count]) {
|
||||
if frame.header.ethertype.get() == ethertype {
|
||||
return Ok(Box::new(EthernetResource {
|
||||
network: network,
|
||||
data: frame.data,
|
||||
peer_addr: frame.header.src,
|
||||
ethertype: ethertype,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("Ethernet: Failed to open network:");
|
||||
}
|
||||
} else {
|
||||
println!("Ethernet: No ethertype provided");
|
||||
}
|
||||
} else {
|
||||
println!("Ethernet: No host provided");
|
||||
}
|
||||
|
||||
Err(Error::new(ENOENT))
|
||||
} else {
|
||||
Err(Error::new(EACCES))
|
||||
}
|
||||
}
|
||||
}
|
7
schemes/ipd/Cargo.toml
Normal file
7
schemes/ipd/Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "ipd"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
resource_scheme = { path = "../../crates/resource_scheme/" }
|
||||
syscall = { path = "../../syscall/" }
|
275
schemes/ipd/src/common.rs
Normal file
275
schemes/ipd/src/common.rs
Normal file
|
@ -0,0 +1,275 @@
|
|||
use std::{mem, slice, u8, u16};
|
||||
|
||||
pub static mut MAC_ADDR: MacAddr = MacAddr { bytes: [0x50, 0x51, 0x52, 0x53, 0x54, 0x55] };
|
||||
pub static BROADCAST_MAC_ADDR: MacAddr = MacAddr { bytes: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] };
|
||||
|
||||
pub static mut IP_ADDR: Ipv4Addr = Ipv4Addr { bytes: [10, 0, 2, 15] };
|
||||
pub static mut IP_ROUTER_ADDR: Ipv4Addr = Ipv4Addr { bytes: [10, 0, 2, 2] };
|
||||
pub static mut IP_SUBNET: Ipv4Addr = Ipv4Addr { bytes: [255, 255, 255, 0] };
|
||||
pub static BROADCAST_IP_ADDR: Ipv4Addr = Ipv4Addr { bytes: [255, 255, 255, 255] };
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(packed)]
|
||||
pub struct n16(u16);
|
||||
|
||||
impl n16 {
|
||||
pub fn new(value: u16) -> Self {
|
||||
n16(value.to_be())
|
||||
}
|
||||
|
||||
pub fn get(&self) -> u16 {
|
||||
u16::from_be(self.0)
|
||||
}
|
||||
|
||||
pub fn set(&mut self, value: u16) {
|
||||
self.0 = value.to_be();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct MacAddr {
|
||||
pub bytes: [u8; 6],
|
||||
}
|
||||
|
||||
impl MacAddr {
|
||||
pub fn equals(&self, other: Self) -> bool {
|
||||
for i in 0..6 {
|
||||
if self.bytes[i] != other.bytes[i] {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn from_str(string: &str) -> Self {
|
||||
let mut addr = MacAddr { bytes: [0, 0, 0, 0, 0, 0] };
|
||||
|
||||
let mut i = 0;
|
||||
for part in string.split('.') {
|
||||
let octet = u8::from_str_radix(part, 16).unwrap_or(0);
|
||||
match i {
|
||||
0 => addr.bytes[0] = octet,
|
||||
1 => addr.bytes[1] = octet,
|
||||
2 => addr.bytes[2] = octet,
|
||||
3 => addr.bytes[3] = octet,
|
||||
4 => addr.bytes[4] = octet,
|
||||
5 => addr.bytes[5] = octet,
|
||||
_ => break,
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
addr
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
let mut string = String::new();
|
||||
for i in 0..6 {
|
||||
if i > 0 {
|
||||
string.push('.');
|
||||
}
|
||||
string.push_str(&format!("{:X}", self.bytes[i]));
|
||||
}
|
||||
string
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Ipv4Addr {
|
||||
pub bytes: [u8; 4],
|
||||
}
|
||||
|
||||
impl Ipv4Addr {
|
||||
pub fn equals(&self, other: Self) -> bool {
|
||||
for i in 0..4 {
|
||||
if self.bytes[i] != other.bytes[i] {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn from_str(string: &str) -> Self {
|
||||
let mut addr = Ipv4Addr { bytes: [0, 0, 0, 0] };
|
||||
|
||||
let mut i = 0;
|
||||
for part in string.split('.') {
|
||||
let octet = part.parse::<u8>().unwrap_or(0);
|
||||
match i {
|
||||
0 => addr.bytes[0] = octet,
|
||||
1 => addr.bytes[1] = octet,
|
||||
2 => addr.bytes[2] = octet,
|
||||
3 => addr.bytes[3] = octet,
|
||||
_ => break,
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
addr
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
let mut string = String::new();
|
||||
|
||||
for i in 0..4 {
|
||||
if i > 0 {
|
||||
string = string + ".";
|
||||
}
|
||||
string = string + &format!("{}", self.bytes[i]);
|
||||
}
|
||||
|
||||
string
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Checksum {
|
||||
pub data: u16,
|
||||
}
|
||||
|
||||
impl Checksum {
|
||||
pub unsafe fn check(&self, mut ptr: usize, mut len: usize) -> bool {
|
||||
let mut sum: usize = 0;
|
||||
while len > 1 {
|
||||
sum += *(ptr as *const u16) as usize;
|
||||
len -= 2;
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
if len > 0 {
|
||||
sum += *(ptr as *const u8) as usize;
|
||||
}
|
||||
|
||||
while (sum >> 16) > 0 {
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
}
|
||||
|
||||
sum == 0xFFFF
|
||||
}
|
||||
|
||||
pub unsafe fn calculate(&mut self, ptr: usize, len: usize) {
|
||||
self.data = 0;
|
||||
|
||||
let sum = Checksum::sum(ptr, len);
|
||||
|
||||
self.data = Checksum::compile(sum);
|
||||
}
|
||||
|
||||
pub unsafe fn sum(mut ptr: usize, mut len: usize) -> usize {
|
||||
let mut sum = 0;
|
||||
|
||||
while len > 1 {
|
||||
sum += *(ptr as *const u16) as usize;
|
||||
len -= 2;
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
if len > 0 {
|
||||
sum += *(ptr as *const u8) as usize;
|
||||
}
|
||||
|
||||
sum
|
||||
}
|
||||
|
||||
pub fn compile(mut sum: usize) -> u16 {
|
||||
while (sum >> 16) > 0 {
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
}
|
||||
|
||||
0xFFFF - (sum as u16)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(packed)]
|
||||
pub struct ArpHeader {
|
||||
pub htype: n16,
|
||||
pub ptype: n16,
|
||||
pub hlen: u8,
|
||||
pub plen: u8,
|
||||
pub oper: n16,
|
||||
pub src_mac: MacAddr,
|
||||
pub src_ip: Ipv4Addr,
|
||||
pub dst_mac: MacAddr,
|
||||
pub dst_ip: Ipv4Addr,
|
||||
}
|
||||
|
||||
pub struct Arp {
|
||||
pub header: ArpHeader,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Arp {
|
||||
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
|
||||
if bytes.len() >= mem::size_of::<ArpHeader>() {
|
||||
unsafe {
|
||||
return Some(Arp {
|
||||
header: *(bytes.as_ptr() as *const ArpHeader),
|
||||
data: bytes[mem::size_of::<ArpHeader>() ..].to_vec(),
|
||||
});
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
unsafe {
|
||||
let header_ptr: *const ArpHeader = &self.header;
|
||||
let mut ret = Vec::from(slice::from_raw_parts(header_ptr as *const u8,
|
||||
mem::size_of::<ArpHeader>()));
|
||||
ret.extend_from_slice(&self.data);
|
||||
ret
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(packed)]
|
||||
pub struct Ipv4Header {
|
||||
pub ver_hlen: u8,
|
||||
pub services: u8,
|
||||
pub len: n16,
|
||||
pub id: n16,
|
||||
pub flags_fragment: n16,
|
||||
pub ttl: u8,
|
||||
pub proto: u8,
|
||||
pub checksum: Checksum,
|
||||
pub src: Ipv4Addr,
|
||||
pub dst: Ipv4Addr,
|
||||
}
|
||||
|
||||
pub struct Ipv4 {
|
||||
pub header: Ipv4Header,
|
||||
pub options: Vec<u8>,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Ipv4 {
|
||||
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
|
||||
if bytes.len() >= mem::size_of::<Ipv4Header>() {
|
||||
unsafe {
|
||||
let header = *(bytes.as_ptr() as *const Ipv4Header);
|
||||
let header_len = ((header.ver_hlen & 0xF) << 2) as usize;
|
||||
|
||||
return Some(Ipv4 {
|
||||
header: header,
|
||||
options: bytes[mem::size_of::<Ipv4Header>() .. header_len].to_vec(),
|
||||
data: bytes[header_len .. header.len.get() as usize].to_vec(),
|
||||
});
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
unsafe {
|
||||
let header_ptr: *const Ipv4Header = &self.header;
|
||||
let mut ret = Vec::<u8>::from(slice::from_raw_parts(header_ptr as *const u8,
|
||||
mem::size_of::<Ipv4Header>()));
|
||||
ret.extend_from_slice(&self.options);
|
||||
ret.extend_from_slice(&self.data);
|
||||
ret
|
||||
}
|
||||
}
|
||||
}
|
30
schemes/ipd/src/main.rs
Normal file
30
schemes/ipd/src/main.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
#![feature(rand)]
|
||||
|
||||
extern crate resource_scheme;
|
||||
extern crate syscall;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::thread;
|
||||
|
||||
use resource_scheme::ResourceScheme;
|
||||
use syscall::Packet;
|
||||
|
||||
use scheme::IpScheme;
|
||||
|
||||
pub mod common;
|
||||
pub mod resource;
|
||||
pub mod scheme;
|
||||
|
||||
fn main() {
|
||||
thread::spawn(move || {
|
||||
let mut socket = File::create(":ip").expect("ipd: failed to create ip scheme");
|
||||
let scheme = IpScheme::new();
|
||||
loop {
|
||||
let mut packet = Packet::default();
|
||||
socket.read(&mut packet).expect("ipd: failed to read events from ip scheme");
|
||||
scheme.handle(&mut packet);
|
||||
socket.write(&packet).expect("ipd: failed to write responses to ip scheme");
|
||||
}
|
||||
});
|
||||
}
|
114
schemes/ipd/src/resource.rs
Normal file
114
schemes/ipd/src/resource.rs
Normal file
|
@ -0,0 +1,114 @@
|
|||
use std::{cmp, mem};
|
||||
|
||||
use resource_scheme::Resource;
|
||||
use syscall;
|
||||
use syscall::error::*;
|
||||
|
||||
use common::{n16, Ipv4Addr, Checksum, Ipv4Header, Ipv4, IP_ADDR, BROADCAST_IP_ADDR};
|
||||
|
||||
/// A IP (internet protocole) resource
|
||||
pub struct IpResource {
|
||||
pub link: usize,
|
||||
pub data: Vec<u8>,
|
||||
pub peer_addr: Ipv4Addr,
|
||||
pub proto: u8,
|
||||
pub id: u16,
|
||||
}
|
||||
|
||||
impl Resource for IpResource {
|
||||
fn dup(&self) -> Result<Box<Self>> {
|
||||
let link = try!(syscall::dup(self.link));
|
||||
Ok(Box::new(IpResource {
|
||||
link: link,
|
||||
data: self.data.clone(),
|
||||
peer_addr: self.peer_addr,
|
||||
proto: self.proto,
|
||||
id: self.id,
|
||||
}))
|
||||
}
|
||||
|
||||
fn path(&self, buf: &mut [u8]) -> Result<usize> {
|
||||
let path_string = format!("ip:{}/{:X}", self.peer_addr.to_string(), self.proto);
|
||||
let path = path_string.as_bytes();
|
||||
|
||||
for (b, p) in buf.iter_mut().zip(path.iter()) {
|
||||
*b = *p;
|
||||
}
|
||||
|
||||
Ok(cmp::min(buf.len(), path.len()))
|
||||
}
|
||||
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
if !self.data.is_empty() {
|
||||
let mut data: Vec<u8> = Vec::new();
|
||||
mem::swap(&mut self.data, &mut data);
|
||||
|
||||
for (b, d) in buf.iter_mut().zip(data.iter()) {
|
||||
*b = *d;
|
||||
}
|
||||
|
||||
return Ok(cmp::min(buf.len(), data.len()));
|
||||
}
|
||||
|
||||
let mut bytes = [0; 65536];
|
||||
let count = try!(syscall::read(self.link, &mut bytes));
|
||||
|
||||
if let Some(packet) = Ipv4::from_bytes(&bytes[..count]) {
|
||||
if packet.header.proto == self.proto &&
|
||||
(packet.header.dst.equals(unsafe { IP_ADDR }) || packet.header.dst.equals(BROADCAST_IP_ADDR)) &&
|
||||
(packet.header.src.equals(self.peer_addr) || self.peer_addr.equals(BROADCAST_IP_ADDR)) {
|
||||
for (b, d) in buf.iter_mut().zip(packet.data.iter()) {
|
||||
*b = *d;
|
||||
}
|
||||
|
||||
return Ok(cmp::min(buf.len(), packet.data.len()));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
let ip_data = Vec::from(buf);
|
||||
|
||||
self.id += 1;
|
||||
let mut ip = Ipv4 {
|
||||
header: Ipv4Header {
|
||||
ver_hlen: 0x40 | (mem::size_of::<Ipv4Header>() / 4 & 0xF) as u8, // No Options
|
||||
services: 0,
|
||||
len: n16::new((mem::size_of::<Ipv4Header>() + ip_data.len()) as u16), // No Options
|
||||
id: n16::new(self.id),
|
||||
flags_fragment: n16::new(0),
|
||||
ttl: 128,
|
||||
proto: self.proto,
|
||||
checksum: Checksum { data: 0 },
|
||||
src: unsafe { IP_ADDR },
|
||||
dst: self.peer_addr,
|
||||
},
|
||||
options: Vec::new(),
|
||||
data: ip_data,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let header_ptr: *const Ipv4Header = &ip.header;
|
||||
ip.header.checksum.data =
|
||||
Checksum::compile(Checksum::sum(header_ptr as usize, mem::size_of::<Ipv4Header>()) +
|
||||
Checksum::sum(ip.options.as_ptr() as usize, ip.options.len()));
|
||||
}
|
||||
|
||||
match syscall::write(self.link, &ip.to_bytes()) {
|
||||
Ok(_) => Ok(buf.len()),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
fn sync(&mut self) -> Result<usize> {
|
||||
syscall::fsync(self.link)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for IpResource {
|
||||
fn drop(&mut self) {
|
||||
let _ = syscall::close(self.link);
|
||||
}
|
||||
}
|
155
schemes/ipd/src/scheme.rs
Normal file
155
schemes/ipd/src/scheme.rs
Normal file
|
@ -0,0 +1,155 @@
|
|||
use std::cell::RefCell;
|
||||
use std::rand;
|
||||
use std::{str, u16};
|
||||
|
||||
use resource_scheme::ResourceScheme;
|
||||
use syscall;
|
||||
use syscall::error::{Error, Result, EACCES, ENOENT, EINVAL};
|
||||
use syscall::flag::O_RDWR;
|
||||
|
||||
use common::{n16, MacAddr, Ipv4Addr, ArpHeader, Arp, Ipv4, MAC_ADDR, BROADCAST_MAC_ADDR, BROADCAST_IP_ADDR, IP_ADDR, IP_ROUTER_ADDR, IP_SUBNET};
|
||||
use resource::IpResource;
|
||||
|
||||
/// A ARP entry (MAC + IP)
|
||||
pub struct ArpEntry {
|
||||
ip: Ipv4Addr,
|
||||
mac: MacAddr,
|
||||
}
|
||||
|
||||
/// A IP scheme
|
||||
pub struct IpScheme {
|
||||
pub arp: RefCell<Vec<ArpEntry>>,
|
||||
}
|
||||
|
||||
impl IpScheme {
|
||||
pub fn new() -> IpScheme {
|
||||
IpScheme {
|
||||
arp: RefCell::new(Vec::new())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceScheme<IpResource> for IpScheme {
|
||||
fn open_resource(&self, url: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result<Box<IpResource>> {
|
||||
if uid == 0 {
|
||||
let path = try!(str::from_utf8(url).or(Err(Error::new(EINVAL))));
|
||||
let mut parts = path.split('/');
|
||||
if let Some(host_string) = parts.next() {
|
||||
if let Some(proto_string) = parts.next() {
|
||||
let proto = u8::from_str_radix(proto_string, 16).unwrap_or(0);
|
||||
|
||||
if ! host_string.is_empty() {
|
||||
let peer_addr = Ipv4Addr::from_str(host_string);
|
||||
let mut route_mac = BROADCAST_MAC_ADDR;
|
||||
|
||||
if ! peer_addr.equals(BROADCAST_IP_ADDR) {
|
||||
let mut needs_routing = false;
|
||||
|
||||
for octet in 0..4 {
|
||||
let me = unsafe { IP_ADDR.bytes[octet] };
|
||||
let mask = unsafe { IP_SUBNET.bytes[octet] };
|
||||
let them = peer_addr.bytes[octet];
|
||||
if me & mask != them & mask {
|
||||
needs_routing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let route_addr = if needs_routing {
|
||||
unsafe { IP_ROUTER_ADDR }
|
||||
} else {
|
||||
peer_addr
|
||||
};
|
||||
|
||||
for entry in self.arp.borrow().iter() {
|
||||
if entry.ip.equals(route_addr) {
|
||||
route_mac = entry.mac;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if route_mac.equals(BROADCAST_MAC_ADDR) {
|
||||
if let Ok(link) = syscall::open(&format!("ethernet:{}/806", &route_mac.to_string()), O_RDWR) {
|
||||
let arp = Arp {
|
||||
header: ArpHeader {
|
||||
htype: n16::new(1),
|
||||
ptype: n16::new(0x800),
|
||||
hlen: 6,
|
||||
plen: 4,
|
||||
oper: n16::new(1),
|
||||
src_mac: unsafe { MAC_ADDR },
|
||||
src_ip: unsafe { IP_ADDR },
|
||||
dst_mac: route_mac,
|
||||
dst_ip: route_addr,
|
||||
},
|
||||
data: Vec::new(),
|
||||
};
|
||||
|
||||
match syscall::write(link, &arp.to_bytes()) {
|
||||
Ok(_) => loop {
|
||||
let mut bytes = [0; 65536];
|
||||
match syscall::read(link, &mut bytes) {
|
||||
Ok(count) => if let Some(packet) = Arp::from_bytes(&bytes[..count]) {
|
||||
if packet.header.oper.get() == 2 &&
|
||||
packet.header.src_ip.equals(route_addr) {
|
||||
route_mac = packet.header.src_mac;
|
||||
self.arp.borrow_mut().push(ArpEntry {
|
||||
ip: route_addr,
|
||||
mac: route_mac,
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
Err(_) => (),
|
||||
}
|
||||
},
|
||||
Err(err) => println!("IP: ARP Write Failed: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(link) = syscall::open(&format!("ethernet:{}/800", &route_mac.to_string()), O_RDWR) {
|
||||
return Ok(Box::new(IpResource {
|
||||
link: link,
|
||||
data: Vec::new(),
|
||||
peer_addr: peer_addr,
|
||||
proto: proto,
|
||||
id: (rand() % 65536) as u16,
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
while let Ok(link) = syscall::open("ethernet:/800", O_RDWR) {
|
||||
let mut bytes = [0; 65536];
|
||||
match syscall::read(link, &mut bytes) {
|
||||
Ok(count) => {
|
||||
if let Some(packet) = Ipv4::from_bytes(&bytes[..count]) {
|
||||
if packet.header.proto == proto &&
|
||||
(packet.header.dst.equals(unsafe { IP_ADDR }) || packet.header.dst.equals(BROADCAST_IP_ADDR)) {
|
||||
return Ok(Box::new(IpResource {
|
||||
link: link,
|
||||
data: packet.data,
|
||||
peer_addr: packet.header.src,
|
||||
proto: proto,
|
||||
id: (rand() % 65536) as u16,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("IP: No protocol provided");
|
||||
}
|
||||
} else {
|
||||
println!("IP: No host provided");
|
||||
}
|
||||
|
||||
Err(Error::new(ENOENT))
|
||||
} else {
|
||||
Err(Error::new(EACCES))
|
||||
}
|
||||
}
|
||||
}
|
1
schemes/orbital
Submodule
1
schemes/orbital
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 3667b8960255928363b88ac9ac5902f228823512
|
7
schemes/tcpd/Cargo.toml
Normal file
7
schemes/tcpd/Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "tcpd"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
resource_scheme = { path = "../../crates/resource_scheme/" }
|
||||
syscall = { path = "../../syscall/" }
|
217
schemes/tcpd/src/common.rs
Normal file
217
schemes/tcpd/src/common.rs
Normal file
|
@ -0,0 +1,217 @@
|
|||
use std::{mem, slice, u8, u16, u32};
|
||||
|
||||
pub static mut IP_ADDR: Ipv4Addr = Ipv4Addr { bytes: [10, 0, 2, 15] };
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(packed)]
|
||||
pub struct n16(u16);
|
||||
|
||||
impl n16 {
|
||||
pub fn new(value: u16) -> Self {
|
||||
n16(value.to_be())
|
||||
}
|
||||
|
||||
pub fn get(&self) -> u16 {
|
||||
u16::from_be(self.0)
|
||||
}
|
||||
|
||||
pub fn set(&mut self, value: u16) {
|
||||
self.0 = value.to_be();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(packed)]
|
||||
pub struct n32(u32);
|
||||
|
||||
impl n32 {
|
||||
pub fn new(value: u32) -> Self {
|
||||
n32(value.to_be())
|
||||
}
|
||||
|
||||
pub fn get(&self) -> u32 {
|
||||
u32::from_be(self.0)
|
||||
}
|
||||
|
||||
pub fn set(&mut self, value: u32) {
|
||||
self.0 = value.to_be();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Ipv4Addr {
|
||||
pub bytes: [u8; 4],
|
||||
}
|
||||
|
||||
impl Ipv4Addr {
|
||||
pub fn equals(&self, other: Self) -> bool {
|
||||
for i in 0..4 {
|
||||
if self.bytes[i] != other.bytes[i] {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn from_str(string: &str) -> Self {
|
||||
let mut addr = Ipv4Addr { bytes: [0, 0, 0, 0] };
|
||||
|
||||
let mut i = 0;
|
||||
for part in string.split('.') {
|
||||
let octet = part.parse::<u8>().unwrap_or(0);
|
||||
match i {
|
||||
0 => addr.bytes[0] = octet,
|
||||
1 => addr.bytes[1] = octet,
|
||||
2 => addr.bytes[2] = octet,
|
||||
3 => addr.bytes[3] = octet,
|
||||
_ => break,
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
addr
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
let mut string = String::new();
|
||||
|
||||
for i in 0..4 {
|
||||
if i > 0 {
|
||||
string = string + ".";
|
||||
}
|
||||
string = string + &format!("{}", self.bytes[i]);
|
||||
}
|
||||
|
||||
string
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Checksum {
|
||||
pub data: u16,
|
||||
}
|
||||
|
||||
impl Checksum {
|
||||
pub unsafe fn check(&self, mut ptr: usize, mut len: usize) -> bool {
|
||||
let mut sum: usize = 0;
|
||||
while len > 1 {
|
||||
sum += *(ptr as *const u16) as usize;
|
||||
len -= 2;
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
if len > 0 {
|
||||
sum += *(ptr as *const u8) as usize;
|
||||
}
|
||||
|
||||
while (sum >> 16) > 0 {
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
}
|
||||
|
||||
sum == 0xFFFF
|
||||
}
|
||||
|
||||
pub unsafe fn calculate(&mut self, ptr: usize, len: usize) {
|
||||
self.data = 0;
|
||||
|
||||
let sum = Checksum::sum(ptr, len);
|
||||
|
||||
self.data = Checksum::compile(sum);
|
||||
}
|
||||
|
||||
pub unsafe fn sum(mut ptr: usize, mut len: usize) -> usize {
|
||||
let mut sum = 0;
|
||||
|
||||
while len > 1 {
|
||||
sum += *(ptr as *const u16) as usize;
|
||||
len -= 2;
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
if len > 0 {
|
||||
sum += *(ptr as *const u8) as usize;
|
||||
}
|
||||
|
||||
sum
|
||||
}
|
||||
|
||||
pub fn compile(mut sum: usize) -> u16 {
|
||||
while (sum >> 16) > 0 {
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
}
|
||||
|
||||
0xFFFF - (sum as u16)
|
||||
}
|
||||
}
|
||||
|
||||
pub const TCP_FIN: u16 = 1;
|
||||
pub const TCP_SYN: u16 = 1 << 1;
|
||||
pub const TCP_RST: u16 = 1 << 2;
|
||||
pub const TCP_PSH: u16 = 1 << 3;
|
||||
pub const TCP_ACK: u16 = 1 << 4;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(packed)]
|
||||
pub struct TcpHeader {
|
||||
pub src: n16,
|
||||
pub dst: n16,
|
||||
pub sequence: n32,
|
||||
pub ack_num: n32,
|
||||
pub flags: n16,
|
||||
pub window_size: n16,
|
||||
pub checksum: Checksum,
|
||||
pub urgent_pointer: n16,
|
||||
}
|
||||
|
||||
pub struct Tcp {
|
||||
pub header: TcpHeader,
|
||||
pub options: Vec<u8>,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Tcp {
|
||||
pub fn checksum(&mut self, src_addr: &Ipv4Addr, dst_addr: &Ipv4Addr) {
|
||||
self.header.checksum.data = 0;
|
||||
|
||||
let proto = n16::new(0x06);
|
||||
let segment_len = n16::new((mem::size_of::<TcpHeader>() + self.options.len() + self.data.len()) as u16);
|
||||
self.header.checksum.data = Checksum::compile(unsafe {
|
||||
Checksum::sum(src_addr.bytes.as_ptr() as usize, src_addr.bytes.len()) +
|
||||
Checksum::sum(dst_addr.bytes.as_ptr() as usize, dst_addr.bytes.len()) +
|
||||
Checksum::sum((&proto as *const n16) as usize, mem::size_of::<n16>()) +
|
||||
Checksum::sum((&segment_len as *const n16) as usize, mem::size_of::<n16>()) +
|
||||
Checksum::sum((&self.header as *const TcpHeader) as usize, mem::size_of::<TcpHeader>()) +
|
||||
Checksum::sum(self.options.as_ptr() as usize, self.options.len()) +
|
||||
Checksum::sum(self.data.as_ptr() as usize, self.data.len())
|
||||
});
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
|
||||
if bytes.len() >= mem::size_of::<TcpHeader>() {
|
||||
unsafe {
|
||||
let header = *(bytes.as_ptr() as *const TcpHeader);
|
||||
let header_len = ((header.flags.get() & 0xF000) >> 10) as usize;
|
||||
|
||||
return Some(Tcp {
|
||||
header: header,
|
||||
options: bytes[mem::size_of::<TcpHeader>()..header_len].to_vec(),
|
||||
data: bytes[header_len..bytes.len()].to_vec(),
|
||||
});
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
unsafe {
|
||||
let header_ptr: *const TcpHeader = &self.header;
|
||||
let mut ret = Vec::from(slice::from_raw_parts(header_ptr as *const u8,
|
||||
mem::size_of::<TcpHeader>()));
|
||||
ret.extend_from_slice(&self.options);
|
||||
ret.extend_from_slice(&self.data);
|
||||
ret
|
||||
}
|
||||
}
|
||||
}
|
30
schemes/tcpd/src/main.rs
Normal file
30
schemes/tcpd/src/main.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
#![feature(rand)]
|
||||
|
||||
extern crate resource_scheme;
|
||||
extern crate syscall;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::thread;
|
||||
|
||||
use resource_scheme::ResourceScheme;
|
||||
use syscall::Packet;
|
||||
|
||||
use scheme::TcpScheme;
|
||||
|
||||
pub mod common;
|
||||
pub mod resource;
|
||||
pub mod scheme;
|
||||
|
||||
fn main() {
|
||||
thread::spawn(move || {
|
||||
let mut socket = File::create(":tcp").expect("tcpd: failed to create tcp scheme");
|
||||
let scheme = TcpScheme;
|
||||
loop {
|
||||
let mut packet = Packet::default();
|
||||
socket.read(&mut packet).expect("tcpd: failed to read events from tcp scheme");
|
||||
scheme.handle(&mut packet);
|
||||
socket.write(&packet).expect("tcpd: failed to write responses to tcp scheme");
|
||||
}
|
||||
});
|
||||
}
|
328
schemes/tcpd/src/resource.rs
Normal file
328
schemes/tcpd/src/resource.rs
Normal file
|
@ -0,0 +1,328 @@
|
|||
use std::{cmp, mem};
|
||||
use std::cell::UnsafeCell;
|
||||
use std::sync::Arc;
|
||||
|
||||
use resource_scheme::Resource;
|
||||
use syscall;
|
||||
use syscall::error::*;
|
||||
|
||||
use common::{n16, n32, Ipv4Addr, Checksum, IP_ADDR, Tcp, TcpHeader, TCP_SYN, TCP_PSH, TCP_FIN, TCP_ACK};
|
||||
|
||||
pub struct TcpStream {
|
||||
pub ip: usize,
|
||||
pub peer_addr: Ipv4Addr,
|
||||
pub peer_port: u16,
|
||||
pub host_port: u16,
|
||||
pub sequence: u32,
|
||||
pub acknowledge: u32,
|
||||
pub finished: bool
|
||||
}
|
||||
|
||||
impl TcpStream {
|
||||
fn path(&self, buf: &mut [u8]) -> Result<usize> {
|
||||
let path_string = format!("tcp:{}:{}/{}", self.peer_addr.to_string(), self.peer_port, self.host_port);
|
||||
let path = path_string.as_bytes();
|
||||
|
||||
for (b, p) in buf.iter_mut().zip(path.iter()) {
|
||||
*b = *p;
|
||||
}
|
||||
|
||||
Ok(cmp::min(buf.len(), path.len()))
|
||||
}
|
||||
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
if self.finished {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
loop {
|
||||
let mut bytes = [0; 65536];
|
||||
let count = try!(syscall::read(self.ip, &mut bytes));
|
||||
|
||||
if let Some(segment) = Tcp::from_bytes(&bytes[..count]) {
|
||||
if segment.header.dst.get() == self.host_port && segment.header.src.get() == self.peer_port {
|
||||
//println!("Read: {}=={} {:X}: {}", segment.header.sequence.get(), self.acknowledge, segment.header.flags.get(), segment.data.len());
|
||||
|
||||
if self.acknowledge == segment.header.sequence.get() {
|
||||
if segment.header.flags.get() & TCP_FIN == TCP_FIN {
|
||||
self.finished = true;
|
||||
}
|
||||
|
||||
if segment.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK {
|
||||
let flags = if self.finished {
|
||||
TCP_ACK | TCP_FIN
|
||||
} else {
|
||||
TCP_ACK
|
||||
};
|
||||
|
||||
// Send ACK
|
||||
self.acknowledge += segment.data.len() as u32;
|
||||
let mut tcp = Tcp {
|
||||
header: TcpHeader {
|
||||
src: n16::new(self.host_port),
|
||||
dst: n16::new(self.peer_port),
|
||||
sequence: n32::new(self.sequence),
|
||||
ack_num: n32::new(self.acknowledge),
|
||||
flags: n16::new(((mem::size_of::<TcpHeader>() << 10) & 0xF000) as u16 | flags),
|
||||
window_size: n16::new(65535),
|
||||
checksum: Checksum {
|
||||
data: 0
|
||||
},
|
||||
urgent_pointer: n16::new(0)
|
||||
},
|
||||
options: Vec::new(),
|
||||
data: Vec::new()
|
||||
};
|
||||
|
||||
tcp.checksum(& unsafe { IP_ADDR }, &self.peer_addr);
|
||||
|
||||
//println!("Sending read ack: {} {} {:X}", tcp.header.sequence.get(), tcp.header.ack_num.get(), tcp.header.flags.get());
|
||||
|
||||
let _ = syscall::write(self.ip, &tcp.to_bytes());
|
||||
|
||||
// TODO: Support broken packets (one packet in two buffers)
|
||||
let mut i = 0;
|
||||
while i < buf.len() && i < segment.data.len() {
|
||||
buf[i] = segment.data[i];
|
||||
i += 1;
|
||||
}
|
||||
return Ok(i);
|
||||
}
|
||||
} else {
|
||||
println!("TCP: MISMATCH: {}=={}", segment.header.sequence.get(), self.acknowledge);
|
||||
}
|
||||
} else {
|
||||
println!("TCP: WRONG PORT {}=={} && {}=={}", segment.header.dst.get(), self.host_port, segment.header.src.get(), self.peer_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
let tcp_data = Vec::from(buf);
|
||||
|
||||
let mut tcp = Tcp {
|
||||
header: TcpHeader {
|
||||
src: n16::new(self.host_port),
|
||||
dst: n16::new(self.peer_port),
|
||||
sequence: n32::new(self.sequence),
|
||||
ack_num: n32::new(self.acknowledge),
|
||||
flags: n16::new((((mem::size_of::<TcpHeader>()) << 10) & 0xF000) as u16 | TCP_PSH |
|
||||
TCP_ACK),
|
||||
window_size: n16::new(65535),
|
||||
checksum: Checksum { data: 0 },
|
||||
urgent_pointer: n16::new(0),
|
||||
},
|
||||
options: Vec::new(),
|
||||
data: tcp_data,
|
||||
};
|
||||
|
||||
tcp.checksum(& unsafe { IP_ADDR }, &self.peer_addr);
|
||||
|
||||
match syscall::write(self.ip, &tcp.to_bytes()) {
|
||||
Ok(size) => {
|
||||
loop {
|
||||
// Wait for ACK
|
||||
let mut bytes = [0; 65536];
|
||||
match syscall::read(self.ip, &mut bytes) {
|
||||
Ok(count) => {
|
||||
if let Some(segment) = Tcp::from_bytes(&bytes[..count]) {
|
||||
if segment.header.dst.get() == self.host_port &&
|
||||
segment.header.src.get() == self.peer_port {
|
||||
return if (segment.header.flags.get() & (TCP_SYN | TCP_ACK)) == TCP_ACK {
|
||||
self.sequence = segment.header.ack_num.get();
|
||||
self.acknowledge = segment.header.sequence.get();
|
||||
Ok(size)
|
||||
} else {
|
||||
Err(Error::new(EPIPE))
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
fn sync(&mut self) -> Result<usize> {
|
||||
syscall::fsync(self.ip)
|
||||
}
|
||||
|
||||
/// Etablish client
|
||||
pub fn client_establish(&mut self) -> bool {
|
||||
// Send SYN
|
||||
let mut tcp = Tcp {
|
||||
header: TcpHeader {
|
||||
src: n16::new(self.host_port),
|
||||
dst: n16::new(self.peer_port),
|
||||
sequence: n32::new(self.sequence),
|
||||
ack_num: n32::new(self.acknowledge),
|
||||
flags: n16::new(((mem::size_of::<TcpHeader>() << 10) & 0xF000) as u16 | TCP_SYN),
|
||||
window_size: n16::new(65535),
|
||||
checksum: Checksum { data: 0 },
|
||||
urgent_pointer: n16::new(0),
|
||||
},
|
||||
options: Vec::new(),
|
||||
data: Vec::new(),
|
||||
};
|
||||
|
||||
tcp.checksum(& unsafe { IP_ADDR }, &self.peer_addr);
|
||||
|
||||
match syscall::write(self.ip, &tcp.to_bytes()) {
|
||||
Ok(_) => {
|
||||
loop {
|
||||
// Wait for SYN-ACK
|
||||
let mut bytes = [0; 65536];
|
||||
match syscall::read(self.ip, &mut bytes) {
|
||||
Ok(count) => {
|
||||
if let Some(segment) = Tcp::from_bytes(&bytes[..count]) {
|
||||
if segment.header.dst.get() == self.host_port &&
|
||||
segment.header.src.get() == self.peer_port {
|
||||
return if segment.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_SYN | TCP_ACK {
|
||||
self.sequence = segment.header.ack_num.get();
|
||||
self.acknowledge = segment.header.sequence.get();
|
||||
|
||||
self.acknowledge += 1;
|
||||
tcp = Tcp {
|
||||
header: TcpHeader {
|
||||
src: n16::new(self.host_port),
|
||||
dst: n16::new(self.peer_port),
|
||||
sequence: n32::new(self.sequence),
|
||||
ack_num: n32::new(self.acknowledge),
|
||||
flags: n16::new(((mem::size_of::<TcpHeader>() << 10) & 0xF000) as u16 | TCP_ACK),
|
||||
window_size: n16::new(65535),
|
||||
checksum: Checksum {
|
||||
data: 0
|
||||
},
|
||||
urgent_pointer: n16::new(0)
|
||||
},
|
||||
options: Vec::new(),
|
||||
data: Vec::new()
|
||||
};
|
||||
|
||||
tcp.checksum(& unsafe { IP_ADDR }, &self.peer_addr);
|
||||
|
||||
let _ = syscall::write(self.ip, &tcp.to_bytes());
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => return false,
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to establish a server connection
|
||||
pub fn server_establish(&mut self, _: Tcp) -> bool {
|
||||
// Send SYN-ACK
|
||||
self.acknowledge += 1;
|
||||
let mut tcp = Tcp {
|
||||
header: TcpHeader {
|
||||
src: n16::new(self.host_port),
|
||||
dst: n16::new(self.peer_port),
|
||||
sequence: n32::new(self.sequence),
|
||||
ack_num: n32::new(self.acknowledge),
|
||||
flags: n16::new(((mem::size_of::<TcpHeader>() << 10) & 0xF000) as u16 | TCP_SYN |
|
||||
TCP_ACK),
|
||||
window_size: n16::new(65535),
|
||||
checksum: Checksum { data: 0 },
|
||||
urgent_pointer: n16::new(0),
|
||||
},
|
||||
options: Vec::new(),
|
||||
data: Vec::new(),
|
||||
};
|
||||
|
||||
tcp.checksum(& unsafe { IP_ADDR }, &self.peer_addr);
|
||||
|
||||
match syscall::write(self.ip, &tcp.to_bytes()) {
|
||||
Ok(_) => {
|
||||
loop {
|
||||
// Wait for ACK
|
||||
let mut bytes = [0; 65536];
|
||||
match syscall::read(self.ip, &mut bytes) {
|
||||
Ok(count ) => {
|
||||
if let Some(segment) = Tcp::from_bytes(&bytes[..count]) {
|
||||
if segment.header.dst.get() == self.host_port &&
|
||||
segment.header.src.get() == self.peer_port {
|
||||
return if segment.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK {
|
||||
self.sequence = segment.header.ack_num.get();
|
||||
self.acknowledge = segment.header.sequence.get();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => return false,
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TcpStream {
|
||||
fn drop(&mut self) {
|
||||
// Send FIN-ACK
|
||||
let mut tcp = Tcp {
|
||||
header: TcpHeader {
|
||||
src: n16::new(self.host_port),
|
||||
dst: n16::new(self.peer_port),
|
||||
sequence: n32::new(self.sequence),
|
||||
ack_num: n32::new(self.acknowledge),
|
||||
flags: n16::new((((mem::size_of::<TcpHeader>()) << 10) & 0xF000) as u16 | TCP_FIN | TCP_ACK),
|
||||
window_size: n16::new(65535),
|
||||
checksum: Checksum { data: 0 },
|
||||
urgent_pointer: n16::new(0),
|
||||
},
|
||||
options: Vec::new(),
|
||||
data: Vec::new(),
|
||||
};
|
||||
|
||||
tcp.checksum(& unsafe { IP_ADDR }, &self.peer_addr);
|
||||
|
||||
let _ = syscall::write(self.ip, &tcp.to_bytes());
|
||||
let _ = syscall::close(self.ip);
|
||||
}
|
||||
}
|
||||
|
||||
/// A TCP resource
|
||||
pub struct TcpResource {
|
||||
pub stream: Arc<UnsafeCell<TcpStream>>
|
||||
}
|
||||
|
||||
impl Resource for TcpResource {
|
||||
fn dup(&self) -> Result<Box<TcpResource>> {
|
||||
Ok(Box::new(TcpResource {
|
||||
stream: self.stream.clone()
|
||||
}))
|
||||
}
|
||||
|
||||
fn path(&self, buf: &mut [u8]) -> Result<usize> {
|
||||
unsafe { (*self.stream.get()).path(buf) }
|
||||
}
|
||||
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
unsafe { (*self.stream.get()).read(buf) }
|
||||
}
|
||||
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
unsafe { (*self.stream.get()).write(buf) }
|
||||
}
|
||||
|
||||
fn sync(&mut self) -> Result<usize> {
|
||||
unsafe { (*self.stream.get()).sync() }
|
||||
}
|
||||
}
|
94
schemes/tcpd/src/scheme.rs
Normal file
94
schemes/tcpd/src/scheme.rs
Normal file
|
@ -0,0 +1,94 @@
|
|||
use std::cell::UnsafeCell;
|
||||
use std::rand;
|
||||
use std::sync::Arc;
|
||||
use std::{str, u16};
|
||||
|
||||
use resource_scheme::ResourceScheme;
|
||||
use syscall;
|
||||
use syscall::error::{Error, Result, ENOENT, EINVAL};
|
||||
use syscall::flag::O_RDWR;
|
||||
|
||||
use common::{Ipv4Addr, Tcp, TCP_SYN, TCP_ACK};
|
||||
use resource::{TcpResource, TcpStream};
|
||||
|
||||
/// A TCP scheme
|
||||
pub struct TcpScheme;
|
||||
|
||||
impl ResourceScheme<TcpResource> for TcpScheme {
|
||||
fn open_resource(&self, url: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<Box<TcpResource>> {
|
||||
let path = try!(str::from_utf8(url).or(Err(Error::new(EINVAL))));
|
||||
let mut parts = path.split('/');
|
||||
let remote = parts.next().unwrap_or("");
|
||||
let path = parts.next().unwrap_or("");
|
||||
|
||||
let mut remote_parts = remote.split(':');
|
||||
let host = remote_parts.next().unwrap_or("");
|
||||
let port = remote_parts.next().unwrap_or("");
|
||||
|
||||
if ! host.is_empty() && ! port.is_empty() {
|
||||
let peer_addr = Ipv4Addr::from_str(host);
|
||||
let peer_port = port.parse::<u16>().unwrap_or(0);
|
||||
let host_port = (rand() % 32768 + 32768) as u16;
|
||||
|
||||
match syscall::open(&format!("ip:{}/6", peer_addr.to_string()), O_RDWR) {
|
||||
Ok(ip) => {
|
||||
let mut stream = TcpStream {
|
||||
ip: ip,
|
||||
peer_addr: peer_addr,
|
||||
peer_port: peer_port,
|
||||
host_port: host_port,
|
||||
sequence: rand() as u32,
|
||||
acknowledge: 0,
|
||||
finished: false
|
||||
};
|
||||
|
||||
if stream.client_establish() {
|
||||
return Ok(Box::new(TcpResource {
|
||||
stream: Arc::new(UnsafeCell::new(stream))
|
||||
}));
|
||||
}
|
||||
}
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
} else if ! path.is_empty() {
|
||||
let host_port = path.parse::<u16>().unwrap_or(0);
|
||||
|
||||
while let Ok(ip) = syscall::open("ip:/6", O_RDWR) {
|
||||
let mut bytes = [0; 65536];
|
||||
match syscall::read(ip, &mut bytes) {
|
||||
Ok(count) => {
|
||||
if let Some(segment) = Tcp::from_bytes(&bytes[..count]) {
|
||||
if segment.header.dst.get() == host_port && segment.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_SYN {
|
||||
let mut path = [0; 256];
|
||||
if let Ok(path_count) = syscall::fpath(ip, &mut path) {
|
||||
let ip_reference = unsafe { str::from_utf8_unchecked(&path[.. path_count]) }.split(':').nth(1).unwrap_or("");
|
||||
let ip_remote = ip_reference.split('/').next().unwrap_or("");
|
||||
let peer_addr = ip_remote.split(':').next().unwrap_or("");
|
||||
|
||||
let mut stream = TcpStream {
|
||||
ip: ip,
|
||||
peer_addr: Ipv4Addr::from_str(peer_addr),
|
||||
peer_port: segment.header.src.get(),
|
||||
host_port: host_port,
|
||||
sequence: rand() as u32,
|
||||
acknowledge: segment.header.sequence.get(),
|
||||
finished: false
|
||||
};
|
||||
|
||||
if stream.server_establish(segment) {
|
||||
return Ok(Box::new(TcpResource {
|
||||
stream: Arc::new(UnsafeCell::new(stream))
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
}
|
7
schemes/udpd/Cargo.toml
Normal file
7
schemes/udpd/Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "udpd"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
resource_scheme = { path = "../../crates/resource_scheme/" }
|
||||
syscall = { path = "../../syscall/" }
|
167
schemes/udpd/src/common.rs
Normal file
167
schemes/udpd/src/common.rs
Normal file
|
@ -0,0 +1,167 @@
|
|||
use std::{mem, slice, u8, u16};
|
||||
|
||||
pub static mut IP_ADDR: Ipv4Addr = Ipv4Addr { bytes: [10, 0, 2, 15] };
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(packed)]
|
||||
pub struct n16(u16);
|
||||
|
||||
impl n16 {
|
||||
pub fn new(value: u16) -> Self {
|
||||
n16(value.to_be())
|
||||
}
|
||||
|
||||
pub fn get(&self) -> u16 {
|
||||
u16::from_be(self.0)
|
||||
}
|
||||
|
||||
pub fn set(&mut self, value: u16) {
|
||||
self.0 = value.to_be();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Ipv4Addr {
|
||||
pub bytes: [u8; 4],
|
||||
}
|
||||
|
||||
impl Ipv4Addr {
|
||||
pub fn equals(&self, other: Self) -> bool {
|
||||
for i in 0..4 {
|
||||
if self.bytes[i] != other.bytes[i] {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn from_str(string: &str) -> Self {
|
||||
let mut addr = Ipv4Addr { bytes: [0, 0, 0, 0] };
|
||||
|
||||
let mut i = 0;
|
||||
for part in string.split('.') {
|
||||
let octet = part.parse::<u8>().unwrap_or(0);
|
||||
match i {
|
||||
0 => addr.bytes[0] = octet,
|
||||
1 => addr.bytes[1] = octet,
|
||||
2 => addr.bytes[2] = octet,
|
||||
3 => addr.bytes[3] = octet,
|
||||
_ => break,
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
addr
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
let mut string = String::new();
|
||||
|
||||
for i in 0..4 {
|
||||
if i > 0 {
|
||||
string = string + ".";
|
||||
}
|
||||
string = string + &format!("{}", self.bytes[i]);
|
||||
}
|
||||
|
||||
string
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Checksum {
|
||||
pub data: u16,
|
||||
}
|
||||
|
||||
impl Checksum {
|
||||
pub unsafe fn check(&self, mut ptr: usize, mut len: usize) -> bool {
|
||||
let mut sum: usize = 0;
|
||||
while len > 1 {
|
||||
sum += *(ptr as *const u16) as usize;
|
||||
len -= 2;
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
if len > 0 {
|
||||
sum += *(ptr as *const u8) as usize;
|
||||
}
|
||||
|
||||
while (sum >> 16) > 0 {
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
}
|
||||
|
||||
sum == 0xFFFF
|
||||
}
|
||||
|
||||
pub unsafe fn calculate(&mut self, ptr: usize, len: usize) {
|
||||
self.data = 0;
|
||||
|
||||
let sum = Checksum::sum(ptr, len);
|
||||
|
||||
self.data = Checksum::compile(sum);
|
||||
}
|
||||
|
||||
pub unsafe fn sum(mut ptr: usize, mut len: usize) -> usize {
|
||||
let mut sum = 0;
|
||||
|
||||
while len > 1 {
|
||||
sum += *(ptr as *const u16) as usize;
|
||||
len -= 2;
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
if len > 0 {
|
||||
sum += *(ptr as *const u8) as usize;
|
||||
}
|
||||
|
||||
sum
|
||||
}
|
||||
|
||||
pub fn compile(mut sum: usize) -> u16 {
|
||||
while (sum >> 16) > 0 {
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
}
|
||||
|
||||
0xFFFF - (sum as u16)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(packed)]
|
||||
pub struct UdpHeader {
|
||||
pub src: n16,
|
||||
pub dst: n16,
|
||||
pub len: n16,
|
||||
pub checksum: Checksum,
|
||||
}
|
||||
|
||||
pub struct Udp {
|
||||
pub header: UdpHeader,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Udp {
|
||||
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
|
||||
if bytes.len() >= mem::size_of::<UdpHeader>() {
|
||||
unsafe {
|
||||
Option::Some(Udp {
|
||||
header: *(bytes.as_ptr() as *const UdpHeader),
|
||||
data: bytes[mem::size_of::<UdpHeader>()..bytes.len()].to_vec(),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Option::None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
unsafe {
|
||||
let header_ptr: *const UdpHeader = &self.header;
|
||||
let mut ret = Vec::from(slice::from_raw_parts(header_ptr as *const u8,
|
||||
mem::size_of::<UdpHeader>()));
|
||||
ret.extend_from_slice(&self.data);
|
||||
ret
|
||||
}
|
||||
}
|
||||
}
|
30
schemes/udpd/src/main.rs
Normal file
30
schemes/udpd/src/main.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
#![feature(rand)]
|
||||
|
||||
extern crate resource_scheme;
|
||||
extern crate syscall;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::thread;
|
||||
|
||||
use resource_scheme::ResourceScheme;
|
||||
use syscall::Packet;
|
||||
|
||||
use scheme::UdpScheme;
|
||||
|
||||
pub mod common;
|
||||
pub mod resource;
|
||||
pub mod scheme;
|
||||
|
||||
fn main() {
|
||||
thread::spawn(move || {
|
||||
let mut socket = File::create(":udp").expect("udpd: failed to create udp scheme");
|
||||
let scheme = UdpScheme;
|
||||
loop {
|
||||
let mut packet = Packet::default();
|
||||
socket.read(&mut packet).expect("udpd: failed to read events from udp scheme");
|
||||
scheme.handle(&mut packet);
|
||||
socket.write(&packet).expect("udpd: failed to write responses to udp scheme");
|
||||
}
|
||||
});
|
||||
}
|
114
schemes/udpd/src/resource.rs
Normal file
114
schemes/udpd/src/resource.rs
Normal file
|
@ -0,0 +1,114 @@
|
|||
use std::{cmp, mem};
|
||||
|
||||
use resource_scheme::Resource;
|
||||
use syscall;
|
||||
use syscall::error::*;
|
||||
|
||||
use common::{n16, Ipv4Addr, Checksum, IP_ADDR, Udp, UdpHeader};
|
||||
|
||||
/// UDP resource
|
||||
pub struct UdpResource {
|
||||
pub ip: usize,
|
||||
pub data: Vec<u8>,
|
||||
pub peer_addr: Ipv4Addr,
|
||||
pub peer_port: u16,
|
||||
pub host_port: u16,
|
||||
}
|
||||
|
||||
impl Resource for UdpResource {
|
||||
fn dup(&self) -> Result<Box<UdpResource>> {
|
||||
match syscall::dup(self.ip) {
|
||||
Ok(ip) => {
|
||||
Ok(Box::new(UdpResource {
|
||||
ip: ip,
|
||||
data: self.data.clone(),
|
||||
peer_addr: self.peer_addr,
|
||||
peer_port: self.peer_port,
|
||||
host_port: self.host_port,
|
||||
}))
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
fn path(&self, buf: &mut [u8]) -> Result<usize> {
|
||||
let path_string = format!("udp:{}:{}/{}", self.peer_addr.to_string(), self.peer_port, self.host_port);
|
||||
let path = path_string.as_bytes();
|
||||
|
||||
for (b, p) in buf.iter_mut().zip(path.iter()) {
|
||||
*b = *p;
|
||||
}
|
||||
|
||||
Ok(cmp::min(buf.len(), path.len()))
|
||||
}
|
||||
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
if ! self.data.is_empty() {
|
||||
let mut bytes: Vec<u8> = Vec::new();
|
||||
mem::swap(&mut self.data, &mut bytes);
|
||||
|
||||
// TODO: Allow splitting
|
||||
let mut i = 0;
|
||||
while i < buf.len() && i < bytes.len() {
|
||||
buf[i] = bytes[i];
|
||||
i += 1;
|
||||
}
|
||||
|
||||
return Ok(i);
|
||||
}
|
||||
|
||||
loop {
|
||||
let mut bytes = [0; 65536];
|
||||
let count = try!(syscall::read(self.ip, &mut bytes));
|
||||
|
||||
if let Some(datagram) = Udp::from_bytes(&bytes[..count]) {
|
||||
if datagram.header.dst.get() == self.host_port &&
|
||||
datagram.header.src.get() == self.peer_port {
|
||||
// TODO: Allow splitting
|
||||
let mut i = 0;
|
||||
while i < buf.len() && i < datagram.data.len() {
|
||||
buf[i] = datagram.data[i];
|
||||
i += 1;
|
||||
}
|
||||
|
||||
return Ok(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
let mut udp = Udp {
|
||||
header: UdpHeader {
|
||||
src: n16::new(self.host_port),
|
||||
dst: n16::new(self.peer_port),
|
||||
len: n16::new((mem::size_of::<UdpHeader>() + buf.len()) as u16),
|
||||
checksum: Checksum { data: 0 },
|
||||
},
|
||||
data: Vec::from(buf),
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let proto = n16::new(0x11);
|
||||
let datagram_len = n16::new((mem::size_of::<UdpHeader>() + udp.data.len()) as u16);
|
||||
udp.header.checksum.data =
|
||||
Checksum::compile(Checksum::sum((&IP_ADDR as *const Ipv4Addr) as usize,
|
||||
mem::size_of::<Ipv4Addr>()) +
|
||||
Checksum::sum((&self.peer_addr as *const Ipv4Addr) as usize,
|
||||
mem::size_of::<Ipv4Addr>()) +
|
||||
Checksum::sum((&proto as *const n16) as usize,
|
||||
mem::size_of::<n16>()) +
|
||||
Checksum::sum((&datagram_len as *const n16) as usize,
|
||||
mem::size_of::<n16>()) +
|
||||
Checksum::sum((&udp.header as *const UdpHeader) as usize,
|
||||
mem::size_of::<UdpHeader>()) +
|
||||
Checksum::sum(udp.data.as_ptr() as usize, udp.data.len()));
|
||||
}
|
||||
|
||||
syscall::write(self.ip, &udp.to_bytes()).and(Ok(buf.len()))
|
||||
}
|
||||
|
||||
fn sync(&mut self) -> Result<usize> {
|
||||
syscall::fsync(self.ip)
|
||||
}
|
||||
}
|
69
schemes/udpd/src/scheme.rs
Normal file
69
schemes/udpd/src/scheme.rs
Normal file
|
@ -0,0 +1,69 @@
|
|||
use std::rand;
|
||||
use std::{str, u16};
|
||||
|
||||
use resource_scheme::ResourceScheme;
|
||||
use syscall;
|
||||
use syscall::error::{Error, Result, ENOENT, EINVAL};
|
||||
use syscall::flag::O_RDWR;
|
||||
|
||||
use common::{Ipv4Addr, Udp};
|
||||
use resource::UdpResource;
|
||||
|
||||
/// UDP UdpScheme
|
||||
pub struct UdpScheme;
|
||||
|
||||
impl ResourceScheme<UdpResource> for UdpScheme {
|
||||
fn open_resource(&self, url: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<Box<UdpResource>> {
|
||||
let path = try!(str::from_utf8(url).or(Err(Error::new(EINVAL))));
|
||||
let mut parts = path.split('/');
|
||||
let remote = parts.next().unwrap_or("");
|
||||
let path = parts.next().unwrap_or("");
|
||||
|
||||
// Check host and port vs path
|
||||
if remote.is_empty() {
|
||||
let host_port = path.parse::<u16>().unwrap_or(0);
|
||||
if host_port > 0 {
|
||||
while let Ok(ip) = syscall::open("ip:/11", O_RDWR) {
|
||||
let mut bytes = [0; 65536];
|
||||
if let Ok(count) = syscall::read(ip, &mut bytes) {
|
||||
if let Some(datagram) = Udp::from_bytes(&bytes[..count]) {
|
||||
if datagram.header.dst.get() == host_port {
|
||||
let mut path = [0; 256];
|
||||
if let Ok(path_count) = syscall::fpath(ip, &mut path) {
|
||||
let ip_reference = unsafe { str::from_utf8_unchecked(&path[.. path_count]) }.split(':').nth(1).unwrap_or("");
|
||||
let peer_addr = ip_reference.split('/').next().unwrap_or("").split(':').next().unwrap_or("");
|
||||
|
||||
return Ok(Box::new(UdpResource {
|
||||
ip: ip,
|
||||
data: datagram.data,
|
||||
peer_addr: Ipv4Addr::from_str(peer_addr),
|
||||
peer_port: datagram.header.src.get(),
|
||||
host_port: host_port,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let mut remote_parts = remote.split(':');
|
||||
let peer_addr = remote_parts.next().unwrap_or("");
|
||||
let peer_port = remote_parts.next().unwrap_or("").parse::<u16>().unwrap_or(0);
|
||||
if peer_port > 0 {
|
||||
let host_port = path.parse::<u16>().unwrap_or((rand() % 32768 + 32768) as u16);
|
||||
if let Ok(ip) = syscall::open(&format!("ip:{}/11", peer_addr), O_RDWR) {
|
||||
return Ok(Box::new(UdpResource {
|
||||
ip: ip,
|
||||
data: Vec::new(),
|
||||
peer_addr: Ipv4Addr::from_str(peer_addr),
|
||||
peer_port: peer_port as u16,
|
||||
host_port: host_port,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue