From 962019e31049a82ac56c2b5d55607b5d31ee442e Mon Sep 17 00:00:00 2001 From: TQ Hirsch Date: Thu, 11 May 2023 18:04:05 +0200 Subject: [PATCH] d3270d now manages to connect and login with commands from netcat --- Cargo.lock | 67 +++++++++++++++++++++++++++- d3270-common/src/b3270.rs | 5 ++- d3270-common/src/b3270/indication.rs | 53 +++++++++++++--------- d3270-common/src/b3270/operation.rs | 2 +- d3270-common/src/b3270/types.rs | 5 ++- d3270-common/src/tracker.rs | 19 +++----- d3270d/Cargo.toml | 1 + d3270d/src/arbiter.rs | 19 +++++--- d3270d/src/main.rs | 23 +++++++++- d3270d/src/tcp_server.rs | 11 ++++- 10 files changed, 155 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c46b4cf..39fcdfe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -653,6 +653,7 @@ dependencies = [ "tokio-stream", "tracing", "tracing-fmt", + "tracing-subscriber 0.3.17", ] [[package]] @@ -1150,6 +1151,15 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata", +] + [[package]] name = "maybe-uninit" version = "2.0.0" @@ -1174,6 +1184,16 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -1215,6 +1235,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "owning_ref" version = "0.4.1" @@ -1636,6 +1662,15 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + [[package]] name = "signal-hook" version = "0.3.15" @@ -1828,6 +1863,16 @@ dependencies = [ "syn 2.0.15", ] +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", +] + [[package]] name = "tide" version = "0.16.0" @@ -2027,7 +2072,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "880547feb88739526e322a366be2411c41c797f0dabcddfe99a3216e5a664f71" dependencies = [ - "tracing-subscriber", + "tracing-subscriber 0.1.6", ] [[package]] @@ -2050,7 +2095,7 @@ dependencies = [ "ansi_term", "chrono", "lazy_static", - "matchers", + "matchers 0.0.1", "owning_ref", "regex", "smallvec 0.6.14", @@ -2058,6 +2103,24 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "tracing-subscriber" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +dependencies = [ + "matchers 0.1.0", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec 1.10.0", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + [[package]] name = "tungstenite" version = "0.13.0" diff --git a/d3270-common/src/b3270.rs b/d3270-common/src/b3270.rs index 7af56b2..9997680 100644 --- a/d3270-common/src/b3270.rs +++ b/d3270-common/src/b3270.rs @@ -11,6 +11,7 @@ pub mod operation; pub mod types; #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +#[serde(rename_all="kebab-case")] pub enum Indication { Bell {}, // TODO: make sure this emits/parses {"bell": {}} /// Indicates that the host connection has changed state. @@ -61,8 +62,6 @@ pub enum Indication { Setting(Setting), /// I/O statistics Stats(Stats), - /// Reports the terminal name sent to the host during TELNET negotiation - TerminalName(TerminalName), /// Change in the scrollbar thumb Thumb(Thumb), /// Indicates the name of the trace file @@ -101,6 +100,8 @@ pub enum InitializeIndication { ScreenMode(ScreenMode), /// Setting changed Setting(Setting), + /// Reports the terminal name sent to the host during TELNET negotiation + TerminalName(TerminalName), /// Scroll thumb position Thumb(Thumb), /// Indicates build-time TLS config diff --git a/d3270-common/src/b3270/indication.rs b/d3270-common/src/b3270/indication.rs index f5a8a40..0ad23d0 100644 --- a/d3270-common/src/b3270/indication.rs +++ b/d3270-common/src/b3270/indication.rs @@ -61,12 +61,12 @@ pub enum ConnectionState { TelnetPending, ConnectedNvt, ConnectedNvtCharmode, + #[serde(rename="connected-3270")] Connected3270, ConnectedUnbound, ConnectedENvt, - ConnectedESscp, - #[serde(rename = "connected-e-tn3270e")] - ConnectedETn3270e, + ConnectedSscp, + ConnectedTn3270e, } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)] @@ -154,7 +154,7 @@ pub enum OiaField { }, /// Host command timer (minutes:seconds) Script { - value: String, + value: bool, }, Timing { #[serde(default, skip_serializing_if = "Option::is_none")] @@ -200,8 +200,9 @@ impl OiaField { #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] pub struct Proxy { pub name: String, - pub username: String, - pub port: u16, + pub username: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub port: Option, } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] @@ -209,14 +210,15 @@ pub struct Setting { pub name: String, /// I'd love something other than depending on serde_json for this. pub value: Option, - pub cause: ActionCause, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub cause: Option, } #[derive(Serialize, Deserialize, Debug, PartialEq, Copy, Clone)] pub struct ScreenMode { pub model: u8, pub rows: u8, - pub cols: u8, + pub columns: u8, pub color: bool, pub oversize: bool, pub extended: bool, @@ -284,7 +286,7 @@ pub enum FileTransferState { } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -#[serde(rename = "kebab-case")] +#[serde(rename_all = "kebab-case")] pub struct Passthru { pub p_tag: String, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -304,7 +306,7 @@ pub struct Popup { } #[derive(Serialize, Deserialize, Debug, PartialEq, Copy, Clone)] -#[serde(rename = "kebab-case")] +#[serde(rename_all = "kebab-case")] pub enum PopupType { /// Error message from a connection attempt ConnectError, @@ -321,14 +323,14 @@ pub enum PopupType { } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -#[serde(rename = "kebab-case")] +#[serde(rename_all = "kebab-case")] pub struct Row { pub row: u8, pub changes: Vec, } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -#[serde(rename = "kebab-case")] +#[serde(rename_all = "kebab-case")] pub enum CountOrText { Count(usize), Text(String), @@ -357,7 +359,7 @@ pub struct Screen { } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -#[serde(rename = "kebab-case")] +#[serde(rename_all = "kebab-case")] pub struct RunResult { #[serde(default, skip_serializing_if = "Option::is_none")] pub r_tag: Option, @@ -371,7 +373,7 @@ pub struct RunResult { } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -#[serde(rename = "kebab-case")] +#[serde(rename_all = "kebab-case")] pub struct Scroll { #[serde(default, skip_serializing_if = "Option::is_none")] pub fg: Option, @@ -380,7 +382,7 @@ pub struct Scroll { } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -#[serde(rename = "kebab-case")] +#[serde(rename_all = "kebab-case")] pub struct Stats { pub bytes_received: usize, pub bytes_sent: usize, @@ -435,12 +437,23 @@ mod test { #[test] pub fn connection_state_serializes_as_expected() { assert_eq!( - serde_json::to_string(&ConnectionState::ConnectedETn3270e).unwrap(), - r#""connected-e-tn3270e""# + serde_json::to_string(&ConnectionState::ConnectedTn3270e).unwrap(), + r#""connected-tn3270e""# ); assert_eq!( - serde_json::to_string(&ConnectionState::ConnectedESscp).unwrap(), - r#""connected-e-sscp""# + serde_json::to_string(&ConnectionState::ConnectedSscp).unwrap(), + r#""connected-sscp""# ); } -} + + fn parse_row() { + let instr = r#"[{"row":1,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","text":"z/OS V1R13 PUT Level 1401"},{"column":26,"fg":"red","gr":"highlight,selectable","count":26},{"column":52,"fg":"red","gr":"highlight,selectable","text":"IP Address = 10.24.74.32 "}]},{"row":2,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":51},{"column":52,"fg":"red","gr":"highlight,selectable","text":"VTAM Terminal = SC0TCP05 "}]},{"row":3,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":80}]},{"row":4,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":23},{"column":24,"fg":"red","gr":"highlight,selectable","text":"Application Developer System"},{"column":52,"fg":"red","gr":"highlight,selectable","count":29}]},{"row":5,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":80}]},{"row":6,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":32},{"column":33,"fg":"red","gr":"highlight,selectable","text":"// OOOOOOO SSSSS"},{"column":52,"fg":"red","gr":"highlight,selectable","count":29}]},{"row":7,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":31},{"column":32,"fg":"red","gr":"highlight,selectable","text":"// OO OO SS"},{"column":47,"fg":"red","gr":"highlight,selectable","count":34}]},{"row":8,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":23},{"column":24,"fg":"red","gr":"highlight,selectable","text":"zzzzzz // OO OO SS"},{"column":46,"fg":"red","gr":"highlight,selectable","count":35}]},{"row":9,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":25},{"column":26,"fg":"red","gr":"highlight,selectable","text":"zz // OO OO SSSS"},{"column":47,"fg":"red","gr":"highlight,selectable","count":34}]},{"row":10,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":23},{"column":24,"fg":"red","gr":"highlight,selectable","text":"zz // OO OO SS"},{"column":49,"fg":"red","gr":"highlight,selectable","count":32}]},{"row":11,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":21},{"column":22,"fg":"red","gr":"highlight,selectable","text":"zz // OO OO SS"},{"column":48,"fg":"red","gr":"highlight,selectable","count":33}]},{"row":12,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":19},{"column":20,"fg":"red","gr":"highlight,selectable","text":"zzzzzz // OOOOOOO SSSS"},{"column":45,"fg":"red","gr":"highlight,selectable","count":36}]},{"row":13,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":80}]},{"row":14,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":80}]},{"row":15,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":19},{"column":20,"fg":"red","gr":"highlight,selectable","text":"System Customization - ADCD.Z113H.*"},{"column":55,"fg":"red","gr":"highlight,selectable","count":26}]},{"row":16,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":80}]},{"row":17,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":80}]},{"row":18,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":80}]},{"row":19,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":80}]},{"row":20,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","text":" ===> Enter \"LOGON\" followed by the TSO userid. Example \"LOGON IBMUSER\" or "}]},{"row":21,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","text":" ===> Enter L followed by the APPLID"},{"column":37,"fg":"red","gr":"highlight,selectable","count":44}]},{"row":22,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","text":" ===> Examples: \"L TSO\", \"L CICSTS41\", \"L CICSTS42\", \"L IMS11\", \"L IMS12\" "}]},{"row":23,"changes":[{"column":1,"fg":"red","gr":"highlight,selectable","count":79},{"column":80,"fg":"green","count":1}]},{"row":24,"changes":[{"column":1,"fg":"green","count":79},{"column":80,"fg":"red","gr":"highlight,selectable","count":1}]}]"#; + if let Err(err) = serde_json::from_slice::>(instr.as_bytes()) { + let pos = err.column(); + println!("Parse error: {err}"); + let (pre, post) = instr.split_at(err.column()); + println!("Context: {pre}\x1b[1;31m{post}\x1b[0m"); + panic!("{}", err); + } + } +} \ No newline at end of file diff --git a/d3270-common/src/b3270/operation.rs b/d3270-common/src/b3270/operation.rs index b7a0cc4..a29e30e 100644 --- a/d3270-common/src/b3270/operation.rs +++ b/d3270-common/src/b3270/operation.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; // {"run":{"actions":[{"action":"Connect","args":["10.24.74.37:3270"]}]}} -// {"run":{"actions":"Key(a)"}} +// {"run":{"actions":[{"action":"Key","args":["a"]}]}} // Operations #[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Clone)] #[serde(rename_all = "kebab-case")] diff --git a/d3270-common/src/b3270/types.rs b/d3270-common/src/b3270/types.rs index 6c14e9a..491304d 100644 --- a/d3270-common/src/b3270/types.rs +++ b/d3270-common/src/b3270/types.rs @@ -97,6 +97,9 @@ impl FromStr for GraphicRendition { type Err = String; fn from_str(s: &str) -> Result { + if s == "default" { + return Ok(GraphicRendition::empty()); + } s.split(",") .map(|attr| { FLAG_NAMES @@ -136,7 +139,7 @@ mod test { } #[derive(Serialize, Deserialize, Debug, PartialEq, Copy, Clone)] -#[serde(rename = "camelCase")] +#[serde(rename_all = "camelCase")] #[repr(u8)] pub enum Color { NeutralBlack, diff --git a/d3270-common/src/tracker.rs b/d3270-common/src/tracker.rs index 8106863..402730a 100644 --- a/d3270-common/src/tracker.rs +++ b/d3270-common/src/tracker.rs @@ -1,6 +1,6 @@ use crate::b3270::indication::{ Change, Connection, ConnectionState, CountOrText, Cursor, Erase, Oia, OiaFieldName, Row, - RunResult, Screen, ScreenMode, Scroll, Setting, TerminalName, Thumb, Tls, TraceFile, + RunResult, Screen, ScreenMode, Scroll, Setting, Thumb, Tls, TraceFile, }; use crate::b3270::types::{Color, GraphicRendition, PackedAttr}; use crate::b3270::{Indication, InitializeIndication}; @@ -23,7 +23,6 @@ pub struct Tracker { cursor: Cursor, connection: Connection, formatted: bool, - terminal_name: Option, trace_file: Option, tls: Option, @@ -62,7 +61,7 @@ impl Tracker { self.erase.bg = erase.bg.or(self.erase.bg); let rows = self.erase.logical_rows.unwrap_or(self.screen_mode.rows) as usize; - let cols = self.erase.logical_cols.unwrap_or(self.screen_mode.cols) as usize; + let cols = self.erase.logical_cols.unwrap_or(self.screen_mode.columns) as usize; self.screen = vec![ vec![ @@ -92,6 +91,7 @@ impl Tracker { | InitializeIndication::Models(_) | InitializeIndication::Prefixes { .. } | InitializeIndication::Proxies(_) + | InitializeIndication::TerminalName(_) | InitializeIndication::TlsHello(_) | InitializeIndication::Tls(_) | InitializeIndication::TraceFile(_) => static_init.push(indicator), @@ -169,7 +169,7 @@ impl Tracker { self.screen_mode = *mode; self.handle_indication(&mut Indication::Erase(Erase { logical_rows: Some(self.screen_mode.rows), - logical_cols: Some(self.screen_mode.cols), + logical_cols: Some(self.screen_mode.columns), fg: None, bg: None, })); @@ -187,9 +187,6 @@ impl Tracker { Indication::Setting(setting) => { self.settings.insert(setting.name.clone(), setting.clone()); } - Indication::TerminalName(term) => { - self.terminal_name = Some(term.clone()); - } Indication::Thumb(thumb) => { self.thumb = thumb.clone(); } @@ -239,9 +236,6 @@ impl Tracker { state: self.formatted, }, ]; - if let Some(terminal_name) = self.terminal_name.clone() { - result.push(Indication::TerminalName(terminal_name)); - } if let Some(trace_file) = self.trace_file.clone() { result.push(Indication::TraceFile(TraceFile { name: Some(trace_file), @@ -283,7 +277,7 @@ impl Tracker { .map(Self::format_row) .enumerate() .map(|(row_id, changes)| Row { - row: row_id as u8 - 1, + row: row_id as u8 + 1, changes, }) .collect(), @@ -297,7 +291,7 @@ impl Default for Tracker { screen: vec![], oia: Default::default(), screen_mode: ScreenMode { - cols: 80, + columns: 80, rows: 43, color: true, model: 4, @@ -329,7 +323,6 @@ impl Default for Tracker { cause: None, }, formatted: false, - terminal_name: None, trace_file: None, tls: None, static_init: vec![], diff --git a/d3270d/Cargo.toml b/d3270d/Cargo.toml index 7bf24c7..3163259 100644 --- a/d3270d/Cargo.toml +++ b/d3270d/Cargo.toml @@ -16,6 +16,7 @@ d3270-common = {path = "../d3270-common"} bytes = "1.4.0" tracing = "0.1.37" tracing-fmt = "0.1.1" +tracing-subscriber = { version = "0.3.17", features = ["registry", "env-filter"] } futures = "0.3.28" tokio-stream = { version = "0.1.14", features = ["sync"] } rand = "0.8.5" diff --git a/d3270d/src/arbiter.rs b/d3270d/src/arbiter.rs index 29887ac..c8e68ed 100644 --- a/d3270d/src/arbiter.rs +++ b/d3270d/src/arbiter.rs @@ -16,7 +16,7 @@ use tokio_stream::wrappers::{errors::BroadcastStreamRecvError, BroadcastStream}; use tracing::{error, info, info_span, instrument, trace, warn, Instrument}; use d3270_common::b3270::indication::RunResult; -use d3270_common::b3270::operation::Action; +use d3270_common::b3270::operation::{Action, Run}; use d3270_common::b3270::{operation, Indication, Operation}; use d3270_common::tracker::{Disposition, Tracker}; @@ -194,11 +194,16 @@ impl B3270 { let (ind_chan, _) = broadcast::channel(100); let mut write_buf = VecDeque::new(); + // Queue any initial actions. - for action in initial_actions { - serde_json::to_writer(&mut write_buf, action).unwrap(); - write_buf.push_back(b'\n'); - } + let act_str = serde_json::to_string(&Operation::Run(Run{ + actions: initial_actions.to_vec(), + type_: Some("keybind".to_owned()), + r_tag: None, + })).unwrap(); + trace!(json=%act_str, "Writing initialization action"); + write_buf.extend(act_str.as_bytes()); + write_buf.push_back(b'\n'); let proc = B3270 { child, @@ -227,11 +232,11 @@ impl Future for B3270 { match buf { Ok(Some(line)) => match serde_json::from_str(&line) { Ok(ind) => { - trace!(json = line, "Received indication"); + trace!(json = %line, "Received indication"); indications.push(ind) } Err(error) => { - warn!(%error, msg=line, "Failed to parse indication"); + warn!(%error, msg=%line, "Failed to parse indication"); } }, // EOF on stdin; this is a big problem diff --git a/d3270d/src/main.rs b/d3270d/src/main.rs index 4703c4d..8b58f2c 100644 --- a/d3270d/src/main.rs +++ b/d3270d/src/main.rs @@ -9,7 +9,9 @@ use anyhow::anyhow; use futures::future::select_all; use futures::FutureExt; use tokio::task::JoinHandle; -use tracing::error; +use tracing::{error, info}; +use tracing_subscriber::fmt::format::FmtSpan; +use tracing_subscriber::prelude::*; use d3270_common::b3270::operation::Action; @@ -46,10 +48,26 @@ impl JoinHandleTagExt for JoinHandle { #[tokio::main] async fn main() -> anyhow::Result<()> { - let mut subprocess_args = vec![OsString::from_str("-json").unwrap()]; + // Configure logging + tracing_subscriber::registry() + .with(tracing_subscriber::filter::EnvFilter::from_default_env()) + .with( + tracing_subscriber::fmt::layer() + .with_span_events(FmtSpan::ACTIVE) + ).init(); + + info!("Test"); + + let mut subprocess_args = vec![ + OsString::from_str("-json").unwrap(), + OsString::from_str("-utf8").unwrap(), + ]; let mut args_iter = std::env::args_os().peekable(); let mut connect_str = None; let mut tcp_listen = None; + + args_iter.next(); // skip program name. + while let Some(arg) = args_iter.next() { // we default to one of the ignored args match arg.to_str().unwrap_or("-json") { @@ -92,6 +110,7 @@ async fn main() -> anyhow::Result<()> { let connect_str = connect_str.ok_or_else(|| anyhow!("No connect string given"))?; + info!(args=?subprocess_args, "Starting b3270"); let subproc = tokio::process::Command::new("b3270") .args(&subprocess_args) .stdin(Stdio::piped()) diff --git a/d3270d/src/tcp_server.rs b/d3270d/src/tcp_server.rs index b2496bb..b267521 100644 --- a/d3270d/src/tcp_server.rs +++ b/d3270d/src/tcp_server.rs @@ -6,16 +6,23 @@ use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; use tokio::net::{TcpListener, TcpStream}; use tokio::select; use tokio::task::JoinHandle; -use tracing::{error, info, info_span, Instrument}; +use tracing::{error, info, info_span, Instrument, instrument}; use crate::arbiter::ArbiterHandleRequester; use crate::gen_connection::GenConnection; +#[instrument(skip(handle_requester))] pub async fn listener_proc( socket: SocketAddr, handle_requester: ArbiterHandleRequester, ) -> anyhow::Result> { - let listener = tokio::net::TcpListener::bind(socket.clone()).await?; + let listener = match tokio::net::TcpListener::bind(socket.clone()).await { + Err(error) => { + error!(?socket, ?error, "Failed to bind"); + return Err(error.into()); + } + Ok(listener) => listener + }; let span = info_span!(target: "connection-handling", "tcp_listener", addr=%socket); Ok(tokio::spawn( async move {