Changeset View
Changeset View
Standalone View
Standalone View
core/backends/lan/uploadjob.cpp
Show All 19 Lines | |||||
20 | 20 | | |||
21 | #include "uploadjob.h" | 21 | #include "uploadjob.h" | ||
22 | 22 | | |||
23 | #include <KLocalizedString> | 23 | #include <KLocalizedString> | ||
24 | 24 | | |||
25 | #include "lanlinkprovider.h" | 25 | #include "lanlinkprovider.h" | ||
26 | #include "kdeconnectconfig.h" | 26 | #include "kdeconnectconfig.h" | ||
27 | #include "core_debug.h" | 27 | #include "core_debug.h" | ||
28 | #include <device.h> | | |||
29 | #include <daemon.h> | 28 | #include <daemon.h> | ||
30 | 29 | | |||
31 | UploadJob::UploadJob(const QSharedPointer<QIODevice>& source, const QString& deviceId) | 30 | UploadJob::UploadJob(const NetworkPacket& networkPacket) | ||
32 | : KJob() | 31 | : KJob() | ||
33 | , m_input(source) | 32 | , m_networkPacket(networkPacket) | ||
34 | , m_server(new Server(this)) | 33 | , m_input(networkPacket.payload()) | ||
35 | , m_socket(nullptr) | 34 | , m_socket(nullptr) | ||
36 | , m_port(0) | | |||
37 | , m_deviceId(deviceId) // We will use this info if link is on ssl, to send encrypted payload | | |||
38 | { | 35 | { | ||
39 | connect(m_input.data(), &QIODevice::aboutToClose, this, &UploadJob::aboutToClose); | | |||
40 | setCapabilities(Killable); | | |||
41 | } | 36 | } | ||
42 | 37 | | |||
43 | void UploadJob::start() | 38 | void UploadJob::setSocket(QSslSocket* socket) | ||
44 | { | 39 | { | ||
45 | m_port = MIN_PORT; | 40 | m_socket = socket; | ||
46 | while (!m_server->listen(QHostAddress::Any, m_port)) { | 41 | m_socket->setParent(this); | ||
47 | m_port++; | | |||
48 | if (m_port > MAX_PORT) { //No ports available? | | |||
49 | qCWarning(KDECONNECT_CORE) << "Error opening a port in range" << MIN_PORT << "-" << MAX_PORT; | | |||
50 | m_port = 0; | | |||
51 | setError(1); | | |||
52 | setErrorText(i18n("Couldn't find an available port")); | | |||
53 | emitResult(); | | |||
54 | return; | | |||
55 | } | | |||
56 | } | | |||
57 | connect(m_server, &QTcpServer::newConnection, this, &UploadJob::newConnection); | | |||
58 | | ||||
59 | Q_EMIT description(this, i18n("Sending file to %1", Daemon::instance()->getDevice(this->m_deviceId)->name()), | | |||
60 | { i18nc("File transfer origin", "From"), m_input.staticCast<QFile>().data()->fileName() } | | |||
61 | ); | | |||
62 | } | 42 | } | ||
63 | 43 | | |||
64 | void UploadJob::newConnection() | 44 | void UploadJob::start() | ||
65 | { | 45 | { | ||
66 | if (!m_input->open(QIODevice::ReadOnly)) { | 46 | if (!m_input->open(QIODevice::ReadOnly)) { | ||
67 | qCWarning(KDECONNECT_CORE) << "error when opening the input to upload"; | 47 | qCWarning(KDECONNECT_CORE) << "error when opening the input to upload"; | ||
68 | return; //TODO: Handle error, clean up... | 48 | return; //TODO: Handle error, clean up... | ||
69 | } | 49 | } | ||
70 | 50 | | |||
71 | m_socket = m_server->nextPendingConnection(); | 51 | if (!m_socket) { | ||
72 | m_socket->setParent(this); | 52 | qCWarning(KDECONNECT_CORE) << "you must call setSocket() before calling start()"; | ||
73 | connect(m_socket, &QSslSocket::disconnected, this, &UploadJob::cleanup); | 53 | return; | ||
74 | connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketFailed(QAbstractSocket::SocketError))); | | |||
75 | connect(m_socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>))); | | |||
76 | connect(m_socket, &QSslSocket::encrypted, this, &UploadJob::startUploading); | | |||
77 | | ||||
78 | LanLinkProvider::configureSslSocket(m_socket, m_deviceId, true); | | |||
79 | | ||||
80 | m_socket->startServerEncryption(); | | |||
81 | } | 54 | } | ||
82 | 55 | | |||
83 | void UploadJob::startUploading() | 56 | connect(m_input.data(), &QIODevice::aboutToClose, this, &UploadJob::aboutToClose); | ||
84 | { | 57 | | ||
85 | bytesUploaded = 0; | 58 | bytesUploaded = 0; | ||
86 | setProcessedAmount(Bytes, bytesUploaded); | 59 | setProcessedAmount(Bytes, bytesUploaded); | ||
87 | setTotalAmount(Bytes, m_input.data()->size()); | | |||
88 | 60 | | |||
89 | connect(m_socket, &QSslSocket::encryptedBytesWritten, this, &UploadJob::encryptedBytesWritten); | 61 | connect(m_socket, &QSslSocket::encryptedBytesWritten, this, &UploadJob::encryptedBytesWritten); | ||
90 | 62 | | |||
91 | if (!m_timer.isValid()) { | | |||
92 | m_timer.start(); | | |||
93 | } | | |||
94 | | ||||
95 | uploadNextPacket(); | 63 | uploadNextPacket(); | ||
96 | } | 64 | } | ||
97 | 65 | | |||
98 | void UploadJob::uploadNextPacket() | 66 | void UploadJob::uploadNextPacket() | ||
99 | { | 67 | { | ||
100 | qint64 bytesAvailable = m_input->bytesAvailable(); | 68 | qint64 bytesAvailable = m_input->bytesAvailable(); | ||
101 | 69 | | |||
102 | if ( bytesAvailable > 0) { | 70 | if ( bytesAvailable > 0) { | ||
103 | qint64 bytesToSend = qMin(m_input->bytesAvailable(), (qint64)4096); | 71 | qint64 bytesToSend = qMin(m_input->bytesAvailable(), (qint64)4096); | ||
104 | bytesUploading = m_socket->write(m_input->read(bytesToSend)); | 72 | bytesUploading = m_socket->write(m_input->read(bytesToSend)); | ||
105 | | ||||
106 | if (bytesUploading < 0) { | | |||
107 | qCWarning(KDECONNECT_CORE) << "error when writing data to upload" << bytesToSend << m_input->bytesAvailable(); | | |||
108 | } | | |||
109 | } | 73 | } | ||
110 | 74 | | |||
111 | if (bytesAvailable <= 0 || bytesUploading < 0) { | 75 | if (bytesAvailable <= 0 || bytesUploading < 0) { | ||
112 | m_input->close(); | 76 | m_input->close(); | ||
113 | disconnect(m_socket, &QSslSocket::encryptedBytesWritten, this, &UploadJob::encryptedBytesWritten); | 77 | disconnect(m_socket, &QSslSocket::encryptedBytesWritten, this, &UploadJob::encryptedBytesWritten); | ||
114 | } | 78 | } | ||
115 | } | 79 | } | ||
116 | 80 | | |||
117 | void UploadJob::encryptedBytesWritten(qint64 bytes) | 81 | void UploadJob::encryptedBytesWritten(qint64 bytes) | ||
118 | { | 82 | { | ||
119 | Q_UNUSED(bytes); | 83 | Q_UNUSED(bytes); | ||
120 | 84 | | |||
121 | bytesUploaded += bytesUploading; | | |||
122 | | ||||
123 | if (m_socket->encryptedBytesToWrite() == 0) { | 85 | if (m_socket->encryptedBytesToWrite() == 0) { | ||
86 | bytesUploaded += bytesUploading; | ||||
124 | setProcessedAmount(Bytes, bytesUploaded); | 87 | setProcessedAmount(Bytes, bytesUploaded); | ||
125 | 88 | | |||
126 | const auto elapsed = m_timer.elapsed(); | | |||
127 | if (elapsed > 0) { | | |||
128 | emitSpeed((1000 * bytesUploaded) / elapsed); | | |||
129 | } | | |||
130 | | ||||
131 | uploadNextPacket(); | 89 | uploadNextPacket(); | ||
132 | } | 90 | } | ||
133 | } | 91 | } | ||
134 | 92 | | |||
135 | void UploadJob::aboutToClose() | 93 | void UploadJob::aboutToClose() | ||
136 | { | 94 | { | ||
137 | qWarning() << "aboutToClose()"; | | |||
138 | m_socket->disconnectFromHost(); | 95 | m_socket->disconnectFromHost(); | ||
139 | } | | |||
140 | | ||||
141 | void UploadJob::cleanup() | | |||
142 | { | | |||
143 | qWarning() << "cleanup()"; | | |||
144 | m_socket->close(); | | |||
145 | emitResult(); | 96 | emitResult(); | ||
146 | } | 97 | } | ||
147 | 98 | | |||
148 | QVariantMap UploadJob::transferInfo() | 99 | bool UploadJob::stop() { | ||
149 | { | 100 | m_input->close(); | ||
150 | Q_ASSERT(m_port != 0); | | |||
151 | return {{"port", m_port}}; | | |||
152 | } | | |||
153 | | ||||
154 | void UploadJob::socketFailed(QAbstractSocket::SocketError error) | | |||
155 | { | | |||
156 | qWarning() << "socketFailed() " << error; | | |||
157 | m_socket->close(); | | |||
158 | setError(2); | | |||
159 | emitResult(); | | |||
160 | } | | |||
161 | 101 | | |||
162 | void UploadJob::sslErrors(const QList<QSslError>& errors) | 102 | return true; | ||
163 | { | | |||
164 | qWarning() << "sslErrors() " << errors; | | |||
165 | setError(1); | | |||
166 | emitResult(); | | |||
167 | m_socket->close(); | | |||
168 | } | 103 | } | ||
169 | 104 | | |||
170 | bool UploadJob::doKill() | 105 | const NetworkPacket UploadJob::getNetworkPacket() | ||
171 | { | 106 | { | ||
172 | if (m_input) { | 107 | return m_networkPacket; | ||
173 | m_input->close(); | | |||
174 | } | | |||
175 | return true; | | |||
176 | } | 108 | } |