diff options
author | Tobias Markmann <tm@ayena.de> | 2016-02-10 19:25:21 (GMT) |
---|---|---|
committer | Kevin Smith <kevin.smith@isode.com> | 2016-02-15 12:31:10 (GMT) |
commit | ca226e7bb019308db4bfc818d7e04422d9d28106 (patch) | |
tree | 9f7ef065f20db3e04eb08560674eed16d10e95e5 /Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp | |
parent | 431eb62386101dc8fc1e7d346c49bd0d81fda70e (diff) | |
download | swift-ca226e7bb019308db4bfc818d7e04422d9d28106.zip swift-ca226e7bb019308db4bfc818d7e04422d9d28106.tar.bz2 |
Fix crash when saving a received file to non-writable location
WriteBytestream::write(…) now returns a boolean indicating
its success state (false in case of an error). Adjusted
FileWriteBytestream accordingly.
The QtWebKitChatView will test if the file path selected by
the user is writable before accepting it and starting the
transfer. If it is not writable a red warning message will be
added to the file-transfer element in the chat view.
Test-Information:
Added an integration test that tests the new behavior for
the FileWriteBytestream class.
Tested two file transfers on OS X 10.11.3, one to a write
protected location and another to /tmp. The first is not accepted
by the UI, and without the UI sanity check it results in a
file-transfer error. The second succeeds as expected.
Change-Id: I5aa0c617423073feb371365a23a294c149c88036
Diffstat (limited to 'Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp')
-rw-r--r-- | Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp | 40 |
1 files changed, 18 insertions, 22 deletions
diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp index 7838dd1..0e1eb6b 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp @@ -1,199 +1,195 @@ /* - * Copyright (c) 2010-2013 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h> #include <boost/bind.hpp> #include <boost/numeric/conversion/cast.hpp> -#include <iostream> -#include <Swiften/Base/ByteArray.h> -#include <Swiften/Base/SafeByteArray.h> #include <Swiften/Base/Algorithm.h> +#include <Swiften/Base/ByteArray.h> #include <Swiften/Base/Concat.h> #include <Swiften/Base/Log.h> -#include <Swiften/Network/HostAddressPort.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> +#include <Swiften/Base/SafeByteArray.h> #include <Swiften/FileTransfer/BytestreamException.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> +#include <Swiften/Network/HostAddressPort.h> namespace Swift { SOCKS5BytestreamServerSession::SOCKS5BytestreamServerSession( boost::shared_ptr<Connection> connection, SOCKS5BytestreamRegistry* bytestreams) : connection(connection), bytestreams(bytestreams), state(Initial), chunkSize(131072), waitingForData(false) { disconnectedConnection = connection->onDisconnected.connect(boost::bind(&SOCKS5BytestreamServerSession::handleDisconnected, this, _1)); } SOCKS5BytestreamServerSession::~SOCKS5BytestreamServerSession() { if (state != Finished && state != Initial) { - std::cerr << "Warning: SOCKS5BytestreamServerSession unfinished" << std::endl; - finish(false); + SWIFT_LOG(warning) << "SOCKS5BytestreamServerSession unfinished" << std::endl; + finish(); } } void SOCKS5BytestreamServerSession::start() { SWIFT_LOG(debug) << std::endl; dataReadConnection = connection->onDataRead.connect( boost::bind(&SOCKS5BytestreamServerSession::handleDataRead, this, _1)); state = WaitingForAuthentication; } void SOCKS5BytestreamServerSession::stop() { - finish(false); + finish(); } void SOCKS5BytestreamServerSession::startSending(boost::shared_ptr<ReadBytestream> stream) { if (state != ReadyForTransfer) { SWIFT_LOG(debug) << "Not ready for transfer!" << std::endl; return; } readBytestream = stream; state = WritingData; dataAvailableConnection = readBytestream->onDataAvailable.connect( boost::bind(&SOCKS5BytestreamServerSession::handleDataAvailable, this)); dataWrittenConnection = connection->onDataWritten.connect( boost::bind(&SOCKS5BytestreamServerSession::sendData, this)); sendData(); } void SOCKS5BytestreamServerSession::startReceiving(boost::shared_ptr<WriteBytestream> stream) { if (state != ReadyForTransfer) { SWIFT_LOG(debug) << "Not ready for transfer!" << std::endl; return; } writeBytestream = stream; state = ReadingData; writeBytestream->write(unprocessedData); // onBytesReceived(unprocessedData.size()); unprocessedData.clear(); } HostAddressPort SOCKS5BytestreamServerSession::getAddressPort() const { return connection->getLocalAddress(); } void SOCKS5BytestreamServerSession::handleDataRead(boost::shared_ptr<SafeByteArray> data) { if (state != ReadingData) { append(unprocessedData, *data); process(); } else { - writeBytestream->write(createByteArray(vecptr(*data), data->size())); - // onBytesReceived(data->size()); + if (!writeBytestream->write(createByteArray(vecptr(*data), data->size()))) { + finish(boost::optional<FileTransferError>(FileTransferError::WriteError)); + } } } void SOCKS5BytestreamServerSession::handleDataAvailable() { if (waitingForData) { sendData(); } } void SOCKS5BytestreamServerSession::handleDisconnected(const boost::optional<Connection::Error>& error) { SWIFT_LOG(debug) << (error ? (error == Connection::ReadError ? "Read Error" : "Write Error") : "No Error") << std::endl; - finish(error ? true : false); + finish(error ? boost::optional<FileTransferError>(FileTransferError::PeerError) : boost::optional<FileTransferError>()); } void SOCKS5BytestreamServerSession::process() { if (state == WaitingForAuthentication) { if (unprocessedData.size() >= 2) { size_t authCount = unprocessedData[1]; size_t i = 2; while (i < 2 + authCount && i < unprocessedData.size()) { // Skip authentication mechanism ++i; } if (i == 2 + authCount) { // Authentication message is complete if (i != unprocessedData.size()) { SWIFT_LOG(debug) << "Junk after authentication mechanism" << std::endl; } unprocessedData.clear(); connection->write(createSafeByteArray("\x05\x00", 2)); state = WaitingForRequest; } } } else if (state == WaitingForRequest) { if (unprocessedData.size() >= 5) { ByteArray requestID; size_t i = 5; size_t hostnameSize = unprocessedData[4]; while (i < 5 + hostnameSize && i < unprocessedData.size()) { requestID.push_back(unprocessedData[i]); ++i; } // Skip the port: 2 byte large, one already skipped. Add one for comparison with size i += 2; if (i <= unprocessedData.size()) { if (i != unprocessedData.size()) { SWIFT_LOG(debug) << "Junk after authentication mechanism" << std::endl; } unprocessedData.clear(); streamID = byteArrayToString(requestID); bool hasBytestream = bytestreams->hasBytestream(streamID); SafeByteArray result = createSafeByteArray("\x05", 1); result.push_back(hasBytestream ? 0x0 : 0x4); append(result, createByteArray("\x00\x03", 2)); result.push_back(boost::numeric_cast<unsigned char>(requestID.size())); append(result, concat(requestID, createByteArray("\x00\x00", 2))); if (!hasBytestream) { SWIFT_LOG(debug) << "Readstream or Wrtiestream with ID " << streamID << " not found!" << std::endl; connection->write(result); - finish(true); + finish(boost::optional<FileTransferError>(FileTransferError::PeerError)); } else { SWIFT_LOG(debug) << "Found stream. Sent OK." << std::endl; connection->write(result); state = ReadyForTransfer; } } } } } void SOCKS5BytestreamServerSession::sendData() { if (!readBytestream->isFinished()) { try { SafeByteArray dataToSend = createSafeByteArray(*readBytestream->read(boost::numeric_cast<size_t>(chunkSize))); if (!dataToSend.empty()) { connection->write(dataToSend); onBytesSent(dataToSend.size()); waitingForData = false; } else { waitingForData = true; } } catch (const BytestreamException&) { - finish(true); + finish(boost::optional<FileTransferError>(FileTransferError::PeerError)); } } else { - finish(false); + finish(); } } -void SOCKS5BytestreamServerSession::finish(bool error) { - SWIFT_LOG(debug) << error << " " << state << std::endl; +void SOCKS5BytestreamServerSession::finish(const boost::optional<FileTransferError>& error) { + SWIFT_LOG(debug) << "state: " << state << std::endl; if (state == Finished) { return; } disconnectedConnection.disconnect(); dataReadConnection.disconnect(); dataWrittenConnection.disconnect(); dataAvailableConnection.disconnect(); readBytestream.reset(); state = Finished; - if (error) { - onFinished(boost::optional<FileTransferError>(FileTransferError::PeerError)); - } else { - onFinished(boost::optional<FileTransferError>()); - } + onFinished(error); } } |