|
1 | 1 | use maybe_async::*; |
2 | | -use std::io::Cursor; |
| 2 | +use std::{io::Cursor, time::Duration}; |
3 | 3 |
|
4 | 4 | #[cfg(feature = "sync")] |
5 | 5 | use std::{ |
6 | 6 | io::{self, Read, Write}, |
7 | | - net::TcpStream, |
| 7 | + net::{TcpStream, ToSocketAddrs}, |
8 | 8 | }; |
9 | 9 | #[cfg(feature = "async")] |
10 | 10 | use tokio::{ |
11 | 11 | io::{self, AsyncReadExt, AsyncWriteExt}, |
12 | 12 | net::{tcp, TcpStream}, |
| 13 | + select, |
13 | 14 | }; |
14 | 15 |
|
15 | 16 | use binrw::prelude::*; |
@@ -37,26 +38,57 @@ type TcpWrite = TcpStream; |
37 | 38 | pub struct NetBiosClient { |
38 | 39 | reader: Option<TcpRead>, |
39 | 40 | writer: Option<TcpWrite>, |
| 41 | + timeout: Option<Duration>, |
40 | 42 | } |
41 | 43 |
|
42 | 44 | impl NetBiosClient { |
43 | | - pub fn new() -> NetBiosClient { |
| 45 | + pub fn new(timeout: Option<Duration>) -> NetBiosClient { |
44 | 46 | NetBiosClient { |
45 | 47 | reader: None, |
46 | 48 | writer: None, |
| 49 | + timeout, |
47 | 50 | } |
48 | 51 | } |
49 | 52 |
|
50 | 53 | /// Connects to a NetBios server in the specified address. |
51 | 54 | #[maybe_async] |
52 | 55 | pub async fn connect(&mut self, address: &str) -> crate::Result<()> { |
53 | | - let socket = TcpStream::connect(address).await?; |
| 56 | + let socket = self.connect_timeout(address).await?; |
54 | 57 | let (r, w) = Self::split_socket(socket); |
55 | 58 | self.reader = Some(r); |
56 | 59 | self.writer = Some(w); |
57 | 60 | Ok(()) |
58 | 61 | } |
59 | 62 |
|
| 63 | + #[cfg(feature = "sync")] |
| 64 | + fn connect_timeout(&mut self, address: &str) -> crate::Result<TcpStream> { |
| 65 | + if let Some(t) = self.timeout { |
| 66 | + log::debug!("Connecting to {} with timeout {:?}.", address, t); |
| 67 | + // convert to SocketAddr: |
| 68 | + let address = address |
| 69 | + .to_socket_addrs()? |
| 70 | + .next() |
| 71 | + .ok_or(crate::Error::InvalidAddress(address.to_string()))?; |
| 72 | + TcpStream::connect_timeout(&address, t).map_err(Into::into) |
| 73 | + } else { |
| 74 | + log::debug!("Connecting to {}.", address); |
| 75 | + TcpStream::connect(&address).map_err(Into::into) |
| 76 | + } |
| 77 | + } |
| 78 | + |
| 79 | + #[cfg(feature = "async")] |
| 80 | + async fn connect_timeout(&mut self, address: &str) -> crate::Result<TcpStream> { |
| 81 | + if let None = self.timeout { |
| 82 | + log::debug!("Connecting to {}.", address); |
| 83 | + return TcpStream::connect(&address).await.map_err(Into::into); |
| 84 | + } |
| 85 | + |
| 86 | + select! { |
| 87 | + res = TcpStream::connect(&address) => res.map_err(Into::into), |
| 88 | + _ = tokio::time::sleep(self.timeout.unwrap()) => Err(crate::Error::OperationTimeout("Tcp connect".to_string(), self.timeout.unwrap())), |
| 89 | + } |
| 90 | + } |
| 91 | + |
60 | 92 | pub fn is_connected(&self) -> bool { |
61 | 93 | self.reader.is_some() |
62 | 94 | } |
@@ -197,10 +229,12 @@ impl NetBiosClient { |
197 | 229 | NetBiosClient { |
198 | 230 | reader: self.reader, |
199 | 231 | writer: None, |
| 232 | + timeout: self.timeout, |
200 | 233 | }, |
201 | 234 | NetBiosClient { |
202 | 235 | reader: None, |
203 | 236 | writer: self.writer, |
| 237 | + timeout: self.timeout, |
204 | 238 | }, |
205 | 239 | )) |
206 | 240 | } |
|
0 commit comments