0

I am developing a Bluetooth application to connect to a mobile phone. I'm using Rfcomm Bluetooth sockets from the old C standard library. I have this code to create a Bluetooth object and prepare the connection:

class BtDevice final {
    ...
    static constexpr bdaddr_t bdaddrAny {0, 0, 0, 0, 0, 0};
    static constexpr uint8_t rfcommChannel = 1;
    const sockaddr_rc ourAddress { .rc_family = AF_BLUETOOTH, .rc_bdaddr = bdaddrAny, .rc_channel = rfcommChannel };        
    int ourSocket = 0;
    ...
}
BtDevice::BtDevice() {
    ourSocket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
    if (ourSocket == -1)
        throw std::runtime_error("Bluetooth: Socket creation failed - " + std::string(strerror(errno)) + ".");

    static constexpr auto flag = 1;
    if(setsockopt(ourSocket, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int)) != 0)
        std::cerr << "Failed to translate socket into the reusable mode - " << strerror(errno) << "." << std::endl;
}
void BtDevice::prepare() {
    if (bind(ourSocket, (sockaddr *) &ourAddress, sizeof(ourAddress)) < 0)
        throw std::runtime_error("Bluetooth: Socket binding failed - " + std::string(strerror(errno)) + ".");
    if (listen(ourSocket, 1) == -1)
        throw std::runtime_error("Bluetooth Socket listening failed - " + std::string(strerror(errno)) + ".");
}

If for some reason the phone connection drops, I want my socket to be destroyed and reopened. I have this code for destroying an object:

BtDevice::~BtDevice()  {
    if(close(ourSocket) != 0)
        std::cerr << "Bluetooth: Socket closure failed - " << strerror(errno) << "." << std::endl;
    else
        std::cout << "Bluetooth socket closed and object is destructed." << std::endl;
}

And I have my program running in a loop in case of errors:

while(true) {
    try {
        BtDevice btDevice;
        btDevice.prepare();

        ...
        /* Main functionality. */
        ...

        break;
    } catch (const std::exception& e) {
        std::cerr << "Exception during the process: " << e.what() << "." << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(5));
    }
}

However, if the connection fails, I see in my output that the bind for the new socket failed with the message "Address already in use" (error 98):

Exception during the initialization process: ... (Connection with phone interrupted). Bluetooth socket closed and object is destructed.

Exception during the initialization process: Bluetooth: Socket binding failed - Address already in use.. Sleeping for 5 seconds...

I've seen questions with similar problems (this question and links from it) and as you can see I added setting the SO_REUSEADDR option right after the socket creation in the constructor.

I see from the documentation that the SO_REUSEADDR option should work for AF_INET sockets:

For AF_INET sockets this means that a socket may bind, except when there is an active listening socket bound to the address.

Should it work the same for bluetooth sockets? And if not, is there a suitable replacement for this?

Alvov1
  • 157
  • 1
  • 2
  • 10

0 Answers0