Skip to content

Commit 9e0256a

Browse files
committed
Final commit lol
1 parent 4ea7fa2 commit 9e0256a

File tree

3 files changed

+94
-25
lines changed

3 files changed

+94
-25
lines changed

CPSC_524_Final_Project (13).pdf

-125 KB
Binary file not shown.

Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ edition = "2021"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
9-
futures = "0.3"
9+
futures = "0.3"
10+
socket2 = { version = "0.4", features = ["all"] }
11+
libc = "0.2"

src/lib.rs

+91-24
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,6 @@
22
mod epoll {
33
use std::io;
44

5-
pub const EPOLL_CTL_ADD: i32 = 1;
6-
pub const EPOLL_CTL_DEL: i32 = 2;
7-
pub const EPOLL_CTL_MOD: i32 = 3;
8-
pub const EPOLLIN: i32 = 0x1;
9-
pub const EPOLLONESHOT: i32 = 1 << 30;
10-
pub const EPOLLET: i32 = 1 << 31;
11-
125
// Module providing unsafe ffi for Linux's epoll and epoll-adjacent syscalls.
136
mod ffi {
147
#[link(name = "c")]
@@ -96,14 +89,17 @@ pub mod blockers {
9689
fd: RawFd,
9790
}
9891

92+
// Abstraction around `epoll`. Allows for blocking until an I/O event is ready.
9993
impl IoBlocker {
94+
// Initialize an `epoll` instance.
10095
pub fn new() -> io::Result<Self> {
10196
match epoll::create() {
10297
Ok(fd) => Ok(IoBlocker { fd }),
10398
Err(e) => Err(e),
10499
}
105100
}
106101

102+
// Generate a registrator that can register events to this IoBlocker's epoll.
107103
pub fn registrator(&self) -> Registrator {
108104
Registrator { fd: self.fd }
109105
}
@@ -113,7 +109,6 @@ pub mod blockers {
113109
const TIMEOUT: i32 = -1; // Wait forever.
114110
const MAX_EVENTS: i32 = 1024;
115111
events.clear();
116-
// std::thread::sleep(core::time::Duration::from_secs(1));
117112

118113
// println!("IoBlocker::block --> begin blocking");
119114
let n_events = epoll::wait(self.fd, events, MAX_EVENTS, TIMEOUT)?;
@@ -127,15 +122,19 @@ pub mod blockers {
127122
}
128123
}
129124

130-
// Ensure that we close held file descriptor.
125+
// Ensure that we close held `epoll` file descriptor.
131126
impl Drop for IoBlocker {
132127
fn drop(&mut self) {
133128
// println!("IoBlocker::drop --> dropping");
134129
epoll::close(self.fd).unwrap();
135130
}
136131
}
137132

138-
// Struct to get around Rust ownership issues
133+
// There should only be a single IoBlocker for a given `epoll` instance,
134+
// since IoBlocker is responsible for creating and destroying its file descriptor.
135+
// However, we need some way for multiple different I/O events to register
136+
// themselves to an `epoll`. For this reason, we need a class that can be
137+
// duplicated such that each task can own its own copy. This is the Registrator.
139138
#[derive(Debug, Clone, Copy)] // Helpful default traits.
140139
pub struct Registrator {
141140
fd: RawFd,
@@ -147,21 +146,21 @@ pub mod blockers {
147146
let fd = interest.as_raw_fd();
148147

149148
// Listen for file to become readable.
150-
let mut event = epoll::Event::new(epoll::EPOLLIN | epoll::EPOLLONESHOT, token);
151-
match epoll::ctl(self.fd, epoll::EPOLL_CTL_ADD, fd, &mut event) {
149+
let mut event = epoll::Event::new(libc::EPOLLIN | libc::EPOLLONESHOT, token);
150+
match epoll::ctl(self.fd, libc::EPOLL_CTL_ADD, fd, &mut event) {
152151
Ok(_) => Ok(()),
153152
Err(e) if e.kind() == io::ErrorKind::AlreadyExists => {
154153
// one-shot epoll consumed, so needs to be re-armed.
155-
epoll::ctl(self.fd, epoll::EPOLL_CTL_MOD, fd, &mut event)
156-
},
154+
epoll::ctl(self.fd, libc::EPOLL_CTL_MOD, fd, &mut event)
155+
}
157156
Err(e) => Err(e),
158157
}
159158
}
160159

161160
pub fn unregister(&self, interest: &impl AsRawFd, token: usize) -> io::Result<()> {
162161
let fd = interest.as_raw_fd();
163-
let mut event = epoll::Event::new(epoll::EPOLLIN | epoll::EPOLLET, token);
164-
match epoll::ctl(self.fd, epoll::EPOLL_CTL_DEL, fd, &mut event) {
162+
let mut event = epoll::Event::new(libc::EPOLLIN | libc::EPOLLET, token);
163+
match epoll::ctl(self.fd, libc::EPOLL_CTL_DEL, fd, &mut event) {
165164
Ok(_) => Ok(()),
166165
Err(e) => Err(e),
167166
}
@@ -172,12 +171,14 @@ pub mod blockers {
172171
// Provides future API for awaitable services. For use by external crates.
173172
// In this case, the only provided service is a TcpStream.
174173
pub mod services {
175-
use crate::blockers;
174+
use crate::blockers::{self, Registrator};
176175
use futures::io::{AsyncRead, AsyncWrite};
176+
use socket2::{Domain, Protocol, SockAddr, Socket, Type};
177177
use std::io::{self, Error, Read, Write};
178178
use std::net::Shutdown;
179179
use std::os::unix::io::{AsRawFd, RawFd};
180180
use std::{
181+
future::Future,
181182
net,
182183
pin::Pin,
183184
task::{Context, Poll},
@@ -190,23 +191,85 @@ pub mod services {
190191
token: usize,
191192
}
192193

194+
pub struct ConnectStreamFuture<'a> {
195+
socket: &'a Socket,
196+
addr: SockAddr,
197+
registrator: Registrator,
198+
token: usize,
199+
}
200+
201+
impl Future for ConnectStreamFuture<'_> {
202+
type Output = Result<(), io::Error>;
203+
204+
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
205+
match self.socket.connect(&self.addr) {
206+
// Finished connecting, done polling.
207+
Ok(_) => Poll::Ready(Ok(())),
208+
// Since we set this TcpStream to non-blocking, check if
209+
// return value still not ready.
210+
Err(e)
211+
if e.raw_os_error() == Some(libc::EINPROGRESS)
212+
|| e.kind() == io::ErrorKind::WouldBlock =>
213+
{
214+
self.registrator.register(self.socket, self.token).unwrap();
215+
Poll::Pending
216+
}
217+
// Error occurred, done polling.
218+
Err(e) => Poll::Ready(Err(e)),
219+
}
220+
}
221+
}
222+
193223
impl TcpStream {
194-
pub fn connect(
195-
addr: impl net::ToSocketAddrs,
224+
// Asynchronously connect this stream to a socket address.
225+
// Reference: https://docs.rs/async-io/latest/src/async_io/lib.rs.html#1867
226+
pub async fn connect(
227+
addr_generator: impl net::ToSocketAddrs,
196228
registrator: blockers::Registrator,
197229
token: usize,
198230
) -> io::Result<Self> {
199-
let stream = net::TcpStream::connect(addr)?;
200-
stream.set_nonblocking(true)?;
231+
let sock_type = Type::STREAM.nonblocking();
232+
let protocol = Protocol::TCP;
233+
let socket_addr = addr_generator.to_socket_addrs().unwrap().next().unwrap();
234+
let domain = Domain::for_address(socket_addr);
235+
236+
let socket = Socket::new(domain, sock_type, Some(protocol))
237+
.unwrap_or_else(|_| panic!("Failed to create socket at address {}", socket_addr));
238+
239+
// wait for the socket to become writeable.
240+
TcpStream::sock_connect(
241+
&socket,
242+
SockAddr::from(socket_addr),
243+
registrator.clone(),
244+
token,
245+
)
246+
.await?;
247+
248+
let stream = net::TcpStream::from(socket);
201249

202250
Ok(TcpStream {
203251
inner: stream,
204252
registrator,
205253
token,
206254
})
207255
}
256+
257+
fn sock_connect(
258+
socket: &Socket,
259+
addr: SockAddr,
260+
registrator: Registrator,
261+
token: usize,
262+
) -> ConnectStreamFuture {
263+
return ConnectStreamFuture {
264+
socket,
265+
addr,
266+
registrator,
267+
token,
268+
};
269+
}
208270
}
209271

272+
// Allow calling async read operations on socket.
210273
impl AsyncRead for TcpStream {
211274
fn poll_read(
212275
self: Pin<&mut Self>,
@@ -230,6 +293,7 @@ pub mod services {
230293
}
231294
}
232295

296+
// Allow calling async write operations on socket.
233297
impl AsyncWrite for TcpStream {
234298
fn poll_write(
235299
self: Pin<&mut Self>,
@@ -308,6 +372,7 @@ pub mod runtime {
308372
// We use a `SyncSender` as opposed to a regular `Sender` to allow for sharing
309373
// the sender between threads.
310374
ready_queue: mpsc::SyncSender<usize>,
375+
// Unique identifier for this task.
311376
token: usize,
312377
}
313378

@@ -348,7 +413,6 @@ pub mod runtime {
348413
}
349414
}
350415

351-
352416
impl Reactor {
353417
// Create a new Reactor instance.
354418
pub fn new(sender: mpsc::SyncSender<usize>) -> Reactor {
@@ -400,7 +464,10 @@ pub mod runtime {
400464
let mut finished = false;
401465
{
402466
// println!("Executor::run --> received {}", token);
403-
let task = self.task_map.get(&token).unwrap_or_else(|| panic!("Invalid task token {}", token));
467+
let task = self
468+
.task_map
469+
.get(&token)
470+
.unwrap_or_else(|| panic!("Invalid task token {}", token));
404471
let future = &mut *task.future.lock().unwrap();
405472

406473
let waker = Waker::from(Arc::clone(&task));
@@ -414,7 +481,7 @@ pub mod runtime {
414481
// be pointing to garbage upon calling remove.
415482
if finished {
416483
self.task_map.remove(&token).unwrap();
417-
484+
418485
// Done processing all suspended events.
419486
if self.task_map.is_empty() {
420487
break;

0 commit comments

Comments
 (0)