Ping pong
This commit is contained in:
+24
-34
@@ -2,7 +2,6 @@ use std::{
|
|||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
io::{self, Read, Write},
|
io::{self, Read, Write},
|
||||||
net::{SocketAddr, TcpStream},
|
net::{SocketAddr, TcpStream},
|
||||||
time::Duration,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
@@ -125,25 +124,11 @@ pub mod handshake {
|
|||||||
pub struct Client(TcpStream, Option<String>, u64);
|
pub struct Client(TcpStream, Option<String>, u64);
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
/// Create a client with no timeouts
|
/// Create a client
|
||||||
pub fn new(mut stream: TcpStream) -> crate::Result<Self> {
|
pub fn new(mut stream: TcpStream) -> crate::Result<Self> {
|
||||||
handshake::handle_websocket_handshake(&mut stream)?;
|
handshake::handle_websocket_handshake(&mut stream)?;
|
||||||
Ok(Client(stream, None, rand::random()))
|
stream.set_read_timeout(Some(std::time::Duration::from_secs(10)))?;
|
||||||
}
|
stream.set_write_timeout(Some(std::time::Duration::from_secs(10)))?;
|
||||||
|
|
||||||
/// Create a client and set read/write timeouts (useful in prod)
|
|
||||||
pub fn with_timeouts(
|
|
||||||
mut stream: TcpStream,
|
|
||||||
read_timeout: Option<Duration>,
|
|
||||||
write_timeout: Option<Duration>,
|
|
||||||
) -> crate::Result<Self> {
|
|
||||||
if let Some(t) = read_timeout {
|
|
||||||
stream.set_read_timeout(Some(t))?;
|
|
||||||
}
|
|
||||||
if let Some(t) = write_timeout {
|
|
||||||
stream.set_write_timeout(Some(t))?;
|
|
||||||
}
|
|
||||||
handshake::handle_websocket_handshake(&mut stream)?;
|
|
||||||
Ok(Client(stream, None, rand::random()))
|
Ok(Client(stream, None, rand::random()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,18 +154,20 @@ impl Client {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a pong with given payload (control frames must be <=125)
|
/// Send a ping (no payload)
|
||||||
fn send_pong(&self, payload: &[u8]) -> crate::Result<()> {
|
fn send_ping(&self) -> crate::Result<()> {
|
||||||
let mut stream = self.0.try_clone()?;
|
let mut stream = self.0.try_clone()?;
|
||||||
|
// FIN + opcode (ping = 0x89), payload length = 0x00
|
||||||
if payload.len() > 125 {
|
stream.write_all(&[0x89, 0x00])?;
|
||||||
return Err(anyhow!("pong payload too long").into());
|
stream.flush()?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
let mut frame = Vec::with_capacity(2 + payload.len());
|
|
||||||
frame.push(0x8A); // FIN=1, opcode=0xA (Pong)
|
/// Send a pong (no payload)
|
||||||
frame.push(payload.len() as u8);
|
fn send_pong(&self) -> crate::Result<()> {
|
||||||
frame.extend_from_slice(payload);
|
let mut stream = self.0.try_clone()?;
|
||||||
stream.write_all(&frame)?;
|
// FIN + opcode (pong = 0x8A), payload length = 0x00
|
||||||
|
stream.write_all(&[0x8A, 0x00])?;
|
||||||
stream.flush()?;
|
stream.flush()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -229,9 +216,14 @@ impl Client {
|
|||||||
// read the 2-byte header
|
// read the 2-byte header
|
||||||
let mut header = [0u8; 2];
|
let mut header = [0u8; 2];
|
||||||
if let Err(e) = stream.read_exact(&mut header) {
|
if let Err(e) = stream.read_exact(&mut header) {
|
||||||
|
if e.kind() == io::ErrorKind::WouldBlock || e.kind() == io::ErrorKind::TimedOut {
|
||||||
|
self.send_ping()?;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if e.kind() == io::ErrorKind::UnexpectedEof || e.kind() == io::ErrorKind::BrokenPipe
|
if e.kind() == io::ErrorKind::UnexpectedEof || e.kind() == io::ErrorKind::BrokenPipe
|
||||||
{
|
{
|
||||||
return Ok(None); // treat EOF as closed
|
return Ok(None);
|
||||||
}
|
}
|
||||||
return Err(e.into());
|
return Err(e.into());
|
||||||
}
|
}
|
||||||
@@ -287,9 +279,9 @@ impl Client {
|
|||||||
// Continuation / Text / Binary
|
// Continuation / Text / Binary
|
||||||
message_payload.extend(payload);
|
message_payload.extend(payload);
|
||||||
if fin {
|
if fin {
|
||||||
break; // got full message
|
break;
|
||||||
} else {
|
} else {
|
||||||
continue; // wait for more fragments
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0x8 => {
|
0x8 => {
|
||||||
@@ -309,12 +301,10 @@ impl Client {
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
0x9 => {
|
0x9 => {
|
||||||
// Ping → respond with Pong
|
self.send_pong()?;
|
||||||
let _ = self.send_pong(&payload);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
0xA => {
|
0xA => {
|
||||||
// Pong → ignore
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|||||||
Reference in New Issue
Block a user