From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- third_party/rust/mio/examples/tcp_server.rs | 183 ++++++++++++++++++++++++++++ third_party/rust/mio/examples/udp_server.rs | 77 ++++++++++++ 2 files changed, 260 insertions(+) create mode 100644 third_party/rust/mio/examples/tcp_server.rs create mode 100644 third_party/rust/mio/examples/udp_server.rs (limited to 'third_party/rust/mio/examples') diff --git a/third_party/rust/mio/examples/tcp_server.rs b/third_party/rust/mio/examples/tcp_server.rs new file mode 100644 index 0000000000..6347ab6de0 --- /dev/null +++ b/third_party/rust/mio/examples/tcp_server.rs @@ -0,0 +1,183 @@ +// You can run this example from the root of the mio repo: +// cargo run --example tcp_server --features="os-poll net" +use mio::event::Event; +use mio::net::{TcpListener, TcpStream}; +use mio::{Events, Interest, Poll, Registry, Token}; +use std::collections::HashMap; +use std::io::{self, Read, Write}; +use std::str::from_utf8; + +// Setup some tokens to allow us to identify which event is for which socket. +const SERVER: Token = Token(0); + +// Some data we'll send over the connection. +const DATA: &[u8] = b"Hello world!\n"; + +fn main() -> io::Result<()> { + env_logger::init(); + + // Create a poll instance. + let mut poll = Poll::new()?; + // Create storage for events. + let mut events = Events::with_capacity(128); + + // Setup the TCP server socket. + let addr = "127.0.0.1:9000".parse().unwrap(); + let mut server = TcpListener::bind(addr)?; + + // Register the server with poll we can receive events for it. + poll.registry() + .register(&mut server, SERVER, Interest::READABLE)?; + + // Map of `Token` -> `TcpStream`. + let mut connections = HashMap::new(); + // Unique token for each incoming connection. + let mut unique_token = Token(SERVER.0 + 1); + + println!("You can connect to the server using `nc`:"); + println!(" $ nc 127.0.0.1 9000"); + println!("You'll see our welcome message and anything you type will be printed here."); + + loop { + poll.poll(&mut events, None)?; + + for event in events.iter() { + match event.token() { + SERVER => loop { + // Received an event for the TCP server socket, which + // indicates we can accept an connection. + let (mut connection, address) = match server.accept() { + Ok((connection, address)) => (connection, address), + Err(e) if e.kind() == io::ErrorKind::WouldBlock => { + // If we get a `WouldBlock` error we know our + // listener has no more incoming connections queued, + // so we can return to polling and wait for some + // more. + break; + } + Err(e) => { + // If it was any other kind of error, something went + // wrong and we terminate with an error. + return Err(e); + } + }; + + println!("Accepted connection from: {}", address); + + let token = next(&mut unique_token); + poll.registry().register( + &mut connection, + token, + Interest::READABLE.add(Interest::WRITABLE), + )?; + + connections.insert(token, connection); + }, + token => { + // Maybe received an event for a TCP connection. + let done = if let Some(connection) = connections.get_mut(&token) { + handle_connection_event(poll.registry(), connection, event)? + } else { + // Sporadic events happen, we can safely ignore them. + false + }; + if done { + if let Some(mut connection) = connections.remove(&token) { + poll.registry().deregister(&mut connection)?; + } + } + } + } + } + } +} + +fn next(current: &mut Token) -> Token { + let next = current.0; + current.0 += 1; + Token(next) +} + +/// Returns `true` if the connection is done. +fn handle_connection_event( + registry: &Registry, + connection: &mut TcpStream, + event: &Event, +) -> io::Result { + if event.is_writable() { + // We can (maybe) write to the connection. + match connection.write(DATA) { + // We want to write the entire `DATA` buffer in a single go. If we + // write less we'll return a short write error (same as + // `io::Write::write_all` does). + Ok(n) if n < DATA.len() => return Err(io::ErrorKind::WriteZero.into()), + Ok(_) => { + // After we've written something we'll reregister the connection + // to only respond to readable events. + registry.reregister(connection, event.token(), Interest::READABLE)? + } + // Would block "errors" are the OS's way of saying that the + // connection is not actually ready to perform this I/O operation. + Err(ref err) if would_block(err) => {} + // Got interrupted (how rude!), we'll try again. + Err(ref err) if interrupted(err) => { + return handle_connection_event(registry, connection, event) + } + // Other errors we'll consider fatal. + Err(err) => return Err(err), + } + } + + if event.is_readable() { + let mut connection_closed = false; + let mut received_data = vec![0; 4096]; + let mut bytes_read = 0; + // We can (maybe) read from the connection. + loop { + match connection.read(&mut received_data[bytes_read..]) { + Ok(0) => { + // Reading 0 bytes means the other side has closed the + // connection or is done writing, then so are we. + connection_closed = true; + break; + } + Ok(n) => { + bytes_read += n; + if bytes_read == received_data.len() { + received_data.resize(received_data.len() + 1024, 0); + } + } + // Would block "errors" are the OS's way of saying that the + // connection is not actually ready to perform this I/O operation. + Err(ref err) if would_block(err) => break, + Err(ref err) if interrupted(err) => continue, + // Other errors we'll consider fatal. + Err(err) => return Err(err), + } + } + + if bytes_read != 0 { + let received_data = &received_data[..bytes_read]; + if let Ok(str_buf) = from_utf8(received_data) { + println!("Received data: {}", str_buf.trim_end()); + } else { + println!("Received (none UTF-8) data: {:?}", received_data); + } + } + + if connection_closed { + println!("Connection closed"); + return Ok(true); + } + } + + Ok(false) +} + +fn would_block(err: &io::Error) -> bool { + err.kind() == io::ErrorKind::WouldBlock +} + +fn interrupted(err: &io::Error) -> bool { + err.kind() == io::ErrorKind::Interrupted +} diff --git a/third_party/rust/mio/examples/udp_server.rs b/third_party/rust/mio/examples/udp_server.rs new file mode 100644 index 0000000000..ed6881d99c --- /dev/null +++ b/third_party/rust/mio/examples/udp_server.rs @@ -0,0 +1,77 @@ +// You can run this example from the root of the mio repo: +// cargo run --example udp_server --features="os-poll net" +use log::warn; +use mio::net::UdpSocket; +use mio::{Events, Interest, Poll, Token}; +use std::io; + +// A token to allow us to identify which event is for the `UdpSocket`. +const UDP_SOCKET: Token = Token(0); + +fn main() -> io::Result<()> { + env_logger::init(); + + // Create a poll instance. + let mut poll = Poll::new()?; + // Create storage for events. Since we will only register a single socket, a + // capacity of 1 will do. + let mut events = Events::with_capacity(1); + + // Setup the UDP socket. + let addr = "127.0.0.1:9000".parse().unwrap(); + let mut socket = UdpSocket::bind(addr)?; + + // Register our socket with the token defined above and an interest in being + // `READABLE`. + poll.registry() + .register(&mut socket, UDP_SOCKET, Interest::READABLE)?; + + println!("You can connect to the server using `nc`:"); + println!(" $ nc -u 127.0.0.1 9000"); + println!("Anything you type will be echoed back to you."); + + // Initialize a buffer for the UDP packet. We use the maximum size of a UDP + // packet, which is the maximum value of 16 a bit integer. + let mut buf = [0; 1 << 16]; + + // Our event loop. + loop { + // Poll to check if we have events waiting for us. + poll.poll(&mut events, None)?; + + // Process each event. + for event in events.iter() { + // Validate the token we registered our socket with, + // in this example it will only ever be one but we + // make sure it's valid none the less. + match event.token() { + UDP_SOCKET => loop { + // In this loop we receive all packets queued for the socket. + match socket.recv_from(&mut buf) { + Ok((packet_size, source_address)) => { + // Echo the data. + socket.send_to(&buf[..packet_size], source_address)?; + } + Err(e) if e.kind() == io::ErrorKind::WouldBlock => { + // If we get a `WouldBlock` error we know our socket + // has no more packets queued, so we can return to + // polling and wait for some more. + break; + } + Err(e) => { + // If it was any other kind of error, something went + // wrong and we terminate with an error. + return Err(e); + } + } + }, + _ => { + // This should never happen as we only registered our + // `UdpSocket` using the `UDP_SOCKET` token, but if it ever + // does we'll log it. + warn!("Got event for unexpected token: {:?}", event); + } + } + } + } +} -- cgit v1.2.3