diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 31138b4b0..457f81dcd 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -41,6 +41,7 @@ target_link_libraries(kdeconnectcore PUBLIC Qt5::Network KF5::CoreAddons + KF5::KIOCore qca-qt5 PRIVATE Qt5::DBus diff --git a/core/backends/lan/landevicelink.cpp b/core/backends/lan/landevicelink.cpp index e7f974586..9fb8f4baa 100644 --- a/core/backends/lan/landevicelink.cpp +++ b/core/backends/lan/landevicelink.cpp @@ -24,9 +24,11 @@ #include "core_debug.h" #include "kdeconnectconfig.h" #include "backends/linkprovider.h" -#include "uploadjob.h" #include "socketlinereader.h" #include "lanlinkprovider.h" +#include +#include +#include LanDeviceLink::LanDeviceLink(const QString& deviceId, LinkProvider* parent, QSslSocket* socket, ConnectionStarted connectionSource) : DeviceLink(deviceId, parent) @@ -98,6 +100,9 @@ bool LanDeviceLink::sendPacket(NetworkPacket& np) UploadJob* LanDeviceLink::sendPayload(const NetworkPacket& np) { UploadJob* job = new UploadJob(np.payload(), deviceId()); + if (np.type() == PACKET_TYPE_SHARE_REQUEST && np.payloadSize() >= 0) { + KIO::getJobTracker()->registerJob(job); + } job->start(); return job; } diff --git a/core/backends/lan/uploadjob.cpp b/core/backends/lan/uploadjob.cpp index 65a713f80..1bd2d17d1 100644 --- a/core/backends/lan/uploadjob.cpp +++ b/core/backends/lan/uploadjob.cpp @@ -25,6 +25,8 @@ #include "lanlinkprovider.h" #include "kdeconnectconfig.h" #include "core_debug.h" +#include +#include UploadJob::UploadJob(const QSharedPointer& source, const QString& deviceId) : KJob() @@ -34,8 +36,8 @@ UploadJob::UploadJob(const QSharedPointer& source, const QString& dev , m_port(0) , m_deviceId(deviceId) // We will use this info if link is on ssl, to send encrypted payload { - connect(m_input.data(), &QIODevice::readyRead, this, &UploadJob::startUploading); connect(m_input.data(), &QIODevice::aboutToClose, this, &UploadJob::aboutToClose); + setCapabilities(Killable); } void UploadJob::start() @@ -53,6 +55,10 @@ void UploadJob::start() } } connect(m_server, &QTcpServer::newConnection, this, &UploadJob::newConnection); + + Q_EMIT description(this, i18n("Sending file to %1", Daemon::instance()->getDevice(this->m_deviceId)->name()), + { i18nc("File transfer origin", "From"), m_input.staticCast().data()->fileName() } + ); } void UploadJob::newConnection() @@ -68,7 +74,6 @@ void UploadJob::newConnection() connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketFailed(QAbstractSocket::SocketError))); connect(m_socket, SIGNAL(sslErrors(QList)), this, SLOT(sslErrors(QList))); connect(m_socket, &QSslSocket::encrypted, this, &UploadJob::startUploading); -// connect(mSocket, &QAbstractSocket::stateChanged, [](QAbstractSocket::SocketState state){ qDebug() << "statechange" << state; }); LanLinkProvider::configureSslSocket(m_socket, m_deviceId, true); @@ -77,32 +82,66 @@ void UploadJob::newConnection() void UploadJob::startUploading() { - while ( m_input->bytesAvailable() > 0 ) - { - qint64 bytes = qMin(m_input->bytesAvailable(), (qint64)4096); - int w = m_socket->write(m_input->read(bytes)); - if (w<0) { - qCWarning(KDECONNECT_CORE) << "error when writing data to upload" << bytes << m_input->bytesAvailable(); - break; - } - else - { - while ( m_socket->flush() ); + bytesUploaded = 0; + setProcessedAmount(Bytes, bytesUploaded); + setTotalAmount(Bytes, m_input.data()->size()); + + connect(m_socket, &QSslSocket::encryptedBytesWritten, this, &UploadJob::encryptedBytesWritten); + + if (!m_timer.isValid()) { + m_timer.start(); + } + + uploadNextPacket(); +} + +void UploadJob::uploadNextPacket() +{ + qint64 bytesAvailable = m_input->bytesAvailable(); + + if ( bytesAvailable > 0) { + qint64 bytesToSend = qMin(m_input->bytesAvailable(), (qint64)4096); + bytesUploading = m_socket->write(m_input->read(bytesToSend)); + + if (bytesUploading < 0) { + qCWarning(KDECONNECT_CORE) << "error when writing data to upload" << bytesToSend << m_input->bytesAvailable(); } } - m_input->close(); + + if (bytesAvailable <= 0 || bytesUploading < 0) { + m_input->close(); + disconnect(m_socket, &QSslSocket::encryptedBytesWritten, this, &UploadJob::encryptedBytesWritten); + } +} + +void UploadJob::encryptedBytesWritten(qint64 bytes) +{ + Q_UNUSED(bytes); + + bytesUploaded += bytesUploading; + + if (m_socket->encryptedBytesToWrite() == 0) { + setProcessedAmount(Bytes, bytesUploaded); + + const auto elapsed = m_timer.elapsed(); + if (elapsed > 0) { + emitSpeed((1000 * bytesUploaded) / elapsed); + } + + uploadNextPacket(); + } } void UploadJob::aboutToClose() { -// qDebug() << "closing..."; + qWarning() << "aboutToClose()"; m_socket->disconnectFromHost(); } void UploadJob::cleanup() { + qWarning() << "cleanup()"; m_socket->close(); -// qDebug() << "closed!"; emitResult(); } @@ -114,16 +153,24 @@ QVariantMap UploadJob::transferInfo() void UploadJob::socketFailed(QAbstractSocket::SocketError error) { - qWarning() << "error uploading" << error; + qWarning() << "socketFailed() " << error; + m_socket->close(); setError(2); emitResult(); - m_socket->close(); } void UploadJob::sslErrors(const QList& errors) { - qWarning() << "ssl errors" << errors; + qWarning() << "sslErrors() " << errors; setError(1); emitResult(); m_socket->close(); } + +bool UploadJob::doKill() +{ + if (m_input) { + m_input->close(); + } + return true; +} diff --git a/core/backends/lan/uploadjob.h b/core/backends/lan/uploadjob.h index e449e4154..7f9ff4f66 100644 --- a/core/backends/lan/uploadjob.h +++ b/core/backends/lan/uploadjob.h @@ -28,6 +28,8 @@ #include #include #include "server.h" +#include +#include class KDECONNECTCORE_EXPORT UploadJob : public KJob @@ -46,13 +48,21 @@ private: QSslSocket* m_socket; quint16 m_port; const QString m_deviceId; + qint64 bytesUploading; + qint64 bytesUploaded; + QElapsedTimer m_timer; const static quint16 MIN_PORT = 1739; const static quint16 MAX_PORT = 1764; + +protected: + bool doKill() override; private Q_SLOTS: void startUploading(); + void uploadNextPacket(); void newConnection(); + void encryptedBytesWritten(qint64 bytes); void aboutToClose(); void cleanup();