summaryrefslogtreecommitdiff
path: root/sappeer.cc
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2014-10-19 18:45:03 +0200
committerJavier <dev.git@javispedro.com>2014-10-19 18:45:03 +0200
commitd8d8fc7a0d139e7b864eee3b573bd208f823ad4f (patch)
treea9b54d6e6e6941c620f4f10cef4b5def9be86f82 /sappeer.cc
downloadsapd-d8d8fc7a0d139e7b864eee3b573bd208f823ad4f.tar.gz
sapd-d8d8fc7a0d139e7b864eee3b573bd208f823ad4f.zip
initial import, no crypto
Diffstat (limited to 'sappeer.cc')
-rw-r--r--sappeer.cc379
1 files changed, 379 insertions, 0 deletions
diff --git a/sappeer.cc b/sappeer.cc
new file mode 100644
index 0000000..af843e4
--- /dev/null
+++ b/sappeer.cc
@@ -0,0 +1,379 @@
+#include <QtCore/QDebug>
+
+#include "sapmanager.h"
+#include "sapconnection.h"
+#include "sapconnectionrequest.h"
+#include "sapsocket.h"
+#include "sapchannelinfo.h"
+#include "capabilityagent.h"
+#include "capabilitypeer.h"
+#include "wmspeer.h"
+#include "sappeer.h"
+
+SAPPeer::SAPPeer(SAProtocol::Role role, const QString &localName, const QString &peerName, QObject *parent) :
+ QObject(parent),
+ _wms(new WMSPeer(role, localName, peerName, this)),
+ _role(role),
+ _localName(localName), _peerName(peerName)
+{
+}
+
+SAPConnection * SAPPeer::createServiceConnection(const QString &profile, const QString &requesterProfile, SAPServiceInfo::Role requesterRole)
+{
+ SAPManager *manager = SAPManager::instance();
+
+ int initiator = manager->registeredAgentId(requesterProfile, requesterRole);
+
+ if (initiator < 0) {
+ qWarning() << "Requester profile not found:" << requesterProfile;
+ return 0;
+ }
+
+ // Search remote agent id in capability database.
+ CapabilityPeer *capPeer = capabilityPeer();
+
+ int acceptor = capPeer->remoteAgentId(profile, SAPServiceInfo::oppositeRole(requesterRole));
+ if (acceptor < 0) {
+ qWarning() << "Remote profile not found:" << profile;
+ return 0;
+ }
+
+ SAPServiceInfo sInfo = manager->serviceInfo(initiator);
+ SAPConnection *conn = new SAPConnection(this, profile);
+
+ SAProtocol::ServiceConnectionRequestFrame request;
+ request.messageType = SAProtocol::ServiceConnectionRequest;
+ request.initiatorId = initiator;
+ request.acceptorId = acceptor;
+ request.profile = profile;
+
+ if (request.acceptorId == SAProtocol::capabilityDiscoveryAgentId) {
+ // Addressing the capability discovery service? Be anonymous about it
+ request.initiatorId = SAProtocol::capabilityDiscoveryAgentId;
+ }
+
+ foreach (const SAPChannelInfo &cInfo, sInfo.channels()) {
+ SAProtocol::ServiceConnectionRequestSession session;
+
+ int sessionId = findUnusedSessionId();
+
+ session.sessionId = sessionId;
+ session.channelId = cInfo.channelId();
+ session.qosType = cInfo.qosType();
+ session.qosDataRate = cInfo.qosDataRate();
+ session.qosPriority = cInfo.qosPriority();
+ session.payloadType = cInfo.payloadType();
+
+ request.sessions.append(session);
+
+ SAPSocket *socket = new SAPSocket(conn, sessionId);
+ // TODO set socket QoS parameters
+ conn->setSocket(session.channelId, socket);
+
+ _sessions.insert(sessionId, socket);
+ }
+
+ writeToSession(SAProtocol::defaultSessionId,
+ SAProtocol::packServiceConnectionRequestFrame(request));
+
+ return conn;
+}
+
+SAProtocol::Role SAPPeer::role() const
+{
+ return _role;
+}
+
+QString SAPPeer::localName() const
+{
+ return _localName;
+}
+
+QString SAPPeer::peerName() const
+{
+ return _peerName;
+}
+
+CapabilityPeer *SAPPeer::capabilityPeer()
+{
+ return findChild<CapabilityPeer*>();
+}
+
+bool SAPPeer::writeToSession(int session, const QByteArray &data)
+{
+ if (session == SAProtocol::defaultSessionId) {
+ // Session is default (always open) or already open
+ sendFrame(SAProtocol::packFrame(session, data));
+ return true;
+ } else {
+ SAPSocket *socket = _sessions.value(session, 0);
+ if (socket && socket->isOpen()) {
+ sendFrame(SAProtocol::packFrame(session, data));
+ return true;
+ } else {
+ qWarning() << "Session" << session << "not open yet";
+ return false;
+ }
+ }
+}
+
+void SAPPeer::acceptServiceConnection(SAPConnectionRequest *connReq, int statusCode)
+{
+ SAPConnection *conn = connReq->connection();
+
+ SAProtocol::ServiceConnectionResponseFrame resp;
+ resp.messageType = SAProtocol::ServiceConnectionResponse;
+ resp.acceptorId = connReq->acceptorId();
+ resp.initiatorId = connReq->initiatorId();
+ resp.profile = conn->profile();
+ resp.statusCode = statusCode;
+
+ foreach (const SAPSocket *socket, conn->sockets()) {
+ resp.sessions.push_back(socket->sessionId());
+ }
+
+ qDebug() << "acceptServiceConection" << statusCode;
+
+ writeToSession(SAProtocol::defaultSessionId,
+ SAProtocol::packServiceConnectionResponseFrame(resp));
+
+ if (statusCode == 0) {
+ foreach (SAPSocket *socket, conn->sockets()) {
+ socket->setOpen(true);
+ emit socket->connected();
+ }
+
+ emit conn->connected();
+ } else {
+ // Cancel any partial opened sessions
+ foreach (SAPSocket *socket, conn->sockets()) {
+ _sessions.remove(socket->sessionId());
+ delete socket;
+ }
+ delete conn; // Also deletes child sockets
+ }
+
+ // Can't delete connReq now because we must return to it.
+ // It will take care of itself.
+}
+
+void SAPPeer::handleSessionData(int session, const QByteArray &data)
+{
+ if (session == SAProtocol::defaultSessionId) {
+ // Default session data frame.
+ handleDefaultSessionMessage(data);
+ return;
+ } else {
+ SAPSocket *socket = _sessions.value(session, 0);
+ if (socket && socket->isOpen()) {
+ socket->acceptIncomingData(data);
+ } else {
+ qWarning() << "Got information for a session that's not yet open!" << session;
+ }
+ }
+}
+
+void SAPPeer::handleConnected()
+{
+ emit connected();
+
+ // Manually call the capability agent in order to trigger initial capability discovery.
+ CapabilityAgent *caps = CapabilityAgent::instance();
+ caps->peerFound(this);
+}
+
+void SAPPeer::handleDisconnected()
+{
+ // TODO
+ emit disconnected();
+ deleteLater();
+}
+
+int SAPPeer::findUnusedSessionId() const
+{
+ if (_sessions.size() > SAProtocol::maxSessionId) {
+ qWarning() << "Ran out of session ids!";
+ return -1;
+ }
+
+ int id = 1;
+ while (_sessions.contains(id)) {
+ id++;
+ }
+
+ Q_ASSERT(id <= SAProtocol::maxSessionId && id != SAProtocol::defaultSessionId);
+
+ return id;
+}
+
+void SAPPeer::handleDefaultSessionMessage(const QByteArray &message)
+{
+ const quint8 message_type = message[0];
+
+ switch (message_type) {
+ case SAProtocol::ServiceConnectionRequest: {
+ SAPManager *manager = SAPManager::instance();
+ SAProtocol::ServiceConnectionRequestFrame req = SAProtocol::unpackServiceConnectionRequestFrame(message);
+ bool ok = true;
+
+ qDebug() << "Service connection request to profile" << req.profile;
+
+ SAPAgent *agent = manager->agent(req.acceptorId);
+
+ if (!agent) {
+ qWarning() << "Requested agent does not exist";
+ ok = false;
+ }
+
+ foreach (const SAProtocol::ServiceConnectionRequestSession &s, req.sessions) {
+ if (_sessions.contains(s.sessionId)) {
+ qWarning() << "Requested session is already in use";
+ ok = false;
+ }
+ }
+
+ if (!ok) {
+ SAProtocol::ServiceConnectionResponseFrame resp;
+ resp.messageType = SAProtocol::ServiceConnectionResponse;
+ resp.acceptorId = req.acceptorId;
+ resp.initiatorId = req.initiatorId;
+ resp.profile = req.profile;
+ resp.statusCode = 1;
+
+ foreach (const SAProtocol::ServiceConnectionRequestSession &s, req.sessions) {
+ resp.sessions.push_back(s.sessionId);
+ }
+
+ writeToSession(SAProtocol::defaultSessionId,
+ SAProtocol::packServiceConnectionResponseFrame(resp));
+ return;
+ }
+
+ SAPConnection *conn = new SAPConnection(this, req.profile);
+
+ foreach (const SAProtocol::ServiceConnectionRequestSession &s, req.sessions) {
+ SAPSocket *socket = new SAPSocket(conn, s.sessionId);
+ // TODO set socket QoS parameters
+ conn->setSocket(s.channelId, socket);
+
+ _sessions.insert(s.sessionId, socket);
+ }
+
+ SAPConnectionRequest *connReq = new SAPConnectionRequest(conn, req.initiatorId, req.acceptorId);
+ agent->requestConnection(connReq);
+
+#if 0
+ resp.messageType = SAProtocol::ServiceConnectionResponse;
+ resp.acceptorId = req.acceptorId;
+ resp.initiatorId = req.initiatorId;
+ resp.profile = req.profile;
+ resp.statusCode = 0;
+
+ QList<SAPSocket*> created_sockets;
+
+ SAPAgent *agent = _profiles.value(req.profile, 0);
+ if (agent) {
+ foreach (const SAProtocol::ServiceConnectionRequestSession &s, req.sessions) {
+ if (_openSessions.contains(s.sessionId)) {
+ // Session ID already used.
+ resp.statusCode = 1;
+ break;
+ }
+
+ SAPSocket *socket = new SAPSocket(this, s.sessionId, this);
+
+ qDebug() << "Requesting connection to" << req.profile << s.channelId;
+
+ if (!agent->acceptConnection(req.profile, s.channelId, socket)) {
+ resp.statusCode = 2;
+ break;
+ }
+
+ // Save for later. We can't emit the connected signal right now
+ // because data might be written to the socket even before
+ // we send the response.
+ created_sockets.append(socket);
+
+ resp.sessions.append(s.sessionId);
+ }
+
+ if (resp.statusCode != 0) {
+ resp.sessions.clear(); // TODO Is this correct? Who knows!
+ }
+ }
+
+ qDebug() << "Service connection request statusCode=" << resp.statusCode;
+
+ writeToSession(SAProtocol::defaultSessionId,
+ SAProtocol::packServiceConnectionResponseFrame(resp));
+
+ if (resp.statusCode == 0) {
+ foreach (SAPSocket *socket, created_sockets) {
+ const int session = socket->sessionId();
+ _openSessions.insert(session);
+ qDebug() << "Session" << session << "now live";
+
+ emit socket->connected();
+ }
+ } else {
+ foreach (SAPSocket *socket, created_sockets) {
+ emit socket->disconnected();
+ socket->deleteLater();
+ }
+ }
+#endif
+
+ break;
+ }
+ case SAProtocol::ServiceConnectionResponse: {
+ SAProtocol::ServiceConnectionResponseFrame frame = SAProtocol::unpackServiceConnectionResponseFrame(message);
+
+ bool ok = frame.statusCode == 0;
+
+ if (!ok) {
+ qWarning() << "Failure to create a service connection";
+ } else {
+ qDebug() << "Service connection OK";
+ }
+
+ if (frame.sessions.isEmpty()) {
+ qWarning() << "No sessions in frame, nothing to do";
+ return;
+ }
+
+ SAPSocket *firstSocket = _sessions.value(frame.sessions.first(), 0);
+ if (!firstSocket) {
+ qWarning() << "Unknown session id:" << frame.sessions.first();
+ return;
+ }
+
+ SAPConnection *conn = firstSocket->connection();
+
+ foreach (int session, frame.sessions) {
+ SAPSocket *socket = _sessions.value(session, 0);
+ if (socket) {
+ if (socket->isOpen()) {
+ qWarning() << "Session" << session << "was already open?";
+ }
+
+ qDebug() << "Session" << session << "now live";
+ socket->setOpen(true);
+ emit socket->connected();
+ } else {
+ qWarning() << "Unknown session id:" << session;
+ }
+ }
+
+ if (ok) {
+ emit conn->connected();
+ } else {
+ emit conn->error(frame.statusCode);
+ emit conn->disconnected();
+ }
+
+ break;
+ }
+ default:
+ qWarning() << "Unknown default session message type:" << message_type;
+ }
+}