use std::io;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::time::Instant;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum DeadlineReason {
Idle = 0,
Connect = 1,
FirstByte = 2,
Custom(u8) = 3,
}
impl DeadlineReason {
#[must_use]
pub fn aux(self) -> u16 {
match self {
Self::Idle => 0,
Self::Connect => 1,
Self::FirstByte => 2,
Self::Custom(b) => u16::from(b) | (1 << 8),
}
}
#[must_use]
pub fn from_aux(aux: u16) -> Self {
match aux {
0 => Self::Idle,
1 => Self::Connect,
2 => Self::FirstByte,
other => Self::Custom((other & 0xff) as u8),
}
}
}
use crate::worker::WorkerCtx;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Mode {
Http,
L4,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UpstreamDial {
Initiated,
Established,
}
pub trait Handler: Send + 'static {
fn on_connected(&mut self, io: &mut SessionIo<'_>) {
let _ = io;
}
fn on_downstream_data(&mut self, io: &mut SessionIo<'_>, data: &[u8]);
fn on_downstream_flushed(&mut self, io: &mut SessionIo<'_>) {
let _ = io;
}
fn on_upstream_connected(&mut self, io: &mut SessionIo<'_>);
fn on_upstream_data(&mut self, io: &mut SessionIo<'_>, data: &[u8]);
fn on_upstream_flushed(&mut self, io: &mut SessionIo<'_>) {
let _ = io;
}
fn on_downstream_eof(&mut self, io: &mut SessionIo<'_>);
fn on_upstream_eof(&mut self, io: &mut SessionIo<'_>);
fn on_downstream_error(&mut self, io: &mut SessionIo<'_>, err: io::Error) {
let _ = err;
io.close();
}
fn on_upstream_error(&mut self, io: &mut SessionIo<'_>, err: io::Error);
fn on_shutdown_hint(&mut self, io: &mut SessionIo<'_>) {
let _ = io;
}
fn on_deadline(&mut self, io: &mut SessionIo<'_>, reason: DeadlineReason) {
let _ = reason;
io.close();
}
}
pub trait HandlerFactory: Send + Sync + 'static {
fn mode(&self) -> Mode;
fn build(&self, ctx: &WorkerCtx) -> Box<dyn Handler>;
}
pub struct SessionIo<'a> {
pub(crate) worker: &'a mut super::worker::WorkerState,
pub(crate) slot: u32,
pub(crate) generation: u16,
}
impl<'a> SessionIo<'a> {
#[must_use]
pub fn slot_index(&self) -> u32 {
self.slot
}
pub fn respond(&mut self, bytes: &[u8]) {
self.worker
.downstream_write(self.slot, self.generation, bytes);
}
pub fn write_upstream(&mut self, bytes: &[u8]) {
self.worker
.upstream_write(self.slot, self.generation, bytes);
}
pub fn connect_upstream(&mut self, addr: SocketAddr) -> bool {
self.worker
.connect_upstream(self.slot, self.generation, addr)
}
pub fn connect_upstream_unix(&mut self, path: PathBuf) -> bool {
self.worker
.connect_upstream_unix(self.slot, self.generation, path)
}
pub fn start_splice(&mut self) -> bool {
self.worker.start_splice(self.slot, self.generation)
}
pub fn downstream_eof_write(&mut self) {
self.worker
.shutdown_downstream_write(self.slot, self.generation);
}
pub fn upstream_eof_write(&mut self) {
self.worker
.shutdown_upstream_write(self.slot, self.generation);
}
pub fn close(&mut self) {
self.worker
.close_session(self.slot, self.generation, "handler");
}
pub fn set_deadline(&mut self, at: Option<Instant>, reason: DeadlineReason) {
self.worker
.set_deadline(self.slot, self.generation, at, reason);
}
#[must_use]
pub fn detach_upstream(&mut self) -> Option<std::os::fd::RawFd> {
self.worker.detach_upstream(self.slot, self.generation)
}
pub fn discard_upstream(&mut self) {
self.worker.discard_upstream(self.slot, self.generation);
}
pub fn attach_upstream(&mut self, fd: std::os::fd::RawFd) -> bool {
self.worker.attach_upstream(self.slot, self.generation, fd)
}
#[must_use]
pub fn upstream_fd(&self) -> Option<std::os::fd::RawFd> {
self.worker.upstream_fd(self.slot, self.generation)
}
#[must_use]
pub fn request_sent_upstream(&self) -> bool {
self.worker.request_sent(self.slot, self.generation)
}
pub fn mark_request_sent(&mut self) {
self.worker.mark_request_sent(self.slot, self.generation);
}
#[must_use]
pub fn peer(&self) -> Option<SocketAddr> {
self.worker.peer_of(self.slot, self.generation)
}
#[must_use]
pub fn has_upstream(&self) -> bool {
self.worker.has_upstream(self.slot, self.generation)
}
}