From a45977185a485624095bff1a15024e9199eee676 Mon Sep 17 00:00:00 2001 From: Javier Date: Fri, 1 Jan 2016 22:05:42 +0100 Subject: reorganize source files into SAP and agents --- sap/sapbtpeer.cc | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 sap/sapbtpeer.cc (limited to 'sap/sapbtpeer.cc') diff --git a/sap/sapbtpeer.cc b/sap/sapbtpeer.cc new file mode 100644 index 0000000..188c37b --- /dev/null +++ b/sap/sapbtpeer.cc @@ -0,0 +1,191 @@ +#include +#include "saprotocol.h" +#include "wmspeer.h" +#include "crc16.h" +#include "sapsocket.h" +#include "sapbtpeer.h" + +#define PROTO_DEBUG 0 + +SAPBTPeer::SAPBTPeer(SAProtocol::Role role, QBluetoothSocket *socket, QObject *parent) : + SAPPeer(role, socket->localAddress().toString(), socket->peerAddress().toString(), parent), + _socket(socket), + _curFrameLength(0), + _peerDescriptionExchangeDone(false), _authenticationDone(false) +{ + connect(_socket, SIGNAL(readyRead()), SLOT(handleSocketData())); + connect(_socket, SIGNAL(disconnected()), SLOT(handleSocketDisconnected())); +} + +void SAPBTPeer::handleSocketData() +{ + uint bytes = _socket->bytesAvailable(); + const bool need_crc = _peerDescriptionExchangeDone && _authenticationDone; + const uint header_size = need_crc ? 2 * sizeof(quint16) : 1 * sizeof(quint16); + const uint footer_size = need_crc ? sizeof(quint16) : 0; + + while ((_curFrameLength == 0 && bytes >= header_size) || + (_curFrameLength > 0 && bytes >= _curFrameLength + footer_size)) { + if (_curFrameLength > 0) { + // We are waiting for a full frame of known length + QByteArray frame = _socket->read(_curFrameLength); + Q_ASSERT(frame.size() == (int)_curFrameLength); + _curFrameLength = 0; + + if (need_crc) { + quint16 computed_crc = crc16(0, reinterpret_cast(frame.constData()), frame.size()); + quint16 crc; + _socket->read(reinterpret_cast(&crc), sizeof(quint16)); + crc = qFromBigEndian(crc); + + if (crc != computed_crc) { + qWarning() << "CRC data failure"; + _socket->close(); // Drop the connection, no provision for resync. + return; + } + } + + handleFrame(frame); + } else { + quint16 frame_length; + bytes = _socket->read(reinterpret_cast(&frame_length), sizeof(quint16)); + Q_ASSERT(bytes == sizeof(quint16)); + _curFrameLength = qFromBigEndian(frame_length); + Q_ASSERT(_curFrameLength > 0); + + if (need_crc) { + // Compute the checksum of the BIG ENDIAN frame length. + quint16 computed_crc = crc16(0, reinterpret_cast(&frame_length), sizeof(quint16)); + quint16 crc; + _socket->read(reinterpret_cast(&crc), sizeof(quint16)); + crc = qFromBigEndian(crc); + + if (crc != computed_crc) { + qWarning() << "CRC length failure"; + _curFrameLength = 0; + _socket->close(); // Drop the connection, no provision for resync. + return; + } + } + } + + bytes = _socket->bytesAvailable(); + } +} + +void SAPBTPeer::handleSocketDisconnected() +{ + qDebug() << "Socket disconnected"; + handleDisconnected(); +} + +void SAPBTPeer::sendFrame(const QByteArray &data) +{ + const bool need_crc = _peerDescriptionExchangeDone && _authenticationDone; + quint16 frame_length = qToBigEndian(data.length()); + _socket->write(reinterpret_cast(&frame_length), sizeof(quint16)); + + // Compute the checksum of the BIG ENDIAN frame length. + if (need_crc) { + quint16 crc = qToBigEndian(crc16(0, reinterpret_cast(&frame_length), sizeof(quint16))); + _socket->write(reinterpret_cast(&crc), sizeof(quint16)); + } + + _socket->write(data.constData(), data.size()); + + if (need_crc) { + quint16 crc = qToBigEndian(crc16(0, reinterpret_cast(data.constData()), data.size())); + _socket->write(reinterpret_cast(&crc), sizeof(quint16)); + } + +#if PROTO_DEBUG + qDebug() << "Sent:" << data.toHex(); +#endif +} + +void SAPBTPeer::handleFrame(const QByteArray &data) +{ +#if PROTO_DEBUG + qDebug() << "Recv:" << data.toHex(); +#endif + + if (!_peerDescriptionExchangeDone) { + // This must be a peer description frame! + SAProtocol::PeerDescription peerDesc = SAProtocol::unpackPeerDescription(data); + qDebug() << peerDesc.product << peerDesc.manufacturer << peerDesc.name; + qDebug() << "apdu=" << peerDesc.APDUSize << "ssdu=" << peerDesc.SSDUSize + << "sessions=" << peerDesc.sessions << "timeout=" << peerDesc.timeout; + + SAProtocol::PeerDescription myDesc = peerDesc; + myDesc.messageType = 6; // Why? + myDesc.status = 0; // This seems to be "accepted" + myDesc.product = "RandomPhone"; + myDesc.manufacturer = "me"; + myDesc.name = "gearbttest"; + myDesc.profile = "SWatch"; // This is what Gear manager sends + + sendFrame(SAProtocol::packPeerDescription(myDesc)); + + _peerDescriptionExchangeDone = true; + } else if (!_authenticationDone) { + // This must be a authentication frame... + handleAuthenticationFrame(data); + } else { + SAProtocol::Frame frame = SAProtocol::unpackFrame(data); + switch (frame.type) { + case SAProtocol::FrameData: + handleDataFrame(frame); + break; + case SAProtocol::FrameControl: + handleControlFrame(frame); + break; + default: + qWarning() << "Unknown frame type" << frame.type; + break; + } + } +} + +void SAPBTPeer::handleDataFrame(const SAProtocol::Frame &frame) +{ + Q_ASSERT(frame.type == SAProtocol::FrameData); + + handleSessionData(frame.sessionId, frame.data); +} + +void SAPBTPeer::handleControlFrame(const SAProtocol::Frame &frame) +{ + Q_ASSERT(frame.type == SAProtocol::FrameControl); + + handleSessionControl(frame.sessionId, frame.data); +} + +void SAPBTPeer::handleAuthenticationFrame(const QByteArray &data) +{ + SAProtocol::SecurityFrame sframe = SAProtocol::unpackSecurityFrame(data); + + switch (sframe.type) { + case SAProtocol::SecurityAuthenticateRequest: { + qDebug() << "Starting authorization..."; + SAProtocol::SecurityFrame response = _wms->respondToServerChallenge(sframe); + if (!response.data.isEmpty()) { + sendFrame(SAProtocol::packSecurityFrame(response)); + } + break; + } + case SAProtocol::SecurityAuthenticateConfirm: { + _authenticationDone = _wms->verifyServerResponse(sframe); + if (_authenticationDone) { + qDebug() << "Authentication confirmed"; + handleConnected(); + } else { + qWarning() << "Authentication failure, closing connection"; + _socket->close(); // Will call "handleDisconnected" and emit disconnected signals. + } + break; + } + default: + qWarning() << "Unknown security frame type" << sframe.type; + break; + } +} -- cgit v1.2.3