Documentation run on schemes/ipd. (#18)

* Documentation run on schemes/ipd.

* Update main.rs

* Update resource.rs
This commit is contained in:
David Teller 2016-10-24 15:40:44 +02:00 committed by Jeremy Soller
parent 3634afe549
commit 35696f4169
3 changed files with 75 additions and 7 deletions

View file

@ -1,5 +1,24 @@
#![feature(rand)] #![feature(rand)]
//! Implementation of the IP Scheme as a userland driver.
//!
//! # Role
//!
//! See https://en.wikipedia.org/wiki/Internet_Protocol for more details about the
//! IP protocol. Clients will often prefer using either higher-level protocols TCP
//! or UDP, both of which are built upon IP.
//!
//! # URL Syntax
//!
//! To open a IP connection, use `ip:[host]/protocol`.
//!
//! * If `host` is specified, it must be an ipv4 number (e.g. `192.168.0.1`)
//! and the connection may be used immediately to send/receive data.
//! * If `host` is omitted, this connectino will wait for a distant peer to
//! connect.
//! * The `protocol` is the hex-based number of the ip protocol
//! (see http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml).
extern crate netutils; extern crate netutils;
extern crate resource_scheme; extern crate resource_scheme;
extern crate syscall; extern crate syscall;

View file

@ -5,22 +5,48 @@ use resource_scheme::Resource;
use syscall; use syscall;
use syscall::error::*; use syscall::error::*;
/// A IP (internet protocole) resource /// A IP (internet protocol) resource.
///
/// Each instance represents a connection (~ a IP socket).
pub struct IpResource { pub struct IpResource {
/// Link to the underlying device (typically, an Ethernet card).
pub link: usize, pub link: usize,
pub data: Vec<u8>,
/// If this connection was opened waiting for a peer (i.e. `ip:/protocol`),
/// the data received when the peer actually connected. Otherwise, empty.
/// Emptied during the first call to `read()`.
pub init_data: Vec<u8>,
/// The IP address of the host (i.e. this machine).
pub host_addr: Ipv4Addr, pub host_addr: Ipv4Addr,
/// The IP address of the peer (i.e. the other machine).
pub peer_addr: Ipv4Addr, pub peer_addr: Ipv4Addr,
/// The IP protocol used by this connection. See
/// http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
/// for the list of valid protocols.
pub proto: u8, pub proto: u8,
/// The id of the next packet being sent.
/// See https://en.wikipedia.org/wiki/IPv4#Identification .
pub id: u16, pub id: u16,
} }
impl Resource for IpResource { impl Resource for IpResource {
/// Duplicate the connection.
///
/// This duplicates both `self.link` and `self.init_data`.
///
/// # Errors
///
/// Fails if the `link` to the underlying device cannot be
/// duplicated.
fn dup(&self) -> Result<Box<Self>> { fn dup(&self) -> Result<Box<Self>> {
let link = try!(syscall::dup(self.link)); let link = try!(syscall::dup(self.link));
Ok(Box::new(IpResource { Ok(Box::new(IpResource {
link: link, link: link,
data: self.data.clone(), init_data: self.init_data.clone(),
host_addr: self.host_addr, host_addr: self.host_addr,
peer_addr: self.peer_addr, peer_addr: self.peer_addr,
proto: self.proto, proto: self.proto,
@ -28,6 +54,12 @@ impl Resource for IpResource {
})) }))
} }
/// Get the current path, as `ip:peer/protocol`, where `peer`
/// is the IPv4 address of the peer and `protocol` is the hex-based
/// number of the IP protocol used.
///
/// Note that the `peer` is specified even if the connection was initially
/// created as `ip:/protocol`.
fn path(&self, buf: &mut [u8]) -> Result<usize> { fn path(&self, buf: &mut [u8]) -> Result<usize> {
let path_string = format!("ip:{}/{:X}", self.peer_addr.to_string(), self.proto); let path_string = format!("ip:{}/{:X}", self.peer_addr.to_string(), self.proto);
let path = path_string.as_bytes(); let path = path_string.as_bytes();
@ -39,10 +71,21 @@ impl Resource for IpResource {
Ok(cmp::min(buf.len(), path.len())) Ok(cmp::min(buf.len(), path.len()))
} }
/// Read data from the device.
///
/// If some data has already been made available during the establishment
/// of the connection, this data is (entirely) read during the first call
/// to `read()`, without attempting to actually read from the device. This
/// can happen only if the connection was waiting for a remote peer to connect, i.e.
/// with a url `ip:/protocol`, without host.
///
/// # Errors
///
/// Fails if the call to `syscall::read()` fails for this device.
fn read(&mut self, buf: &mut [u8]) -> Result<usize> { fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if !self.data.is_empty() { if !self.init_data.is_empty() {
let mut data: Vec<u8> = Vec::new(); let mut data: Vec<u8> = Vec::new();
mem::swap(&mut self.data, &mut data); mem::swap(&mut self.init_data, &mut data);
for (b, d) in buf.iter_mut().zip(data.iter()) { for (b, d) in buf.iter_mut().zip(data.iter()) {
*b = *d; *b = *d;
@ -69,6 +112,11 @@ impl Resource for IpResource {
Ok(0) Ok(0)
} }
/// Send data to the peer.
///
/// # Errors
///
/// Fails if the call to `syscall::write()` fails for this device.
fn write(&mut self, buf: &[u8]) -> Result<usize> { fn write(&mut self, buf: &[u8]) -> Result<usize> {
let ip_data = Vec::from(buf); let ip_data = Vec::from(buf);

View file

@ -117,7 +117,7 @@ impl ResourceScheme<IpResource> for IpScheme {
if let Ok(link) = syscall::open(&format!("ethernet:{}/800", &route_mac.to_string()), O_RDWR) { if let Ok(link) = syscall::open(&format!("ethernet:{}/800", &route_mac.to_string()), O_RDWR) {
return Ok(Box::new(IpResource { return Ok(Box::new(IpResource {
link: link, link: link,
data: Vec::new(), init_data: Vec::new(),
host_addr: ip_addr, host_addr: ip_addr,
peer_addr: peer_addr, peer_addr: peer_addr,
proto: proto, proto: proto,
@ -127,6 +127,7 @@ impl ResourceScheme<IpResource> for IpScheme {
} else { } else {
while let Ok(link) = syscall::open("ethernet:/800", O_RDWR) { while let Ok(link) = syscall::open("ethernet:/800", O_RDWR) {
let mut bytes = [0; 65536]; let mut bytes = [0; 65536];
// FIXME: Blocking call?
match syscall::read(link, &mut bytes) { match syscall::read(link, &mut bytes) {
Ok(count) => { Ok(count) => {
if let Some(packet) = Ipv4::from_bytes(&bytes[..count]) { if let Some(packet) = Ipv4::from_bytes(&bytes[..count]) {
@ -134,7 +135,7 @@ impl ResourceScheme<IpResource> for IpScheme {
(packet.header.dst.equals(ip_addr) || packet.header.dst.equals(Ipv4Addr::BROADCAST)) { (packet.header.dst.equals(ip_addr) || packet.header.dst.equals(Ipv4Addr::BROADCAST)) {
return Ok(Box::new(IpResource { return Ok(Box::new(IpResource {
link: link, link: link,
data: packet.data, init_data: packet.data,
host_addr: ip_addr, host_addr: ip_addr,
peer_addr: packet.header.src, peer_addr: packet.header.src,
proto: proto, proto: proto,