From d8d8fc7a0d139e7b864eee3b573bd208f823ad4f Mon Sep 17 00:00:00 2001 From: Javier Date: Sun, 19 Oct 2014 18:45:03 +0200 Subject: initial import, no crypto --- sapbtlistener.cc | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 sapbtlistener.cc (limited to 'sapbtlistener.cc') diff --git a/sapbtlistener.cc b/sapbtlistener.cc new file mode 100644 index 0000000..d5cd071 --- /dev/null +++ b/sapbtlistener.cc @@ -0,0 +1,198 @@ +#include +#include +#include + +#include "saprotocol.h" +#include "sapbtlistener.h" +#include "sapbtpeer.h" + +#ifdef DESKTOP +#include "hfpag.h" +#endif + +namespace +{ +void add_sdp_record(sdp_session_t *session, const QBluetoothUuid &btuuid, quint16 port) +{ + sdp_list_t *svclass_id, *apseq, *root; + uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid; + sdp_list_t *aproto, *proto[2]; + sdp_data_t *chan; + + sdp_record_t *record = sdp_record_alloc(); + + sdp_set_info_attr(record, "SAP", "gearbttest", "Samsung Accessory Protocol"); + + sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); + root = sdp_list_append(0, &root_uuid); + sdp_set_browse_groups(record, root); + + QByteArray uuid = btuuid.toRfc4122(); + sdp_uuid128_create(&svclass_uuid, uuid.constData()); + svclass_id = sdp_list_append(0, &svclass_uuid); + sdp_set_service_classes(record, svclass_id); + + sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); + proto[0] = sdp_list_append(0, &l2cap_uuid); + apseq = sdp_list_append(0, proto[0]); + + sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); + proto[1] = sdp_list_append(0, &rfcomm_uuid); + chan = sdp_data_alloc(SDP_UINT8, &port); + proto[1] = sdp_list_append(proto[1], chan); + apseq = sdp_list_append(apseq, proto[1]); + + aproto = sdp_list_append(0, apseq); + sdp_set_access_protos(record, aproto); + + if (sdp_record_register(session, record, 0) < 0) { + qWarning() << "sdp_record_register failed"; + } +} + +void add_sdp_records(quint16 port) +{ + bdaddr_t addr_any = {{0, 0, 0, 0, 0, 0}}; + bdaddr_t addr_local = {{0, 0, 0, 0xFF, 0xFF, 0xFF}}; + + sdp_session_t *sess = sdp_connect(&addr_any, &addr_local, 0); + if (!sess) { + qWarning() << "sdp_connect failed"; + return; + } + + add_sdp_record(sess, SAProtocol::dataServiceUuid, port); +} + +} + +SAPBTListener::SAPBTListener(QObject *parent) : + QObject(parent), _server(0) +{ +} + +SAPBTListener::~SAPBTListener() +{ + stop(); +} + +void SAPBTListener::start() +{ + if (_server) { + return; + } + + _server = new QRfcommServer(this); + connect(_server, SIGNAL(newConnection()), this, SLOT(acceptConnection())); + if (!_server->listen(QBluetoothAddress(), 0)) { + qWarning() << "Failed to start Bluetooth listener socket"; + stop(); + return; + } + + quint8 serverPort = _server->serverPort(); + +#if 1 + // Basically, QBluetoothServiceInfo is not yet compatible with Bluez5, + // so we hack around it by doing our own SDP connection. + add_sdp_records(serverPort); +#else + + /* + Service Name: SAP + Service RecHandle: 0x1000b + Service Class ID List: + UUID 128: a49eb41e-cb06-495c-9f4f-bb80a90cdf00 + Protocol Descriptor List: + "L2CAP" (0x0100) + "RFCOMM" (0x0003) + Channel: 5 + + Service Name: SAP + Service RecHandle: 0x1000c + Service Class ID List: + UUID 128: a49eb41e-cb06-495c-9f4f-aa80a90cdf4a + Protocol Descriptor List: + "L2CAP" (0x0100) + "RFCOMM" (0x0003) + Channel: 6 + */ + + _service.setServiceName("SAP"); + _service.setServiceDescription("Samsung Accessory Profile"); + _service.setServiceProvider("gearbtteest"); + + QBluetoothServiceInfo::Sequence classIds; + classIds.append(QVariant::fromValue(SAPProtocol::dataServiceUuid)); + _service.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classIds); + + QBluetoothServiceInfo::Sequence browseGroupList; + browseGroupList.append(QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup))); + _service.setAttribute(QBluetoothServiceInfo::BrowseGroupList, browseGroupList); + + QBluetoothServiceInfo::Sequence protocolDescriptorList; + QBluetoothServiceInfo::Sequence protocol; + + protocol.append(QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap))); + protocolDescriptorList.append(QVariant::fromValue(protocol)); + protocol.clear(); + + protocol.append(QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm))); + protocol.append(QVariant::fromValue(serverPort)); + protocolDescriptorList.append(QVariant::fromValue(protocol)); + protocol.clear(); + + _service.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, + protocolDescriptorList); + + if (!_service.registerService()) { + qWarning() << "Failed to register the SAP service"; + } +#endif +} + +void SAPBTListener::stop() +{ + if (!_server) { + return; + } + + if (!_service.unregisterService()) { + qWarning() << "Failed to unregister SAP service"; + } + + delete _server; + _server = 0; +} + +void SAPBTListener::nudge(const QBluetoothAddress &address) +{ + QBluetoothSocket *socket = new QBluetoothSocket(QBluetoothSocket::RfcommSocket, this); + + qDebug() << "Nudging" << address.toString(); + + socket->connectToService(address, 2); //SAPProtocol::nudgeServiceUuid); + +#if 1 + HfpAg *ag = new HfpAg(address, this); + connect(socket, SIGNAL(disconnected()), ag, SLOT(deleteLater())); +#endif + + connect(socket, SIGNAL(connected()), socket, SLOT(deleteLater())); + connect(socket, SIGNAL(error(QBluetoothSocket::SocketError)), socket, SLOT(deleteLater())); +} + +void SAPBTListener::acceptConnection() +{ + qDebug() << "Incoming BT connection"; + QBluetoothSocket *socket = _server->nextPendingConnection(); + if (!socket) { + qWarning() << "Actually, no incoming connection"; + return; + } + + qDebug() << "Got connection"; + + // TODO Why am I hardcoding the role here + new SAPBTPeer(SAProtocol::ClientRole, socket, this); +} -- cgit v1.2.3