105 lines
2.9 KiB
Rust
105 lines
2.9 KiB
Rust
use std::{
|
|
collections::HashSet,
|
|
io::{self, Read, Result, Write},
|
|
net::TcpStream,
|
|
};
|
|
|
|
use ffi::Event;
|
|
use poll::Poll;
|
|
|
|
mod ffi;
|
|
mod poll;
|
|
|
|
fn get_req(path: &str) -> String {
|
|
format!(
|
|
"GET {path} HTTP/1.1\r\n\
|
|
Host: localhost\r\n\
|
|
Connection: close\r\n\
|
|
\r\n"
|
|
)
|
|
}
|
|
|
|
fn handle_events(
|
|
events: &[Event],
|
|
streams: &mut [TcpStream],
|
|
// FIX #4: accepts a set of handled events as argument
|
|
handled: &mut HashSet<usize>,
|
|
) -> Result<usize> {
|
|
let mut handled_events = 0;
|
|
for event in events {
|
|
let index = event.token();
|
|
let mut data = vec![0u8; 4096];
|
|
|
|
loop {
|
|
match streams[index].read(&mut data) {
|
|
Ok(n) if n == 0 => {
|
|
// FIX #4
|
|
// `insert` returns false if the value already existed in the set.
|
|
if !handled.insert(index) {
|
|
break;
|
|
}
|
|
handled_events += 1;
|
|
break;
|
|
}
|
|
Ok(n) => {
|
|
let txt = String::from_utf8_lossy(&data[..n]);
|
|
|
|
println!("RECEIVED: {:?}", event);
|
|
println!("{txt}\n------\n");
|
|
}
|
|
Err(e) if e.kind() == io::ErrorKind::WouldBlock => break,
|
|
// this was not in the book example, but it's a error condition
|
|
// you probably want to handle in some way (either by breaking
|
|
// out of the loop or trying a new read call immediately)
|
|
Err(e) if e.kind() == io::ErrorKind::Interrupted => break,
|
|
Err(e) => return Err(e),
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(handled_events)
|
|
}
|
|
|
|
fn main() -> Result<()> {
|
|
let mut poll = Poll::new()?;
|
|
let n_events = 5;
|
|
|
|
let mut streams = vec![];
|
|
let addr = "localhost:8080";
|
|
|
|
for i in 0..n_events {
|
|
let delay = (n_events - i) * 1000;
|
|
let url_path = format!("/{delay}/request-{i}");
|
|
let request = get_req(&url_path);
|
|
let mut stream = std::net::TcpStream::connect(addr)?;
|
|
stream.set_nonblocking(true)?;
|
|
|
|
stream.write_all(request.as_bytes())?;
|
|
// NB! Token is equal to index in Vec
|
|
poll.registry()
|
|
.register(&stream, i, ffi::EPOLLIN | ffi::EPOLLET)?;
|
|
|
|
streams.push(stream);
|
|
}
|
|
|
|
// FIX #4: store the handled IDs
|
|
let mut handled_ids = HashSet::new();
|
|
|
|
let mut handled_events = 0;
|
|
while handled_events < n_events {
|
|
let mut events = Vec::with_capacity(10);
|
|
poll.poll(&mut events, None)?;
|
|
|
|
if events.is_empty() {
|
|
println!("TIMEOUT (OR SPURIOUS EVENT NOTIFICATION)");
|
|
continue;
|
|
}
|
|
|
|
// ------------------------------------------------------⌄ FIX #4 (new signature)
|
|
handled_events += handle_events(&events, &mut streams, &mut handled_ids)?;
|
|
}
|
|
|
|
println!("FINISHED");
|
|
Ok(())
|
|
}
|