-
Notifications
You must be signed in to change notification settings - Fork 55
Description
Tested on Debian 12, Linux 6.1.0-32-amd64, BlueZ version 5.66. BlueR was at commit 45d0837.
connect inconsistently reports "connection refused", causing errors in later reads and writes. In testing, errors were successfully reported 0-5% of the time on L2CAP streams and L2CAP seqpacket connections, and 30-50% of the time on RFCOMM connections.
The "invalid argument" error is not affected.
I encountered this bug while trying to diagnose #163, hence the similar example.
Examples
I ran these examples with an Android phone, which was already paired and connected over audio. I chose channels which were not open to deliberately trigger an error.
L2CAP stream example
use bluer::AddressType;
use bluer::l2cap::{Socket, SocketAddr};
use tokio::io::AsyncWriteExt;
#[tokio::main]
async fn main() {
let address = SocketAddr::new(
"50:13:1D:XX:XX:XX".parse().unwrap(),
AddressType::BrEdr,
0x13,
);
let socket = Socket::new_stream().expect("new");
println!("Connecting");
let mut connection = socket.connect(address).await.expect("connect");
println!("Connected");
println!("Writing data");
connection.write(&[0x00]).await.expect("write");
println!("Written");
}L2CAP seqpacket example
use bluer::AddressType;
use bluer::l2cap::{Socket, SocketAddr};
#[tokio::main]
async fn main() {
let address = SocketAddr::new(
"50:13:1D:XX:XX:XX".parse().unwrap(),
AddressType::BrEdr,
0x13,
);
let socket = Socket::new_seq_packet().expect("new");
println!("Connecting");
let connection = socket.connect(address).await.expect("connect");
println!("Connected");
println!("Writing data");
connection.send(&[0x00]).await.expect("send");
println!("Written");
}RFCOMM example
use bluer::rfcomm::{Socket, SocketAddr};
use tokio::io::AsyncWriteExt;
#[tokio::main]
async fn main() {
let address = SocketAddr::new(
"50:13:1D:XX:XX:XX".parse().unwrap(),
0x0A,
);
let socket = Socket::new().expect("new");
println!("Connecting");
let mut connection = socket.connect(address).await.expect("connect");
println!("Connected");
println!("Writing data");
connection.write(&[0x00]).await.expect("write");
println!("Written");
}Output
Actual output is
Connecting
Connected
Writing data
thread 'main' panicked at src/main.rs:20:37:
send: Os { code: 107, kind: NotConnected, message: "Transport endpoint is not connected" }
Expected:
Connecting
thread 'main' panicked at src/main.rs:16:56:
connect: Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }
Suspected causes
In testing, getsockopt(socket, SOL_SOCKET, SO_ERROR) would usually return 0 if the socket was not selected/polled for readiness, as if the connection had completed. This was true in Rust and Python.
The problem doesn't occur if I use Mio for polling, instead of Tokio. I suspect that Tokio's AsyncFd isn't using the OS's select or poll to determine readiness, causing false positives, but I'm unsure. There might be other sources of false positives.