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?