/* * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include #include #include #include #include #include #include namespace Swift { IBBSendSession::IBBSendSession( const std::string& id, const JID& from, const JID& to, std::shared_ptr bytestream, IQRouter* router) : id(id), from(from), to(to), bytestream(bytestream), router(router), blockSize(4096), sequenceNumber(0), active(false), waitingForData(false) { bytestream->onDataAvailable.connect(boost::bind(&IBBSendSession::handleDataAvailable, this)); } IBBSendSession::~IBBSendSession() { bytestream->onDataAvailable.disconnect(boost::bind(&IBBSendSession::handleDataAvailable, this)); } void IBBSendSession::start() { IBBRequest::ref request = IBBRequest::create( from, to, IBB::createIBBOpen(id, boost::numeric_cast(blockSize)), router); request->onResponse.connect(boost::bind(&IBBSendSession::handleIBBResponse, this, _1, _2)); active = true; request->send(); currentRequest = request; } void IBBSendSession::stop() { if (active && router->isAvailable()) { IBBRequest::create(from, to, IBB::createIBBClose(id), router)->send(); } if (currentRequest) { currentRequest->onResponse.disconnect(boost::bind(&IBBSendSession::handleIBBResponse, this, _1, _2)); } finish(boost::optional()); } void IBBSendSession::handleIBBResponse(IBB::ref, ErrorPayload::ref error) { currentRequest.reset(); if (!error && active) { if (!bytestream->isFinished()) { sendMoreData(); } else { finish(boost::optional()); } } else { finish(FileTransferError(FileTransferError::PeerError)); } } void IBBSendSession::sendMoreData() { try { std::shared_ptr data = bytestream->read(blockSize); if (!data->empty()) { waitingForData = false; IBBRequest::ref request = IBBRequest::create(from, to, IBB::createIBBData(id, sequenceNumber, *data), router); sequenceNumber++; request->onResponse.connect(boost::bind(&IBBSendSession::handleIBBResponse, this, _1, _2)); request->send(); currentRequest = request; onBytesSent(data->size()); } else { waitingForData = true; } } catch (const BytestreamException&) { finish(FileTransferError(FileTransferError::ReadError)); } } void IBBSendSession::finish(boost::optional error) { active = false; onFinished(error); } void IBBSendSession::handleDataAvailable() { if (waitingForData) { sendMoreData(); } } }