diff --git a/src/core/connection.cpp b/src/core/connection.cpp index c3585d00..8e80a887 100644 --- a/src/core/connection.cpp +++ b/src/core/connection.cpp @@ -1,230 +1,232 @@ /* This file is part of the KDE libraries Copyright (C) 2000 Stephan Kulow David Faure Copyright (C) 2007 Thiago Macieira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "connection_p.h" #include #include "connectionbackend_p.h" #include "kiocoredebug.h" #include #include #include using namespace KIO; void ConnectionPrivate::dequeue() { if (!backend || suspended) { return; } foreach (const Task &task, outgoingTasks) { q->sendnow(task.cmd, task.data); } outgoingTasks.clear(); if (!incomingTasks.isEmpty()) { emit q->readyRead(); } } void ConnectionPrivate::commandReceived(const Task &task) { //qDebug() << this << "Command " << task.cmd << " added to the queue"; if (!suspended && incomingTasks.isEmpty()) { QMetaObject::invokeMethod(q, "dequeue", Qt::QueuedConnection); } - incomingTasks.enqueue(task); + incomingTasks.append(task); } void ConnectionPrivate::disconnected() { q->close(); QMetaObject::invokeMethod(q, "readyRead", Qt::QueuedConnection); } void ConnectionPrivate::setBackend(ConnectionBackend *b) { delete backend; backend = b; if (backend) { q->connect(backend, SIGNAL(commandReceived(Task)), SLOT(commandReceived(Task))); q->connect(backend, SIGNAL(disconnected()), SLOT(disconnected())); backend->setSuspended(suspended); } } Connection::Connection(QObject *parent) : QObject(parent), d(new ConnectionPrivate) { d->q = this; } Connection::~Connection() { close(); delete d; } void Connection::suspend() { //qDebug() << this << "Suspended"; d->suspended = true; if (d->backend) { d->backend->setSuspended(true); } } void Connection::resume() { // send any outgoing or incoming commands that may be in queue QMetaObject::invokeMethod(this, "dequeue", Qt::QueuedConnection); //qDebug() << this << "Resumed"; d->suspended = false; if (d->backend) { d->backend->setSuspended(false); } } void Connection::close() { if (d->backend) { d->backend->disconnect(this); d->backend->deleteLater(); d->backend = nullptr; } d->outgoingTasks.clear(); d->incomingTasks.clear(); } bool Connection::isConnected() const { return d->backend && d->backend->state == ConnectionBackend::Connected; } bool Connection::inited() const { return d->backend; } bool Connection::suspended() const { return d->suspended; } void Connection::connectToRemote(const QUrl &address) { //qDebug() << "Connection requested to " << address; const QString scheme = address.scheme(); if (scheme == QLatin1String("local")) { d->setBackend(new ConnectionBackend(ConnectionBackend::LocalSocketMode, this)); } else if (scheme == QLatin1String("tcp")) { d->setBackend(new ConnectionBackend(ConnectionBackend::TcpSocketMode, this)); } else { qCWarning(KIO_CORE) << "Unknown protocol requested:" << scheme << "(" << address << ")"; Q_ASSERT(0); return; } // connection succeeded if (!d->backend->connectToRemote(address)) { //kWarning(7017) << "could not connect to" << address << "using scheme" << scheme ; delete d->backend; d->backend = nullptr; return; } d->dequeue(); } QString Connection::errorString() const { if (d->backend) { return d->backend->errorString; } return QString(); } bool Connection::send(int cmd, const QByteArray &data) { if (!inited() || !d->outgoingTasks.isEmpty()) { Task task; task.cmd = cmd; task.data = data; - d->outgoingTasks.append(task); + d->outgoingTasks.append(std::move(task)); return true; } else { return sendnow(cmd, data); } } bool Connection::sendnow(int cmd, const QByteArray &data) { if (!d->backend || data.size() > 0xffffff || !isConnected()) { return false; } //qDebug() << this << "Sending command " << _cmd << " of size " << data.size(); return d->backend->sendCommand(cmd, data); } bool Connection::hasTaskAvailable() const { return !d->incomingTasks.isEmpty(); } bool Connection::waitForIncomingTask(int ms) { if (!isConnected()) { return false; } if (d->backend) { return d->backend->waitForIncomingTask(ms); } return false; } int Connection::read(int *_cmd, QByteArray &data) { // if it's still empty, then it's an error if (d->incomingTasks.isEmpty()) { //kWarning() << this << "Task list is empty!"; return -1; } - const Task task = d->incomingTasks.dequeue(); + const Task& task = d->incomingTasks.constFirst(); //qDebug() << this << "Command " << task.cmd << " removed from the queue (size " // << task.data.size() << ")"; *_cmd = task.cmd; data = task.data; + d->incomingTasks.removeFirst(); + // if we didn't empty our reading queue, emit again if (!d->suspended && !d->incomingTasks.isEmpty()) { QMetaObject::invokeMethod(this, "dequeue", Qt::QueuedConnection); } return data.size(); } #include "moc_connection_p.cpp" diff --git a/src/core/connection_p.h b/src/core/connection_p.h index 415c0121..f323fb08 100644 --- a/src/core/connection_p.h +++ b/src/core/connection_p.h @@ -1,169 +1,169 @@ /* This file is part of the KDE libraries Copyright (C) 2000 Stephan Kulow David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIO_CONNECTION_H #define KIO_CONNECTION_H #include #include #include -#include +#include #include "connectionbackend_p.h" namespace KIO { class Connection; // Separated from Connection only for historical reasons - they are both private now class ConnectionPrivate { public: inline ConnectionPrivate() : backend(nullptr), q(nullptr), suspended(false) { } void dequeue(); void commandReceived(const Task &task); void disconnected(); void setBackend(ConnectionBackend *b); - QList outgoingTasks; - QQueue incomingTasks; + QVector outgoingTasks; + QVector incomingTasks; ConnectionBackend *backend; Connection *q; bool suspended; }; class ConnectionServer; /** * @private * * This class provides a simple means for IPC between two applications * via a pipe. * It handles a queue of commands to be sent which makes it possible to * queue data before an actual connection has been established. */ class Connection : public QObject { Q_OBJECT public: /** * Creates a new connection. * @see connectToRemote, listenForRemote */ explicit Connection(QObject *parent = nullptr); virtual ~Connection(); /** * Connects to the remote address. * @param address a local:// or tcp:// URL. */ void connectToRemote(const QUrl &address); /// Closes the connection. void close(); QString errorString() const; bool isConnected() const; /** * Checks whether the connection has been initialized. * @return true if the initialized * @see init() */ bool inited() const; /** * Sends/queues the given command to be sent. * @param cmd the command to set * @param arr the bytes to send * @return true if successful, false otherwise */ bool send(int cmd, const QByteArray &arr = QByteArray()); /** * Sends the given command immediately. * @param _cmd the command to set * @param data the bytes to send * @return true if successful, false otherwise */ bool sendnow(int _cmd, const QByteArray &data); /** * Returns true if there are packets to be read immediately, * false if waitForIncomingTask must be called before more data * is available. */ bool hasTaskAvailable() const; /** * Waits for one more command to be handled and ready. * * @param ms the time to wait in milliseconds * @returns true if one command can be read, false if we timed out */ bool waitForIncomingTask(int ms = 30000); /** * Receive data. * * @param _cmd the received command will be written here * @param data the received data will be written here * @return >=0 indicates the received data size upon success * -1 indicates error */ int read(int *_cmd, QByteArray &data); /** * Don't handle incoming data until resumed. */ void suspend(); /** * Resume handling of incoming data. */ void resume(); /** * Returns status of connection. * @return true if suspended, false otherwise */ bool suspended() const; Q_SIGNALS: void readyRead(); private: Q_PRIVATE_SLOT(d, void dequeue()) Q_PRIVATE_SLOT(d, void commandReceived(Task)) Q_PRIVATE_SLOT(d, void disconnected()) friend class ConnectionPrivate; friend class ConnectionServer; class ConnectionPrivate *const d; }; class ConnectionServerPrivate; } #endif