/* * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include #include #include #include #include #include #include #include #include #include #include namespace Swift { BasicSessionStream::BasicSessionStream( StreamType streamType, std::shared_ptr connection, PayloadParserFactoryCollection* payloadParserFactories, PayloadSerializerCollection* payloadSerializers, TLSContextFactory* tlsContextFactory, TimerFactory* timerFactory, XMLParserFactory* xmlParserFactory, const TLSOptions& tlsOptions) : available(false), connection(connection), tlsContextFactory(tlsContextFactory), timerFactory(timerFactory), tlsOptions_(tlsOptions) { xmppLayer = new XMPPLayer(payloadParserFactories, payloadSerializers, xmlParserFactory, streamType); xmppLayer->onStreamStart.connect(boost::bind(&BasicSessionStream::handleStreamStartReceived, this, _1)); xmppLayer->onStreamEnd.connect(boost::bind(&BasicSessionStream::handleStreamEndReceived, this)); xmppLayer->onElement.connect(boost::bind(&BasicSessionStream::handleElementReceived, this, _1)); xmppLayer->onError.connect(boost::bind(&BasicSessionStream::handleXMPPError, this)); xmppLayer->onDataRead.connect(boost::bind(&BasicSessionStream::handleDataRead, this, _1)); xmppLayer->onWriteData.connect(boost::bind(&BasicSessionStream::handleDataWritten, this, _1)); connection->onDisconnected.connect(boost::bind(&BasicSessionStream::handleConnectionFinished, this, _1)); connectionLayer = new ConnectionLayer(connection); streamStack = new StreamStack(xmppLayer, connectionLayer); available = true; } BasicSessionStream::~BasicSessionStream() { if (auto tlsLayer = streamStack->getLayer()) { tlsLayer->onError.disconnect(boost::bind(&BasicSessionStream::handleTLSError, this, _1)); tlsLayer->onConnected.disconnect(boost::bind(&BasicSessionStream::handleTLSConnected, this)); } delete streamStack; connection->onDisconnected.disconnect(boost::bind(&BasicSessionStream::handleConnectionFinished, this, _1)); delete connectionLayer; xmppLayer->onStreamStart.disconnect(boost::bind(&BasicSessionStream::handleStreamStartReceived, this, _1)); xmppLayer->onStreamEnd.disconnect(boost::bind(&BasicSessionStream::handleStreamEndReceived, this)); xmppLayer->onElement.disconnect(boost::bind(&BasicSessionStream::handleElementReceived, this, _1)); xmppLayer->onError.disconnect(boost::bind(&BasicSessionStream::handleXMPPError, this)); xmppLayer->onDataRead.disconnect(boost::bind(&BasicSessionStream::handleDataRead, this, _1)); xmppLayer->onWriteData.disconnect(boost::bind(&BasicSessionStream::handleDataWritten, this, _1)); delete xmppLayer; } void BasicSessionStream::writeHeader(const ProtocolHeader& header) { assert(available); xmppLayer->writeHeader(header); } void BasicSessionStream::writeElement(std::shared_ptr element) { assert(available); xmppLayer->writeElement(element); } void BasicSessionStream::writeFooter() { assert(available); xmppLayer->writeFooter(); } void BasicSessionStream::writeData(const std::string& data) { assert(available); xmppLayer->writeData(data); } void BasicSessionStream::close() { connection->disconnect(); } bool BasicSessionStream::isOpen() { return available; } bool BasicSessionStream::supportsTLSEncryption() { return tlsContextFactory && tlsContextFactory->canCreate(); } void BasicSessionStream::addTLSEncryption() { assert(available); auto tlsContext = tlsContextFactory->createTLSContext(tlsOptions_); auto tlsLayer = std::make_unique(std::move(tlsContext)); if (hasTLSCertificate() && !tlsLayer->setClientCertificate(getTLSCertificate())) { onClosed(std::make_shared(SessionStreamError::InvalidTLSCertificateError)); } else { streamStack->addLayer(std::move(tlsLayer)); auto tlsLayer = streamStack->getLayer(); tlsLayer->onError.connect(boost::bind(&BasicSessionStream::handleTLSError, this, _1)); tlsLayer->onConnected.connect(boost::bind(&BasicSessionStream::handleTLSConnected, this)); tlsLayer->connect(); } } bool BasicSessionStream::isTLSEncrypted() { return streamStack->getLayer() != nullptr; } Certificate::ref BasicSessionStream::getPeerCertificate() const { return streamStack->getLayer()->getPeerCertificate(); } std::vector BasicSessionStream::getPeerCertificateChain() const { return streamStack->getLayer()->getPeerCertificateChain(); } std::shared_ptr BasicSessionStream::getPeerCertificateVerificationError() const { return streamStack->getLayer()->getPeerCertificateVerificationError(); } ByteArray BasicSessionStream::getTLSFinishMessage() const { return streamStack->getLayer()->getContext()->getFinishMessage(); } bool BasicSessionStream::supportsZLibCompression() { return true; } void BasicSessionStream::addZLibCompression() { auto compressionLayer = std::make_unique(); streamStack->addLayer(std::move(compressionLayer)); } void BasicSessionStream::setWhitespacePingEnabled(bool enabled) { auto whitespacePingLayer = streamStack->getLayer(); if (enabled) { if (!whitespacePingLayer) { streamStack->addLayer(std::make_unique(timerFactory)); whitespacePingLayer = streamStack->getLayer(); } whitespacePingLayer->setActive(); } else if (whitespacePingLayer) { whitespacePingLayer->setInactive(); } } void BasicSessionStream::resetXMPPParser() { xmppLayer->resetParser(); } void BasicSessionStream::handleStreamStartReceived(const ProtocolHeader& header) { onStreamStartReceived(header); } void BasicSessionStream::handleStreamEndReceived() { onStreamEndReceived(); } void BasicSessionStream::handleElementReceived(std::shared_ptr element) { onElementReceived(element); } void BasicSessionStream::handleXMPPError() { available = false; onClosed(std::make_shared(SessionStreamError::ParseError)); } void BasicSessionStream::handleTLSConnected() { onTLSEncrypted(); } void BasicSessionStream::handleTLSError(std::shared_ptr error) { available = false; onClosed(error); } void BasicSessionStream::handleConnectionFinished(const boost::optional& error) { available = false; if (error == Connection::ReadError) { onClosed(std::make_shared(SessionStreamError::ConnectionReadError)); } else if (error) { onClosed(std::make_shared(SessionStreamError::ConnectionWriteError)); } else { onClosed(std::shared_ptr()); } } void BasicSessionStream::handleDataRead(const SafeByteArray& data) { onDataRead(data); } void BasicSessionStream::handleDataWritten(const SafeByteArray& data) { onDataWritten(data); } }