Skip to content

connect reports "connection refused" inconsistently #167

@eyanje

Description

@eyanje

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.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions