Support multiple connectors to listener
This commit is contained in:
+33
-35
@@ -9,17 +9,14 @@ use std::{
|
||||
fn from_syscall_error(error: syscall::Error) -> io::Error {
|
||||
io::Error::from_raw_os_error(error.errno as i32)
|
||||
}
|
||||
fn nonblock(file: &File) -> io::Result<()> {
|
||||
syscall::fcntl(file.as_raw_fd() as usize, syscall::F_SETFL, syscall::O_NONBLOCK)
|
||||
.map(|_| ())
|
||||
.map_err(from_syscall_error)
|
||||
}
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let server = File::create("chan:log")?;
|
||||
let mut event_file = File::open("event:")?;
|
||||
|
||||
nonblock(&server)?;
|
||||
syscall::fcntl(server.as_raw_fd() as usize, syscall::F_SETFL, syscall::O_NONBLOCK)
|
||||
.map(|_| ())
|
||||
.map_err(from_syscall_error)?;
|
||||
event_file.write(&syscall::Event {
|
||||
id: server.as_raw_fd() as usize,
|
||||
data: 0,
|
||||
@@ -36,41 +33,28 @@ fn main() -> io::Result<()> {
|
||||
if event.data == 0 {
|
||||
println!("Listener recevied flags: {}", event.flags);
|
||||
if event.flags & syscall::EVENT_WRITE == syscall::EVENT_WRITE {
|
||||
let stream = syscall::dup(server.as_raw_fd() as usize, b"listen").map_err(from_syscall_error)?;
|
||||
let stream = unsafe { File::from_raw_fd(stream as RawFd) };
|
||||
loop {
|
||||
let stream = match syscall::dup(server.as_raw_fd() as usize, b"listen").map_err(from_syscall_error) {
|
||||
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => break,
|
||||
stream => stream?
|
||||
};
|
||||
let stream = unsafe { File::from_raw_fd(stream as RawFd) };
|
||||
|
||||
nonblock(&stream)?;
|
||||
event_file.write(&syscall::Event {
|
||||
id: stream.as_raw_fd() as usize,
|
||||
data: next_id,
|
||||
flags: syscall::EVENT_READ | syscall::EVENT_WRITE,
|
||||
})?;
|
||||
event_file.write(&syscall::Event {
|
||||
id: stream.as_raw_fd() as usize,
|
||||
data: next_id,
|
||||
flags: syscall::EVENT_READ | syscall::EVENT_WRITE,
|
||||
})?;
|
||||
|
||||
clients.insert(next_id, stream);
|
||||
next_id += 1;
|
||||
clients.insert(next_id, stream);
|
||||
println!("-> Spawned client #{}", next_id);
|
||||
next_id += 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("Client #{} received flags: {}", event.data, event.flags);
|
||||
let client = clients.get_mut(&event.data).unwrap();
|
||||
|
||||
if event.flags & syscall::EVENT_WRITE == syscall::EVENT_WRITE {
|
||||
println!("-> Writing");
|
||||
const BUF: &str = "Hello from the log server\n";
|
||||
let mut written = 0;
|
||||
while written < BUF.len() {
|
||||
let len = match client.write(BUF[written..].as_bytes()) {
|
||||
Ok(0) => {
|
||||
println!("--> EOF");
|
||||
clients.remove(&event.data);
|
||||
continue 'outer;
|
||||
},
|
||||
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => break,
|
||||
len => len?
|
||||
};
|
||||
println!("--> Wrote {}/{} bytes: {:?}", len, BUF.len(), &BUF[written..]);
|
||||
written += len;
|
||||
}
|
||||
}
|
||||
if event.flags & syscall::EVENT_READ == syscall::EVENT_READ {
|
||||
println!("-> Reading");
|
||||
let mut buf = [0; 128];
|
||||
@@ -84,7 +68,21 @@ fn main() -> io::Result<()> {
|
||||
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => break,
|
||||
len => len?
|
||||
};
|
||||
println!("--> Read {}/128 bytes: {:?}", len, str::from_utf8(&buf));
|
||||
println!("--> Read {}/128 bytes: {:?}", len, str::from_utf8(&buf[..len]));
|
||||
}
|
||||
}
|
||||
if event.flags & syscall::EVENT_WRITE == syscall::EVENT_WRITE {
|
||||
println!("-> Writing");
|
||||
const BUF: &str = "Hello from the log server\n";
|
||||
let mut written = 0;
|
||||
while written < BUF.len() {
|
||||
let len = match client.write(BUF[written..].as_bytes()) {
|
||||
Ok(0) => panic!("EOF should never happen here"),
|
||||
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => break,
|
||||
len => len?
|
||||
};
|
||||
println!("--> Wrote {}/{} bytes: {:?}", len, BUF.len(), &BUF[written..]);
|
||||
written += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-7
@@ -1,5 +1,5 @@
|
||||
use std::{
|
||||
fs::File,
|
||||
fs::{File, OpenOptions},
|
||||
io::{self, prelude::*},
|
||||
os::unix::io::{AsRawFd, FromRawFd, RawFd},
|
||||
thread,
|
||||
@@ -23,11 +23,24 @@ fn main() -> io::Result<()> {
|
||||
let mut buf = [0; 5];
|
||||
let server = File::create("chan:hello_world")?;
|
||||
{
|
||||
let mut client = File::open("chan:hello_world")?;
|
||||
// First client not accepted yet
|
||||
assert_eq!(File::open("chan:hello_world").unwrap_err().kind(), io::ErrorKind::ConnectionRefused);
|
||||
println!("Testing O_EXCL...");
|
||||
assert_eq!(
|
||||
OpenOptions::new()
|
||||
.write(true)
|
||||
.create_new(true)
|
||||
.open("chan:hello_world").unwrap_err().kind(),
|
||||
io::ErrorKind::AlreadyExists
|
||||
);
|
||||
|
||||
println!("Testing connecting...");
|
||||
|
||||
File::open("chan:hello_world")?; // closed connection will silently be skipped
|
||||
let mut client = File::create("chan:hello_world")?; // O_CREAT without O_EXCL does nothing
|
||||
let tmp = File::open("chan:hello_world")?; // multiple connections are handled
|
||||
|
||||
let mut stream = dup(&server, "listen")?;
|
||||
assert!(dup(&server, "listen").is_ok());
|
||||
drop(tmp);
|
||||
|
||||
println!("Testing basic I/O...");
|
||||
|
||||
@@ -89,9 +102,6 @@ fn main() -> io::Result<()> {
|
||||
println!("-> Write before accept would block");
|
||||
}
|
||||
|
||||
assert_eq!(dup(&server, "listen").unwrap_err().kind(), io::ErrorKind::ConnectionReset);
|
||||
println!("-> Server can't accept dropped client");
|
||||
|
||||
let mut client = dup(&server, "connect")?;
|
||||
nonblock(&client)?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user