diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index 67f664bd..05965ff5 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -1,166 +1,164 @@ remove_definitions(-DQT_NO_CAST_FROM_ASCII) remove_definitions(-DQT_NO_CAST_FROM_BYTEARRAY) include(ECMAddTests) add_subdirectory(http) add_subdirectory(kcookiejar) find_package(Qt5Widgets REQUIRED) ########### unittests ############### find_package(Qt5Concurrent ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE) ecm_add_tests( kacltest.cpp listdirtest.cpp kmountpointtest.cpp upurltest.cpp dataprotocoltest.cpp jobtest.cpp jobremotetest.cpp kfileitemtest.cpp kprotocolinfotest.cpp ktcpsockettest.cpp globaltest.cpp mkpathjobtest.cpp threadtest.cpp udsentrytest.cpp udsentry_benchmark.cpp kcoredirlister_benchmark.cpp deletejobtest.cpp urlutiltest.cpp batchrenamejobtest.cpp ksambasharetest.cpp NAME_PREFIX "kiocore-" LINK_LIBRARIES KF5::KIOCore KF5::I18n Qt5::Test Qt5::Network ) target_link_libraries(threadtest Qt5::Concurrent) ecm_add_test( http_jobtest.cpp httpserver_p.cpp TEST_NAME http_jobtest NAME_PREFIX "kiocore-" LINK_LIBRARIES KF5::KIOCore KF5::I18n Qt5::Test Qt5::Network ) include(FindGem) find_gem(ftpd) set_package_properties(Gem_ftpd PROPERTIES DESCRIPTION "Ruby gem 'ftpd' required for testing the ftp slave.") if(Gem_ftpd_FOUND) add_definitions(-DRubyExe_EXECUTABLE="${RubyExe_EXECUTABLE}") ecm_add_tests( ftptest.cpp NAME_PREFIX "kiocore-" LINK_LIBRARIES KF5::KIOCore KF5::I18n Qt5::Test Qt5::Network ) endif() if(UNIX) ecm_add_tests( - klocalsockettest.cpp - klocalsocketservertest.cpp privilegejobtest.cpp NAME_PREFIX "kiocore-" LINK_LIBRARIES KF5::KIOCore KF5::I18n Qt5::Test Qt5::Network ) endif() if (TARGET KF5::KIOGui) ecm_add_tests( favicontest.cpp applicationlauncherjobtest.cpp commandlauncherjobtest.cpp NAME_PREFIX "kiogui-" LINK_LIBRARIES KF5::KIOCore KF5::KIOGui Qt5::Test ) target_link_libraries(favicontest Qt5::Concurrent) endif() if (TARGET KF5::KIOWidgets) ecm_add_tests( clipboardupdatertest.cpp dropjobtest.cpp kdynamicjobtrackernowidgetstest.cpp krununittest.cpp kdirlistertest.cpp kdirmodeltest.cpp kfileitemactionstest.cpp fileundomanagertest.cpp kurifiltertest.cpp kurlcompletiontest.cpp jobguitest.cpp pastetest.cpp accessmanagertest.cpp kurifiltersearchprovideractionstest.cpp NAME_PREFIX "kiowidgets-" LINK_LIBRARIES KF5::KIOCore KF5::KIOWidgets Qt5::Test Qt5::DBus ) set_target_properties(krununittest PROPERTIES COMPILE_FLAGS "-DCMAKE_INSTALL_FULL_LIBEXECDIR_KF5=\"\\\"${CMAKE_INSTALL_FULL_LIBEXECDIR_KF5}\\\"\"") # Same as accessmanagertest, but using QNetworkAccessManager, to make sure we # behave the same ecm_add_test( accessmanagertest.cpp TEST_NAME accessmanagertest-qnam NAME_PREFIX "kiowidgets-" LINK_LIBRARIES KF5::KIOCore KF5::KIOWidgets Qt5::Test ) set_target_properties(accessmanagertest-qnam PROPERTIES COMPILE_FLAGS "-DUSE_QNAM") # Same as kurlcompletiontest, but with immediate return, and results posted by thread later ecm_add_test( kurlcompletiontest.cpp TEST_NAME kurlcompletiontest-nowait NAME_PREFIX "kiowidgets-" LINK_LIBRARIES KF5::KIOCore KF5::KIOWidgets Qt5::Test ) set_target_properties(kurlcompletiontest-nowait PROPERTIES COMPILE_FLAGS "-DNO_WAIT") endif() if (TARGET KF5::KIOFileWidgets) find_package(KF5XmlGui ${KF5_DEP_VERSION} REQUIRED) include_directories(${CMAKE_SOURCE_DIR}/src/filewidgets ${CMAKE_BINARY_DIR}/src/filewidgets) ecm_add_tests( kurlnavigatortest.cpp kurlcomboboxtest.cpp kdiroperatortest.cpp kfilewidgettest.cpp kfilecustomdialogtest.cpp knewfilemenutest.cpp kfilecopytomenutest.cpp kfileplacesmodeltest.cpp kfileplacesviewtest.cpp kurlrequestertest.cpp NAME_PREFIX "kiofilewidgets-" LINK_LIBRARIES KF5::KIOFileWidgets KF5::KIOWidgets KF5::XmlGui KF5::Bookmarks Qt5::Test KF5::I18n ) # TODO: fix symbol exports for windows -> 'KSambaShare::KSambaShare': inconsistent dll linkage if (NOT WIN32) ecm_add_test( ksambashareprivatetest.cpp ../src/core/ksambashare.cpp ../src/core/kiocoredebug.cpp TEST_NAME ksambashareprivatetest NAME_PREFIX "kiocore-" LINK_LIBRARIES KF5::KIOCore Qt5::Test Qt5::Network ) endif() set_tests_properties(kiofilewidgets-kfileplacesmodeltest PROPERTIES RUN_SERIAL TRUE) set_tests_properties(kiofilewidgets-kfileplacesviewtest PROPERTIES RUN_SERIAL TRUE) endif() # this should be done by cmake, see bug 371721 if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND Qt5Core_VERSION VERSION_GREATER 5.8.0) set_property(TARGET jobtest APPEND PROPERTY AUTOMOC_MOC_OPTIONS --include ${CMAKE_BINARY_DIR}/src/core/moc_predefs.h) endif() diff --git a/autotests/klocalsocketservertest.cpp b/autotests/klocalsocketservertest.cpp deleted file mode 100644 index 6e76ef53..00000000 --- a/autotests/klocalsocketservertest.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/* - * This file is part of the KDE libraries - * 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 "klocalsocketservertest.h" -#include -#include - -#include -#include -#include "klocalsocket.h" - -static const char afile[] = "/tmp/afile"; -static const char asocket[] = "/tmp/asocket"; - -tst_KLocalSocketServer::tst_KLocalSocketServer() -{ - QFile f(QString::fromLatin1(QFile::encodeName(QLatin1String(afile)))); - f.open(QIODevice::ReadWrite | QIODevice::Truncate); -} - -tst_KLocalSocketServer::~tst_KLocalSocketServer() -{ - QFile::remove(QLatin1String(afile)); -} - -class TimedConnection: public QThread -{ - Q_OBJECT -public: - ~TimedConnection() override - { - wait(); - } -protected: - void run() override { - KLocalSocket socket; - QThread::usleep(200); - socket.connectToPath(QLatin1String(asocket)); - socket.waitForConnected(); - } -}; - -void tst_KLocalSocketServer::cleanup() -{ - QFile::remove(QLatin1String(asocket)); -} - -void tst_KLocalSocketServer::listen_data() -{ - QTest::addColumn("path"); - QTest::addColumn("success"); - - QTest::newRow("null") << QString() << false; - QTest::newRow("empty") << "" << false; - QTest::newRow("a-dir") << "/tmp/" << false; - QTest::newRow("not-a-dir") << QString(afile + QLatin1String("/foo")) << false; - QTest::newRow("not-permitted") << "/root/foo" << false; - QTest::newRow("valid") << asocket << true; -} - -void tst_KLocalSocketServer::listen() -{ - QFETCH(QString, path); - KLocalSocketServer server; - QTEST(server.listen(path), "success"); -} - -void tst_KLocalSocketServer::waitForConnection() -{ - KLocalSocketServer server; - QVERIFY(server.listen(QLatin1String(asocket))); - QVERIFY(!server.hasPendingConnections()); - - { - KLocalSocket socket; - socket.connectToPath(QLatin1String(asocket)); - QVERIFY(socket.waitForConnected()); - - // make sure we can accept that connection - QVERIFY(server.waitForNewConnection()); - QVERIFY(server.hasPendingConnections()); - delete server.nextPendingConnection(); - } - - // test a timeout now - QVERIFY(!server.hasPendingConnections()); - QVERIFY(!server.waitForNewConnection(0)); - QVERIFY(!server.waitForNewConnection(200)); - - { - // now try a timed connection - TimedConnection conn; - conn.start(); - QVERIFY(server.waitForNewConnection(500)); - QVERIFY(server.hasPendingConnections()); - delete server.nextPendingConnection(); - } -} - -void tst_KLocalSocketServer::newConnection() -{ - KLocalSocketServer server; - QVERIFY(server.listen(QLatin1String(asocket))); - QVERIFY(!server.hasPendingConnections()); - - // catch the signal - QSignalSpy spy(&server, SIGNAL(newConnection())); - - KLocalSocket socket; - socket.connectToPath(QLatin1String(asocket)); - QVERIFY(socket.waitForConnected()); - - // let the events be processed - QTest::qWait(100); - - QVERIFY(spy.count() == 1); -} - -void tst_KLocalSocketServer::accept() -{ - KLocalSocketServer server; - QVERIFY(server.listen(QLatin1String(asocket))); - QVERIFY(!server.hasPendingConnections()); - - KLocalSocket socket; - socket.connectToPath(QLatin1String(asocket)); - QVERIFY(socket.waitForConnected()); - QVERIFY(server.waitForNewConnection()); - QVERIFY(server.hasPendingConnections()); - - KLocalSocket *socket2 = server.nextPendingConnection(); - QVERIFY(!server.hasPendingConnections()); - QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); - QCOMPARE(socket2->state(), QAbstractSocket::ConnectedState); - - delete socket2; -} - -void tst_KLocalSocketServer::state() -{ - KLocalSocketServer server; - - // sanity check of the initial state: - QVERIFY(!server.isListening()); - QVERIFY(server.localPath().isEmpty()); - QCOMPARE(int(server.localSocketType()), int(KLocalSocket::UnknownLocalSocketType)); - QVERIFY(!server.hasPendingConnections()); - QVERIFY(!server.nextPendingConnection()); - - // it's not connected, so it shouldn't change timedOut - bool timedOut = true; - QVERIFY(!server.waitForNewConnection(0, &timedOut)); - QVERIFY(timedOut); - timedOut = false; - QVERIFY(!server.waitForNewConnection(0, &timedOut)); - QVERIFY(!timedOut); - - // start listening: - QVERIFY(server.listen(QLatin1String(asocket))); - QVERIFY(server.isListening()); - QCOMPARE(server.localPath(), QString(QLatin1String(asocket))); - QCOMPARE(int(server.localSocketType()), int(KLocalSocket::UnixSocket)); - QVERIFY(!server.hasPendingConnections()); - QVERIFY(!server.nextPendingConnection()); - - // it must timeout now: - timedOut = false; - QVERIFY(!server.waitForNewConnection(0, &timedOut)); - QVERIFY(timedOut); - - // make a connection: - KLocalSocket socket; - socket.connectToPath(QLatin1String(asocket)); - QVERIFY(socket.waitForConnected()); - - // it mustn't time out now: - timedOut = true; - QVERIFY(server.waitForNewConnection(0, &timedOut)); - QVERIFY(!timedOut); - - QVERIFY(server.hasPendingConnections()); - KLocalSocket *socket2 = server.nextPendingConnection(); - QVERIFY(socket2); - delete socket2; - - // close: - server.close(); - - // verify state: - QVERIFY(!server.isListening()); - QVERIFY(server.localPath().isEmpty()); - QCOMPARE(int(server.localSocketType()), int(KLocalSocket::UnknownLocalSocketType)); - QVERIFY(!server.hasPendingConnections()); - QVERIFY(!server.nextPendingConnection()); -} - -void tst_KLocalSocketServer::setMaxPendingConnections() -{ - KLocalSocketServer server; - QVERIFY(server.listen(QLatin1String(asocket))); - QVERIFY(!server.hasPendingConnections()); - server.setMaxPendingConnections(0); // we don't want to receive - - // check if the event loop won't cause a connection to accepted - KLocalSocket socket; - socket.connectToPath(QLatin1String(asocket)); - QTest::qWait(100); // 100 ms doing absolutely nothing - QVERIFY(!server.hasPendingConnections()); - - // now check if we get that connection - server.setMaxPendingConnections(1); - QTest::qWait(100); - QVERIFY(server.hasPendingConnections()); - delete server.nextPendingConnection(); - QVERIFY(socket.waitForDisconnected()); - - // check if we receive only one of the two pending connections - KLocalSocket socket2; - socket.connectToPath(QLatin1String(asocket)); - socket2.connectToPath(QLatin1String(asocket)); - QTest::qWait(100); - - QVERIFY(server.hasPendingConnections()); - delete server.nextPendingConnection(); - QVERIFY(!server.hasPendingConnections()); - QVERIFY(!server.nextPendingConnection()); -} - -void tst_KLocalSocketServer::abstractUnixSocket_data() -{ -#ifndef Q_OS_LINUX - QSKIP("Abstract UNIX sockets are specific for Linux"); -#endif - QTest::addColumn("path"); - QTest::addColumn("success"); - - QTest::newRow("null") << QString() << false; - QTest::newRow("empty") << "" << false; -#if 0 - // apparently, we are allowed to put sockets there, even if we don't have permission to - QTest::newRow("a-dir") << "/tmp/" << false; - QTest::newRow("not-a-dir") << afile + QLatin1String("/foo") << false; - QTest::newRow("not-permitted") << "/root/foo" << false; -#endif - QTest::newRow("valid") << asocket << true; -} - -void tst_KLocalSocketServer::abstractUnixSocket() -{ - QFETCH(QString, path); - QFETCH(bool, success); - - if (success) { - QVERIFY(!QFile::exists(path)); - } - - KLocalSocketServer server; - QCOMPARE(server.listen(path, KLocalSocket::AbstractUnixSocket), success); - - if (success) { - // the socket must not exist in the filesystem - QVERIFY(!QFile::exists(path)); - - // now try to connect to it - KLocalSocket socket; - socket.connectToPath(path, KLocalSocket::AbstractUnixSocket); - QVERIFY(socket.waitForConnected(100)); - QVERIFY(server.waitForNewConnection(100)); - QVERIFY(server.hasPendingConnections()); - - // the socket must still not exist in the filesystem - QVERIFY(!QFile::exists(path)); - - // verify that they can exchange data too: - KLocalSocket *socket2 = server.nextPendingConnection(); - QByteArray data("Hello"); - socket2->write(data); - QVERIFY(socket2->bytesToWrite() == 0 || socket2->waitForBytesWritten(100)); - QVERIFY(socket.waitForReadyRead(100)); - QCOMPARE(socket.read(data.length()), data); - - socket.write(data); - QVERIFY(socket.bytesToWrite() == 0 || socket.waitForBytesWritten(100)); - QVERIFY(socket2->waitForReadyRead(100)); - QCOMPARE(socket2->read(data.length()), data); - - delete socket2; - QVERIFY(socket.waitForDisconnected(100)); - } -} - -QTEST_MAIN(tst_KLocalSocketServer) - -#include "klocalsocketservertest.moc" diff --git a/autotests/klocalsocketservertest.h b/autotests/klocalsocketservertest.h deleted file mode 100644 index 285812a4..00000000 --- a/autotests/klocalsocketservertest.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of the KDE libraries - * 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. - */ -#ifndef KLOCALSOCKETSERVERTEST_H -#define KLOCALSOCKETSERVERTEST_H - -#include - -class tst_KLocalSocketServer : public QObject -{ - Q_OBJECT -public: - tst_KLocalSocketServer(); - ~tst_KLocalSocketServer(); - -private Q_SLOTS: - void cleanup(); - - void listen_data(); - void listen(); - - void waitForConnection(); - void newConnection(); - - void accept(); - - void state(); - - void setMaxPendingConnections(); - - void abstractUnixSocket_data(); - void abstractUnixSocket(); -}; - -#endif diff --git a/autotests/klocalsockettest.cpp b/autotests/klocalsockettest.cpp deleted file mode 100644 index 5ffe6303..00000000 --- a/autotests/klocalsockettest.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/* - * This file is part of the KDE libraries - * 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 "klocalsockettest.h" - -#include - -#include -#include -#include -#include "klocalsocket.h" - -static const char socketpath[] = "/tmp/testsocket"; - -tst_KLocalSocket::tst_KLocalSocket() -{ - server = nullptr; - QFile::remove(QFile::decodeName(socketpath)); -} - -tst_KLocalSocket::~tst_KLocalSocket() -{ - delete server; - QFile::remove(QFile::decodeName(socketpath)); -} - -#include - -class TimedTest: public QThread -{ - Q_OBJECT -public: - KLocalSocket *socket; - TimedTest(KLocalSocket *s) - : socket(s) - { } - ~TimedTest() - { - wait(1000); - } - - void run() override { - QThread::usleep(100000); - socket->write("Hello, World!", 13); - socket->waitForBytesWritten(); - QThread::usleep(100000); - socket->close(); - delete socket; - } -}; - -void tst_KLocalSocket::initTestCase() -{ - server = new KLocalSocketServer(this); - QVERIFY(server->listen(socketpath)); -} - -void tst_KLocalSocket::connection_data() -{ - QTest::addColumn("path"); - - QTest::newRow("null-path") << QString(); - QTest::newRow("empty-path") << ""; - QTest::newRow("directory") << "/tmp"; - QTest::newRow("directory2") << "/tmp/"; - QTest::newRow("non-existing") << "/tmp/nonexistingsocket"; - QTest::newRow("real") << socketpath; -} - -void tst_KLocalSocket::connection() -{ - QFETCH(QString, path); - KLocalSocket socket; - socket.connectToPath(path); - - bool shouldSucceed = path == socketpath; - QCOMPARE(socket.waitForConnected(1000), shouldSucceed); - if (shouldSucceed) { - QVERIFY(server->waitForNewConnection()); - delete server->nextPendingConnection(); - } else { - qDebug() << socket.errorString(); - } -} - -void tst_KLocalSocket::waitFor() -{ - KLocalSocket socket; - socket.connectToPath(socketpath); - QVERIFY(socket.waitForConnected(1000)); - QVERIFY(server->waitForNewConnection()); - - // now accept: - KLocalSocket *socket2 = server->nextPendingConnection(); - - // start thread: - TimedTest thr(socket2); - socket2->setParent(nullptr); - socket2->moveToThread(&thr); - thr.start(); - - QVERIFY(socket.waitForReadyRead(500)); - QByteArray data = socket.read(512); - - QVERIFY(socket.waitForDisconnected(500)); -} - -void tst_KLocalSocket::reading() -{ - static const char data1[] = "Hello ", - data2[] = "World"; - KLocalSocket socket; - socket.connectToPath(socketpath); - QVERIFY(socket.waitForConnected(1000)); - QVERIFY(server->waitForNewConnection()); - - // now accept and write something: - KLocalSocket *socket2 = server->nextPendingConnection(); - socket2->write(data1, sizeof data1 - 1); - QVERIFY(socket2->bytesToWrite() == 0 || socket2->waitForBytesWritten(200)); - - QVERIFY(socket.waitForReadyRead(200)); - QByteArray read = socket.read(sizeof data1 - 1); - QCOMPARE(read.length(), int(sizeof data1) - 1); - QCOMPARE(read.constData(), data1); - - // write data2 - socket2->write(data2, sizeof data2 - 1); - QVERIFY(socket2->bytesToWrite() == 0 || socket2->waitForBytesWritten(200)); - QVERIFY(socket.waitForReadyRead(200)); - read = socket.read(sizeof data2 - 1); - QCOMPARE(read.length(), int(sizeof data2) - 1); - QCOMPARE(read.constData(), data2); - - delete socket2; -} - -void tst_KLocalSocket::writing() -{ - static const char data1[] = "Hello ", - data2[] = "World"; - KLocalSocket socket; - socket.connectToPath(socketpath); - QVERIFY(socket.waitForConnected(1000)); - QVERIFY(server->waitForNewConnection()); - - // now accept and write something: - KLocalSocket *socket2 = server->nextPendingConnection(); - - QCOMPARE(socket.write(data1, sizeof data1 - 1), Q_INT64_C(sizeof data1 - 1)); - QVERIFY(socket.bytesToWrite() == 0 || socket.waitForBytesWritten(100)); - QVERIFY(socket2->waitForReadyRead()); - - QByteArray read = socket2->read(sizeof data1 - 1); - QCOMPARE(read.length(), int(sizeof data1) - 1); - QCOMPARE(read.constData(), data1); - - // write data2 - QCOMPARE(socket.write(data2, sizeof data2 - 1), Q_INT64_C(sizeof data2 - 1)); - QVERIFY(socket.bytesToWrite() == 0 || socket.waitForBytesWritten(100)); - QVERIFY(socket2->waitForReadyRead()); - read = socket2->read(sizeof data2 - 1); - QCOMPARE(read.length(), int(sizeof data2) - 1); - QCOMPARE(read.constData(), data2); - - delete socket2; -} - -void tst_KLocalSocket::state() -{ - KLocalSocket socket; - - // sanity check: - QCOMPARE(int(socket.localSocketType()), int(KLocalSocket::UnknownLocalSocketType)); - QVERIFY(socket.localPath().isEmpty()); - QVERIFY(socket.peerPath().isEmpty()); - QCOMPARE(int(socket.state()), int(QAbstractSocket::UnconnectedState)); - - // now connect and accept - socket.connectToPath(socketpath); - QVERIFY(socket.waitForConnected(1000)); - QVERIFY(server->waitForNewConnection()); - KLocalSocket *socket2 = server->nextPendingConnection(); - - QCOMPARE(socket.peerPath(), QString(socketpath)); - QCOMPARE(socket2->localPath(), QString(socketpath)); - QCOMPARE(int(socket.state()), int(QAbstractSocket::ConnectedState)); - QCOMPARE(int(socket2->state()), int(QAbstractSocket::ConnectedState)); - QCOMPARE(int(socket.localSocketType()), int(KLocalSocket::UnixSocket)); - QCOMPARE(int(socket2->localSocketType()), int(KLocalSocket::UnixSocket)); - - // now close one of the sockets: - socket.close(); - - // it must have reset its state: - QCOMPARE(int(socket.localSocketType()), int(KLocalSocket::UnknownLocalSocketType)); - QVERIFY(socket.peerPath().isEmpty()); - QCOMPARE(int(socket.state()), int(QAbstractSocket::UnconnectedState)); - - // but the other one mustn't have yet: - QCOMPARE(int(socket2->state()), int(QAbstractSocket::ConnectedState)); - QVERIFY(!socket2->localPath().isEmpty()); - QCOMPARE(int(socket2->localSocketType()), int(KLocalSocket::UnixSocket)); - - // wait for disconnected: - QVERIFY(socket2->waitForDisconnected()); - - // now it must have: - QCOMPARE(int(socket2->state()), int(QAbstractSocket::UnconnectedState)); - QVERIFY(socket2->localPath().isEmpty()); - QCOMPARE(int(socket2->localSocketType()), int(KLocalSocket::UnknownLocalSocketType)); - - delete socket2; -} - -void tst_KLocalSocket::connected() -{ - KLocalSocket socket; - socket.connectToPath(socketpath); - QEXPECT_FAIL("", "Will fix later", Continue); - QVERIFY(!socket.isOpen()); - - QSignalSpy spy(&socket, SIGNAL(connected())); - QTest::qWait(100); - - QEXPECT_FAIL("", "Will fix later", Continue); - QCOMPARE(spy.count(), 1); -} - -QTEST_MAIN(tst_KLocalSocket) - -#include "klocalsockettest.moc" diff --git a/autotests/klocalsockettest.h b/autotests/klocalsockettest.h deleted file mode 100644 index 00668d6d..00000000 --- a/autotests/klocalsockettest.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * This file is part of the KDE libraries - * 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. - */ -#ifndef KLOCALSOCKETTEST_H -#define KLOCALSOCKETTEST_H - -#include - -class KLocalSocketServer; -class tst_KLocalSocket : public QObject -{ - Q_OBJECT -public: - KLocalSocketServer *server; - tst_KLocalSocket(); - ~tst_KLocalSocket(); - -private Q_SLOTS: - void initTestCase(); - void connection_data(); - void connection(); - void waitFor(); - - void reading(); - void writing(); - - void state(); - - void connected(); -}; - -#endif diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 93cda26f..6d780614 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,335 +1,332 @@ project(KIOCore) include (ConfigureChecks.cmake) configure_file(config-kiocore.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kiocore.h ) configure_file(config-kmountpoint.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kmountpoint.h) # KSSL_HAVE_SSL only used in kssl/ksslsettings.cpp, but currently ifdefed out #find_package(OpenSSL) #set_package_properties(OpenSSL PROPERTIES DESCRIPTION "Support for secure network communications (SSL and TLS)" # URL "http://openssl.org" # TYPE RECOMMENDED # PURPOSE "KDE uses OpenSSL for the bulk of secure communications, including secure web browsing via HTTPS" # ) #if(OPENSSL_FOUND) # set(KSSL_HAVE_SSL 1) # include_directories(${OPENSSL_INCLUDE_DIR}) #endif() set(kiocore_SRCS idleslave.cpp - klocalsocket.cpp connectionbackend.cpp connection.cpp connectionserver.cpp krecentdocument.cpp kfileitemlistproperties.cpp tcpslavebase.cpp directorysizejob.cpp forwardingslavebase.cpp chmodjob.cpp kdiskfreespaceinfo.cpp usernotificationhandler.cpp ksambasharedata.cpp ksambashare.cpp knfsshare.cpp kfileitem.cpp davjob.cpp deletejob.cpp copyjob.cpp filejob.cpp mkdirjob.cpp mkpathjob.cpp kpasswdserverloop.cpp kpasswdserverclient.cpp kremoteencoding.cpp sessiondata.cpp slavebase.cpp dataslave.cpp dataprotocol.cpp desktopexecparser.cpp emptytrashjob.cpp authinfo.cpp slaveinterface.cpp slave.cpp job_error.cpp job.cpp filecopyjob.cpp listjob.cpp mimetypejob.cpp multigetjob.cpp restorejob.cpp simplejob.cpp specialjob.cpp statjob.cpp storedtransferjob.cpp transferjob.cpp filesystemfreespacejob.cpp scheduler.cpp slaveconfig.cpp kprotocolmanager.cpp hostinfo.cpp kdirnotify.cpp kurlauthorized.cpp kacl.cpp udsentry.cpp global.cpp metadata.cpp kprotocolinfo.cpp kprotocolinfofactory.cpp jobtracker.cpp jobuidelegateextension.cpp jobuidelegatefactory.cpp kmountpoint.cpp kcoredirlister.cpp faviconscache.cpp ksslcertificatemanager.cpp ksslerroruidata.cpp ktcpsocket.cpp kssl/ksslsettings.cpp kioglobal_p.cpp batchrenamejob.cpp ) ecm_qt_declare_logging_category(kiocore_SRCS HEADER kiocoredebug.h IDENTIFIER KIO_CORE CATEGORY_NAME kf5.kio.core DESCRIPTION "KIOCore (KIO)" EXPORT KIO ) ecm_qt_export_logging_category( IDENTIFIER KIO_COPYJOB_DEBUG CATEGORY_NAME kf5.kio.core.copyjob DEFAULT_SEVERITY Warning DESCRIPTION "KIO::CopyJob (KIO)" EXPORT KIO ) ecm_qt_export_logging_category( IDENTIFIER KIO_CORE_DIRLISTER CATEGORY_NAME kf5.kio.core.dirlister DEFAULT_SEVERITY Warning DESCRIPTION "KCoreDirLister (KIO)" EXPORT KIO ) ecm_qt_export_logging_category( IDENTIFIER KIO_CORE_SAMBASHARE CATEGORY_NAME kf5.kio.core.sambashare DEFAULT_SEVERITY Warning DESCRIPTION "sambashare (KIO)" EXPORT KIO ) if (UNIX) set(kiocore_SRCS ${kiocore_SRCS} - klocalsocket_unix.cpp kioglobal_p_unix.cpp ) endif() if (WIN32) set(kiocore_SRCS ${kiocore_SRCS} - klocalsocket_win.cpp kioglobal_p_win.cpp ) endif() qt5_add_dbus_interface(kiocore_SRCS org.kde.KSlaveLauncher.xml klauncher_interface) qt5_add_dbus_interface(kiocore_SRCS org.kde.KIOFuse.VFS.xml kiofuse_interface) set_source_files_properties(org.kde.KPasswdServer.xml PROPERTIES INCLUDE authinfo.h ) qt5_add_dbus_interface(kiocore_SRCS org.kde.KPasswdServer.xml kpasswdserver_interface) install(FILES org.kde.KDirNotify.xml DESTINATION ${KDE_INSTALL_DBUSINTERFACEDIR} RENAME kf5_org.kde.KDirNotify.xml) install(FILES org.kde.KPasswdServer.xml DESTINATION ${KDE_INSTALL_DBUSINTERFACEDIR} RENAME kf5_org.kde.KPasswdServer.xml) install(FILES org.kde.KSlaveLauncher.xml DESTINATION ${KDE_INSTALL_DBUSINTERFACEDIR} RENAME kf5_org.kde.KSlaveLauncher.xml) add_library(KF5KIOCore ${kiocore_SRCS}) add_library(KF5::KIOCore ALIAS KF5KIOCore) ecm_generate_export_header(KF5KIOCore BASE_NAME KIOCore GROUP_BASE_NAME KF VERSION ${KF5_VERSION} DEPRECATED_BASE_VERSION 0 DEPRECATION_VERSIONS 3.0 3.1 3.4 4.0 4.3 4.5 4.6 5.0 5.2 5.8 5.24 5.45 5.48 5.63 5.61 5.64 5.65 5.66 5.69 ) # TODO: add support for EXCLUDE_DEPRECATED_BEFORE_AND_AT to all KIO libs # needs fixing of undeprecated API being still implemented using own deprecated API target_include_directories(KF5KIOCore PUBLIC "$" # kio_version.h "$" ) target_include_directories(KF5KIOCore INTERFACE "$") target_link_libraries(KF5KIOCore PUBLIC KF5::CoreAddons # KJob KF5::Service Qt5::Network Qt5::Concurrent # QtConcurrentRun in hostinfo.cpp Qt5::DBus PRIVATE Qt5::Xml # davjob.cpp uses QDom KF5::I18n KF5::Crash KF5::DBusAddons # KDEInitInterface ) if (UNIX) target_link_libraries(KF5KIOCore PRIVATE KF5::AuthCore) #SlaveBase uses KAuth::Action endif() if(ACL_FOUND) target_link_libraries(KF5KIOCore PRIVATE ${ACL_LIBS}) endif() set_target_properties(KF5KIOCore PROPERTIES VERSION ${KIO_VERSION_STRING} SOVERSION ${KIO_SOVERSION} EXPORT_NAME KIOCore ) # this should be done by cmake, see bug 371721 if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND Qt5Core_VERSION VERSION_GREATER 5.8.0) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/moc_predefs.h COMMAND "${CMAKE_CXX_COMPILER}" "-dM" "-E" "-c" "${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp" > ${CMAKE_CURRENT_BINARY_DIR}/moc_predefs.h ) set_property(TARGET KF5KIOCore APPEND PROPERTY AUTOMOC_MOC_OPTIONS --include ${CMAKE_CURRENT_BINARY_DIR}/moc_predefs.h) set_property(TARGET KF5KIOCore APPEND PROPERTY AUTOGEN_TARGET_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/moc_predefs.h) endif() # Headers prefixed with KIO/ ecm_generate_headers(KIOCore_CamelCase_HEADERS HEADER_NAMES IdleSlave ConnectionServer TCPSlaveBase DirectorySizeJob ForwardingSlaveBase Job # ### should forward to job_base.h, not job.h... JobTracker Global ChmodJob DeleteJob CopyJob EmptyTrashJob FileJob MkdirJob MkpathJob SlaveBase SlaveConfig HostInfo MetaData UDSEntry JobUiDelegateExtension JobUiDelegateFactory SlaveInterface Slave FileCopyJob ListJob MimetypeJob MultiGetJob RestoreJob SimpleJob SpecialJob StatJob StoredTransferJob TransferJob Scheduler AuthInfo DavJob DesktopExecParser FileSystemFreeSpaceJob BatchRenameJob PREFIX KIO REQUIRED_HEADERS KIO_namespaced_HEADERS ) # Create local forwarding header for kio/job_base.h set(REGULAR_HEADER_NAME ${CMAKE_CURRENT_BINARY_DIR}/kio/job_base.h) if (NOT EXISTS ${REGULAR_HEADER_NAME}) file(WRITE ${REGULAR_HEADER_NAME} "#include \"${CMAKE_CURRENT_SOURCE_DIR}/job_base.h\"\n") endif() install(TARGETS KF5KIOCore EXPORT KF5KIOTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) list(APPEND KIO_namespaced_HEADERS http_slave_defaults.h ioslave_defaults.h job_base.h jobclasses.h ) install(FILES ${KIO_namespaced_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KIOCore/kio COMPONENT Devel ) # Headers not prefixed with KIO/ ecm_generate_headers(KIOCore_HEADERS HEADER_NAMES KACL KUrlAuthorized KCoreDirLister KRemoteEncoding KDirNotify KDiskFreeSpaceInfo KFileItem KFileItemListProperties KMountPoint KNFSShare KSambaShare KSambaShareData KPasswdServerClient KProtocolInfo KProtocolManager KRecentDocument KSslCertificateManager KSslErrorUiData KTcpSocket REQUIRED_HEADERS KIOCore_HEADERS ) ecm_generate_headers(KIOCore_HEADERS HEADER_NAMES KSSLSettings RELATIVE kssl REQUIRED_HEADERS KIOCore_HEADERS ) install(FILES ${KIOCore_CamelCase_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KIOCore/KIO COMPONENT Devel) install(FILES ksslcertificatemanager_p.h ${KIOCore_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/kiocore_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KIOCore COMPONENT Devel) install(FILES accept-languages.codes DESTINATION ${KDE_INSTALL_CONFDIR}) # make available to ecm_add_qch in parent folder set(KIOCore_QCH_SOURCES ${KIOCore_HEADERS} ${KIO_namespaced_HEADERS} PARENT_SCOPE) include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME KIOCore LIB_NAME KF5KIOCore DEPS "KCoreAddons KService" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KIOCore) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/core/connection.cpp b/src/core/connection.cpp index c27f5c57..563d8dff 100644 --- a/src/core/connection.cpp +++ b/src/core/connection.cpp @@ -1,239 +1,237 @@ /* 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 using namespace KIO; void ConnectionPrivate::dequeue() { if (!backend || suspended) { return; } for (const Task &task : qAsConst(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() && readMode == Connection::ReadMode::EventDriven) { QMetaObject::invokeMethod(q, "dequeue", Qt::QueuedConnection); } incomingTasks.append(task); } void ConnectionPrivate::disconnected() { q->close(); if (readMode == Connection::ReadMode::EventDriven) { 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 if (d->readMode == Connection::ReadMode::EventDriven) { 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)); + d->setBackend(new ConnectionBackend(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(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.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() && d->readMode == Connection::ReadMode::EventDriven) { QMetaObject::invokeMethod(this, "dequeue", Qt::QueuedConnection); } return data.size(); } void Connection::setReadMode(ReadMode readMode) { d->readMode = readMode; } #include "moc_connection_p.cpp" diff --git a/src/core/connectionbackend.cpp b/src/core/connectionbackend.cpp index 1da195a8..e91df449 100644 --- a/src/core/connectionbackend.cpp +++ b/src/core/connectionbackend.cpp @@ -1,339 +1,297 @@ /* 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 "connectionbackend_p.h" #include -#include #include -#include "klocalsocket.h" #include #include #include #include #include #include +#include +#include #include "kiocoredebug.h" using namespace KIO; -ConnectionBackend::ConnectionBackend(Mode m, QObject *parent) +ConnectionBackend::ConnectionBackend(QObject *parent) : QObject(parent), state(Idle), socket(nullptr), len(-1), cmd(0), - signalEmitted(false), - mode(m) + signalEmitted(false) { localServer = nullptr; } ConnectionBackend::~ConnectionBackend() { - if (mode == LocalSocketMode && localServer && - localServer->localSocketType() == KLocalSocket::UnixSocket) { - QFile::remove(localServer->localPath()); - } } void ConnectionBackend::setSuspended(bool enable) { if (state != Connected) { return; } Q_ASSERT(socket); Q_ASSERT(!localServer); // !tcpServer as well if (enable) { //qCDebug(KIO_CORE) << socket << "suspending"; socket->setReadBufferSize(1); } else { //qCDebug(KIO_CORE) << socket << "resuming"; // Calling setReadBufferSize from a readyRead slot leads to a bug in Qt, fixed in 13c246ee119 socket->setReadBufferSize(StandardBufferSize); if (socket->bytesAvailable() >= HeaderSize) { // there are bytes available QMetaObject::invokeMethod(this, "socketReadyRead", Qt::QueuedConnection); } // We read all bytes here, but we don't use readAll() because we need // to read at least one byte (even if there isn't any) so that the // socket notifier is reenabled QByteArray data = socket->read(socket->bytesAvailable() + 1); for (int i = data.size(); --i >= 0;) { socket->ungetChar(data[i]); } // Workaround Qt5 bug, readyRead isn't always emitted here... QMetaObject::invokeMethod(this, "socketReadyRead", Qt::QueuedConnection); } } bool ConnectionBackend::connectToRemote(const QUrl &url) { Q_ASSERT(state == Idle); Q_ASSERT(!socket); Q_ASSERT(!localServer); // !tcpServer as well - if (mode == LocalSocketMode) { - KLocalSocket *sock = new KLocalSocket(this); - QString path = url.path(); -#if 0 - // TODO: Activate once abstract socket support is implemented in Qt. - KLocalSocket::LocalSocketType type = KLocalSocket::UnixSocket; - - if (url.queryItem(QLatin1String("abstract")) == QLatin1Char('1')) { - type = KLocalSocket::AbstractUnixSocket; - } -#endif - sock->connectToPath(path); - socket = sock; - } else { - socket = new QTcpSocket(this); - socket->connectToHost(url.host(), url.port()); + QLocalSocket *sock = new QLocalSocket(this); + QString path = url.path(); + sock->connectToServer(path); + socket = sock; - if (!socket->waitForConnected(1000)) { - state = Idle; - qCDebug(KIO_CORE) << "could not connect to" << url; - return false; - } - } connect(socket, &QIODevice::readyRead, this, &ConnectionBackend::socketReadyRead); - connect(socket, &QAbstractSocket::disconnected, this, &ConnectionBackend::socketDisconnected); + connect(socket, &QLocalSocket::disconnected, this, &ConnectionBackend::socketDisconnected); state = Connected; return true; } void ConnectionBackend::socketDisconnected() { state = Idle; emit disconnected(); } bool ConnectionBackend::listenForRemote() { Q_ASSERT(state == Idle); Q_ASSERT(!socket); Q_ASSERT(!localServer); // !tcpServer as well - if (mode == LocalSocketMode) { - const QString prefix = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation); - static QBasicAtomicInt s_socketCounter = Q_BASIC_ATOMIC_INITIALIZER(1); - QString appName = QCoreApplication::instance()->applicationName(); - appName.replace(QLatin1Char('/'), QLatin1Char('_')); // #357499 - QTemporaryFile socketfile(prefix + QLatin1Char('/') + appName + QStringLiteral("XXXXXX.%1.slave-socket").arg(s_socketCounter.fetchAndAddAcquire(1))); - if (!socketfile.open()) { - errorString = i18n("Unable to create io-slave: %1", QString::fromUtf8(strerror(errno))); - return false; - } - - QString sockname = socketfile.fileName(); - address.clear(); - address.setScheme(QStringLiteral("local")); - address.setPath(sockname); - socketfile.setAutoRemove(false); - socketfile.remove(); // can't bind if there is such a file - - localServer = new KLocalSocketServer(this); - if (!localServer->listen(sockname, KLocalSocket::UnixSocket)) { - errorString = localServer->errorString(); - delete localServer; - localServer = nullptr; - return false; - } - - connect(localServer, &KLocalSocketServer::newConnection, this, &ConnectionBackend::newConnection); - } else { - tcpServer = new QTcpServer(this); - tcpServer->listen(QHostAddress::LocalHost); - if (!tcpServer->isListening()) { - errorString = tcpServer->errorString(); - delete tcpServer; - tcpServer = nullptr; - return false; - } + const QString prefix = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation); + static QBasicAtomicInt s_socketCounter = Q_BASIC_ATOMIC_INITIALIZER(1); + QString appName = QCoreApplication::instance()->applicationName(); + appName.replace(QLatin1Char('/'), QLatin1Char('_')); // #357499 + QTemporaryFile socketfile(prefix + QLatin1Char('/') + appName + QStringLiteral("XXXXXX.%1.slave-socket").arg(s_socketCounter.fetchAndAddAcquire(1))); + if (!socketfile.open()) { + errorString = i18n("Unable to create io-slave: %1", QString::fromUtf8(strerror(errno))); + return false; + } - address = QUrl(QLatin1String("tcp://127.0.0.1:") + QString::number(tcpServer->serverPort())); - connect(tcpServer, &QTcpServer::newConnection, this, &ConnectionBackend::newConnection); + QString sockname = socketfile.fileName(); + address.clear(); + address.setScheme(QStringLiteral("local")); + address.setPath(sockname); + socketfile.setAutoRemove(false); + socketfile.remove(); // can't bind if there is such a file + + localServer = new QLocalServer(this); + if (!localServer->listen(sockname)) { + errorString = localServer->errorString(); + delete localServer; + localServer = nullptr; + return false; } + connect(localServer, &QLocalServer::newConnection, this, &ConnectionBackend::newConnection); + state = Listening; return true; } bool ConnectionBackend::waitForIncomingTask(int ms) { Q_ASSERT(state == Connected); Q_ASSERT(socket); - if (socket->state() != QAbstractSocket::ConnectedState) { + if (socket->state() != QLocalSocket::LocalSocketState::ConnectedState) { state = Idle; return false; // socket has probably closed, what do we do? } signalEmitted = false; if (socket->bytesAvailable()) { socketReadyRead(); } if (signalEmitted) { return true; // there was enough data in the socket } // not enough data in the socket, so wait for more QElapsedTimer timer; timer.start(); - while (socket->state() == QAbstractSocket::ConnectedState && !signalEmitted && + while (socket->state() == QLocalSocket::LocalSocketState::ConnectedState && !signalEmitted && (ms == -1 || timer.elapsed() < ms)) if (!socket->waitForReadyRead(ms == -1 ? -1 : ms - timer.elapsed())) { break; } if (signalEmitted) { return true; } - if (socket->state() != QAbstractSocket::ConnectedState) { + if (socket->state() != QLocalSocket::LocalSocketState::ConnectedState) { state = Idle; } return false; } bool ConnectionBackend::sendCommand(int cmd, const QByteArray &data) const { Q_ASSERT(state == Connected); Q_ASSERT(socket); char buffer[HeaderSize + 2]; sprintf(buffer, "%6x_%2x_", data.size(), cmd); socket->write(buffer, HeaderSize); socket->write(data); //qCDebug(KIO_CORE) << this << "Sending command" << hex << cmd << "of" // << data.size() << "bytes (" << socket->bytesToWrite() // << "bytes left to write )"; // blocking mode: - while (socket->bytesToWrite() > 0 && socket->state() == QAbstractSocket::ConnectedState) { + while (socket->bytesToWrite() > 0 && socket->state() == QLocalSocket::LocalSocketState::ConnectedState) { socket->waitForBytesWritten(-1); } - return socket->state() == QAbstractSocket::ConnectedState; + return socket->state() == QLocalSocket::LocalSocketState::ConnectedState; } ConnectionBackend *ConnectionBackend::nextPendingConnection() { Q_ASSERT(state == Listening); - Q_ASSERT(localServer || tcpServer); + Q_ASSERT(localServer); Q_ASSERT(!socket); //qCDebug(KIO_CORE) << "Got a new connection"; - QTcpSocket *newSocket; - if (mode == LocalSocketMode) { - newSocket = localServer->nextPendingConnection(); - } else { - newSocket = tcpServer->nextPendingConnection(); - } + QLocalSocket *newSocket = localServer->nextPendingConnection(); if (!newSocket) { return nullptr; // there was no connection... } - ConnectionBackend *result = new ConnectionBackend(Mode(mode)); + ConnectionBackend *result = new ConnectionBackend(); result->state = Connected; result->socket = newSocket; newSocket->setParent(result); connect(newSocket, &QIODevice::readyRead, result, &ConnectionBackend::socketReadyRead); - connect(newSocket, &QAbstractSocket::disconnected, result, &ConnectionBackend::socketDisconnected); + connect(newSocket, &QLocalSocket::disconnected, result, &ConnectionBackend::socketDisconnected); return result; } void ConnectionBackend::socketReadyRead() { bool shouldReadAnother; do { if (!socket) // might happen if the invokeMethods were delivered after we disconnected { return; } //qCDebug(KIO_CORE) << this << "Got" << socket->bytesAvailable() << "bytes"; if (len == -1) { // We have to read the header char buffer[HeaderSize]; if (socket->bytesAvailable() < HeaderSize) { return; // wait for more data } socket->read(buffer, sizeof buffer); buffer[6] = 0; buffer[9] = 0; char *p = buffer; while (*p == ' ') { p++; } len = strtol(p, nullptr, 16); p = buffer + 7; while (*p == ' ') { p++; } cmd = strtol(p, nullptr, 16); //qCDebug(KIO_CORE) << this << "Beginning of command" << hex << cmd << "of size" << len; } QPointer that = this; //qCDebug(KIO_CORE) << socket << "Want to read" << len << "bytes"; if (socket->bytesAvailable() >= len) { Task task; task.cmd = cmd; if (len) { task.data = socket->read(len); } len = -1; signalEmitted = true; emit commandReceived(task); } else if (len > StandardBufferSize) { qCDebug(KIO_CORE) << socket << "Jumbo packet of" << len << "bytes"; // Calling setReadBufferSize from a readyRead slot leads to a bug in Qt, fixed in 13c246ee119 socket->setReadBufferSize(len + 1); } // If we're dead, better don't try anything. if (that.isNull()) { return; } // Do we have enough for an another read? if (len == -1) { shouldReadAnother = socket->bytesAvailable() >= HeaderSize; } else { shouldReadAnother = socket->bytesAvailable() >= len; } } while (shouldReadAnother); } diff --git a/src/core/connectionbackend_p.h b/src/core/connectionbackend_p.h index 0b862c9f..80ed7154 100644 --- a/src/core/connectionbackend_p.h +++ b/src/core/connectionbackend_p.h @@ -1,85 +1,83 @@ /* This file is part of the KDE libraries 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. */ #ifndef KIO_CONNECTIONBACKEND_P_H #define KIO_CONNECTIONBACKEND_P_H #include #include -class KLocalSocketServer; + +class QLocalServer; +class QLocalSocket; + class QTcpServer; -class QTcpSocket; namespace KIO { struct Task { int cmd; QByteArray data; }; class ConnectionBackend: public QObject { Q_OBJECT public: enum { Idle, Listening, Connected } state; - enum Mode { LocalSocketMode, TcpSocketMode }; QUrl address; QString errorString; private: - QTcpSocket *socket; - union { - KLocalSocketServer *localServer; - QTcpServer *tcpServer; - }; + QLocalSocket *socket; + QLocalServer *localServer; long len; int cmd; int port; bool signalEmitted; quint8 mode; static const int HeaderSize = 10; static const int StandardBufferSize = 32 * 1024; Q_SIGNALS: void disconnected(); void commandReceived(const Task &task); void newConnection(); public: - explicit ConnectionBackend(Mode m, QObject *parent = nullptr); + explicit ConnectionBackend(QObject *parent = nullptr); ~ConnectionBackend(); void setSuspended(bool enable); bool connectToRemote(const QUrl &url); bool listenForRemote(); bool waitForIncomingTask(int ms); bool sendCommand(int command, const QByteArray &data) const; ConnectionBackend *nextPendingConnection(); public Q_SLOTS: void socketReadyRead(); void socketDisconnected(); }; } #endif diff --git a/src/core/connectionserver.cpp b/src/core/connectionserver.cpp index a7fe176f..a6ef2552 100644 --- a/src/core/connectionserver.cpp +++ b/src/core/connectionserver.cpp @@ -1,112 +1,108 @@ /* 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. */ #include "connectionserver.h" #include "connection_p.h" #include "connectionbackend_p.h" using namespace KIO; class KIO::ConnectionServerPrivate { public: inline ConnectionServerPrivate() : backend(nullptr) { } ConnectionServer *q; ConnectionBackend *backend; }; ConnectionServer::ConnectionServer(QObject *parent) : QObject(parent), d(new ConnectionServerPrivate) { d->q = this; } ConnectionServer::~ConnectionServer() { delete d; } void ConnectionServer::listenForRemote() { -#ifdef Q_OS_WIN - d->backend = new ConnectionBackend(ConnectionBackend::TcpSocketMode, this); -#else - d->backend = new ConnectionBackend(ConnectionBackend::LocalSocketMode, this); -#endif + d->backend = new ConnectionBackend(this); if (!d->backend->listenForRemote()) { delete d->backend; d->backend = nullptr; return; } connect(d->backend, &ConnectionBackend::newConnection, this, &ConnectionServer::newConnection); //qDebug() << "Listening on" << d->backend->address; } QUrl ConnectionServer::address() const { if (d->backend) { return d->backend->address; } return QUrl(); } bool ConnectionServer::isListening() const { return d->backend && d->backend->state == ConnectionBackend::Listening; } void ConnectionServer::close() { delete d->backend; d->backend = nullptr; } Connection *ConnectionServer::nextPendingConnection() { if (!isListening()) { return nullptr; } ConnectionBackend *newBackend = d->backend->nextPendingConnection(); if (!newBackend) { return nullptr; // no new backend... } Connection *result = new Connection; result->d->setBackend(newBackend); newBackend->setParent(result); return result; } void ConnectionServer::setNextPendingConnection(Connection *conn) { ConnectionBackend *newBackend = d->backend->nextPendingConnection(); Q_ASSERT(newBackend); conn->d->setBackend(newBackend); newBackend->setParent(conn); conn->d->dequeue(); } diff --git a/src/core/klocalsocket.cpp b/src/core/klocalsocket.cpp deleted file mode 100644 index 16cb7014..00000000 --- a/src/core/klocalsocket.cpp +++ /dev/null @@ -1,228 +0,0 @@ -/* - * This file is part of the KDE libraries - * 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 "klocalsocket.h" -#include "klocalsocket_p.h" -#include "kiocoredebug.h" - -#include - -//#define LocalSocket (QAbstractSocket::SocketType(int(QAbstractSocket::UdpSocket) + 1)) - -void KLocalSocketPrivate::emitError(QAbstractSocket::SocketError error, const QString &errorString) -{ - q->setSocketState(QAbstractSocket::UnconnectedState); - q->setSocketError(error); - q->setErrorString(errorString); - emit q->stateChanged(QAbstractSocket::UnconnectedState); - emit q->error(error); -} - -void KLocalSocketServerPrivate::emitError(QAbstractSocket::SocketError an_error, const QString &an_errorString) -{ - error = an_error; - errorString = an_errorString; -} - -KLocalSocket::KLocalSocket(QObject *parent) - : QTcpSocket(parent), d(new KLocalSocketPrivate(this)) -{ -} - -KLocalSocket::~KLocalSocket() -{ - delete d; - // parent's destructor closes the socket -} - -void KLocalSocket::connectToPath(const QString &path, OpenMode mode) -{ - // cheat: - connectToHost(path, UnixSocket, mode); -} - -void KLocalSocket::connectToPath(const QString &path, LocalSocketType type, OpenMode mode) -{ - // cheat: - connectToHost(path, type, mode); -} - -void KLocalSocket::connectToHostImplementation(const QString &path, quint16 type, OpenMode mode) -{ - if (state() == ConnectedState || state() == ConnectingState) { - return; - } - - d->localPath.clear(); - d->peerPath.clear(); - - setSocketState(ConnectingState); - emit stateChanged(ConnectingState); - - d->connectToPath(path, LocalSocketType(type), mode); -} - -void KLocalSocket::disconnectFromHostImplementation() -{ - QTcpSocket::disconnectFromHost(); - - d->peerPath.clear(); - d->localPath.clear(); - d->type = UnknownLocalSocketType; -} - -void KLocalSocket::disconnectFromPath() -{ - // cheat: - disconnectFromHost(); -} - -KLocalSocket::LocalSocketType KLocalSocket::localSocketType() const -{ - return d->type; -} - -QString KLocalSocket::localPath() const -{ - return d->localPath; -} - -QString KLocalSocket::peerPath() const -{ - return d->peerPath; -} - -KLocalSocketServerPrivate::KLocalSocketServerPrivate(KLocalSocketServer *qq) - : q(qq), descriptor(-1), maxPendingConnections(30), - state(QAbstractSocket::UnconnectedState), - error(QAbstractSocket::UnknownSocketError), - type(KLocalSocket::UnknownLocalSocketType), - readNotifier(nullptr) -{ -} - -KLocalSocketServer::KLocalSocketServer(QObject *parent) - : QObject(parent), d(new KLocalSocketServerPrivate(this)) -{ -} - -KLocalSocketServer::~KLocalSocketServer() -{ - close(); - delete d; -} - -bool KLocalSocketServer::isListening() const -{ - return d->state == QAbstractSocket::ListeningState; -} - -bool KLocalSocketServer::listen(const QString &path, KLocalSocket::LocalSocketType type) -{ - if (d->state == QAbstractSocket::ListeningState) { - return false; // already created - } - - if (!d->listen(path, type)) { - // the private set the error code - return false; - } - - d->localPath = path; - return true; -} - -void KLocalSocketServer::close() -{ - d->close(); -} - -void KLocalSocketServer::setMaxPendingConnections(int numConnections) -{ - if (numConnections >= 0) { - d->maxPendingConnections = numConnections; - d->readNotifier->setEnabled(d->pendingConnections.size() < d->maxPendingConnections); - } else { - qCWarning(KIO_CORE, "KLocalSocketServer::setMaxPendingConnections: cannot set to a negative number"); - } -} - -int KLocalSocketServer::maxPendingConnections() const -{ - return d->maxPendingConnections; -} - -KLocalSocket::LocalSocketType KLocalSocketServer::localSocketType() const -{ - return d->type; -} - -QString KLocalSocketServer::localPath() const -{ - return d->localPath; -} - -bool KLocalSocketServer::waitForNewConnection(int msec, bool *timedOut) -{ - if (!isListening()) { - return false; // can't wait if we're not listening - } - - return d->waitForNewConnection(msec, timedOut); -} - -bool KLocalSocketServer::hasPendingConnections() const -{ - return !d->pendingConnections.isEmpty(); -} - -KLocalSocket *KLocalSocketServer::nextPendingConnection() -{ - if (hasPendingConnections()) { - d->readNotifier->setEnabled((d->pendingConnections.size() - 1) < d->maxPendingConnections); - return d->pendingConnections.dequeue(); - } - return nullptr; -} - -void KLocalSocketServer::incomingConnection(int descriptor) -{ - KLocalSocket *socket = new KLocalSocket(this); - KLocalSocketPrivate *socket_d = KLocalSocketPrivate::d(socket); - socket_d->localPath = d->localPath; - socket_d->type = d->type; - - socket->setSocketDescriptor(descriptor, QAbstractSocket::ConnectedState, QIODevice::ReadWrite); - d->pendingConnections.enqueue(socket); - - emit newConnection(); -} - -QAbstractSocket::SocketError KLocalSocketServer::serverError() const -{ - return d->error; -} - -QString KLocalSocketServer::errorString() const -{ - return d->errorString; -} - -#include "moc_klocalsocket.cpp" diff --git a/src/core/klocalsocket.h b/src/core/klocalsocket.h deleted file mode 100644 index 3b624d77..00000000 --- a/src/core/klocalsocket.h +++ /dev/null @@ -1,335 +0,0 @@ -/* - * This file is part of the KDE libraries - * 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. - */ - -#ifndef KLOCALSOCKET_H -#define KLOCALSOCKET_H - -#include "kiocore_export.h" -#include -#include -#include - -class KLocalSocketPrivate; -/** - * @class KLocalSocket - * @brief KLocalSocket allows one to create and use local (Unix) sockets - * - * On some platforms, local sockets are a kind of streaming socket - * that can be used to transmit and receive data just like Internet - * (TCP) streaming sockets. The difference is that they remain local - * to the host running them and cannot be accessed externally. They - * are also very fast and (in theory) consume less resources than - * standard TCP sockets. - * - * KLocalSocket supports two kinds of local socket types (see - * KLocalSocket::LocalSocketType): - * - Unix sockets (UnixSocket): standard Unix sockets whose names are - * file paths and obey filesystem restrictions - * - Abstract Unix sockets (AbstractUnixSocket): similar to Unix - * sockets, but they don't exist as entries in the filesystem and, - * thus, aren't restricted by its permissions - * - * @author Thiago Macieira - * @internal DO NOT USE. Only for KIO. - */ -class KIOCORE_EXPORT KLocalSocket : public QTcpSocket // Only exported for the unittest. Header not installed -{ - Q_OBJECT -public: - /** - * Defines the local socket type. See KLocalSocket for more - * information - */ - enum LocalSocketType { - UnixSocket, ///< Unix sockets - AbstractUnixSocket, ///< Abstract Unix sockets - UnknownLocalSocketType = -1 - }; - - /** - * Creates a KLocalSocket object with @p parent as the parent - * object. - * - * @param parent the parent object - */ - explicit KLocalSocket(QObject *parent = nullptr); - /** - * Destroys the KLocalSocket object and frees up any resources - * associated. If the socket is open, it will be closed. - */ - virtual ~KLocalSocket(); - - /** - * Opens a connection to a listening Unix socket at @p path. Use - * waitForConnection() to find out if the connection succeeded or - * not. - * - * @param path the Unix socket to connect to - * @param mode the mode to use when opening (see QIODevice::OpenMode) - */ - void connectToPath(const QString &path, OpenMode mode = ReadWrite); - /** - * @overload - * Opens a connection to a listening local socket at address @p - * path. Use waitForConnection() to find out if the connection - * succeeded or not. - * - * @param path the local socket address to connect to - * @param type the local socket type to use - * @param mode the mode to use when opening (see QIODevice::OpenMode) - */ - void connectToPath(const QString &path, LocalSocketType type, OpenMode mode = ReadWrite); - /** - * Disconnects the socket from its server. - */ - void disconnectFromPath(); - - /** - * Returns the socket type for this socket, when - * connected. Returns UnknownLocalSocketType if not - * connected. - */ - LocalSocketType localSocketType() const; - - /** - * Returns the local address of this socket, when - * connected. Returns QString() if not connected. - * - * Most of the time, the socket has no local address. - */ - QString localPath() const; - /** - * Returns the peer address of this socket. That is, the address - * that this socket connected to (see connectToPath). Returns - * QString() if not connected. - */ - QString peerPath() const; - -private: - using QAbstractSocket::connectToHost; - using QAbstractSocket::disconnectFromHost; - -protected Q_SLOTS: - /// @internal - void connectToHostImplementation(const QString &hostName, quint16 port, OpenMode mode); - void disconnectFromHostImplementation(); - -public: - void connectToHost(const QHostAddress &address, quint16 port, OpenMode mode = ReadWrite) override - { - connectToHostImplementation(address.toString(), port, mode); - } - void connectToHost(const QString &hostName, quint16 port, OpenMode mode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol) override - { - Q_UNUSED(protocol) - connectToHostImplementation(hostName, port, mode); - } - void disconnectFromHost() override - { - disconnectFromHostImplementation(); - } - -private: - Q_DISABLE_COPY(KLocalSocket) - friend class KLocalSocketPrivate; - KLocalSocketPrivate *const d; -}; - -class KLocalSocketServerPrivate; -/** - * @class KLocalSocketServer - * @brief KLocalSocketServer allows one to create a listening local - * socket and accept incoming connections - * - * On some platforms, local sockets are a kind of streaming socket - * that can be used to transmit and receive data just like Internet - * (TCP) streaming sockets. The difference is that they remain local - * to the host running them and cannot be accessed externally. They - * are also very fast and (in theory) consume less resources than - * standard TCP sockets. - * - * KLocalSocketServer allows you to create the listening (i.e., - * passive) end of this local socket and accept incoming connections - * from users of KLocalSocket. It supports the same kind of socket - * types that KLocalSocket does (see KLocalSocket::LocalSocketType). - * - * @author Thiago Macieira - */ -class KIOCORE_EXPORT KLocalSocketServer : public QObject -{ - Q_OBJECT -public: - /** - * Creates a KLocalSocketServer object with @p parent as the - * parent object. The object is created without binding to any - * address. - * - * @param parent the parent object - */ - explicit KLocalSocketServer(QObject *parent = nullptr); - /** - * Destroys the KLocalSocketServer object and frees up any - * resource associated. If the socket is still listening, it's - * closed (see close()). - * - * The sockets that were accepted using this KLocalSocketServer - * object are not affected and will remain open. However, note - * that nextPendingConnection() returns objects that have this - * KLocalSocketServer as parents, so the QObject destruction will - * delete any objects that were not reparented. - */ - virtual ~KLocalSocketServer(); - - /** - * Binds this socket to the address @p path and starts listening - * there. - * - * If @p type is KLocalSocket::UnixSocket, @p path is - * treated as a Unix filesystem path and the calling user must - * have permission to create the named directory entry (that is, - * the user must have write permission to the parent directory, - * etc.) - * - * If @p type is KLocalSocket::AbstractUnixSocket, @p path is - * just a name that can be anything. It'll be converted to an - * 8-bit identifier just as if it were a file path, but - * filesystem restrictions do not apply. - * - * This function returns true if it succeeded in binding the - * socket to @p path and placing it in listen mode. It returns - * false otherwise. - * - * @param path the path to listen on - * @param type the local socket type - * @returns true on success, false otherwise - */ - bool listen(const QString &path, KLocalSocket::LocalSocketType type = KLocalSocket::UnixSocket); - - /** - * Closes the socket. No further connections will be accepted, - * but connections that were already pending can still be - * retrieved with nextPendingConnection(). - * - * Connections that were accepted and are already open will not - * be affected. - */ - void close(); - - /** - * Returns true if the socket is listening, false otherwise. - */ - bool isListening() const; - - /** - * Sets the maximum number of connections that KLocalSocketServer - * will accept on your behalf and keep queued, ready to be - * retrieved with nextPendingConnection(). If you set @p - * numConnections to 0, hasPendingConnections() will always - * return false. You can still use waitForNewConnection(), - * though. - * - * @param numConnections the number of connections to accept - * and keep queued. - */ - void setMaxPendingConnections(int numConnections); - /** - * Returns the value set with setMaxPendingConnections(). - */ - int maxPendingConnections() const; - - /** - * Returns the socket type that this socket is listening on. If it - * is not listening, returns QAbstractSocket::UnknownLocalSocketType. - */ - KLocalSocket::LocalSocketType localSocketType() const; - /** - * Returns the address of this socket if it is listening on, or - * QString() if it is not listening. - */ - QString localPath() const; - - /** - * Suspends the execution of the calling thread for at most @p - * msec milliseconds and wait for a new socket connection to be - * accepted (whichever comes first). If no new socket connection - * is received within @p msec milliseconds, consider this a - * time-out and set the boolean pointed by @p timedOut to false - * (if it's not 0). - * - * If @p msec is 0, this call will not block, but will simply poll - * the system to check if a new connection has been received in - * the background. - * - * Use @p msec value of -1 to block indefinitely. - * - * @param msec the time in milliseconds to block at most (-1 - * to block forever) - * @param timedOut points to a boolean that will be set to true - * if a timeout did occur - * @returns true if a new connection has been accepted or false if - * an error occurred or if the operation timed out. - */ - bool waitForNewConnection(int msec = 0, bool *timedOut = nullptr); - - /** - * Returns true if a new socket can be received with - * nextPendingConnection(). - */ - virtual bool hasPendingConnections() const; - /** - * Returns a new socket if one is available or @c nullptr if none is. - * - * Note that the objects returned by this function will have the - * current KLocalSocketServer object as its parent. You may want - * to reparent the accepted objects if you intend them to outlive - * the current object. - */ - virtual KLocalSocket *nextPendingConnection(); - - /** - * If an error occurred, return the error code. - */ - QAbstractSocket::SocketError serverError() const; - /** - * If an error occurred, return the error message. - */ - QString errorString() const; - -protected: - /// @internal - virtual void incomingConnection(int handle); - -Q_SIGNALS: - /** - * The newConnection() signal is emitted whenever a new connection - * is ready and has been accepted. Whenever it is emitted, calling - * nextPendingConnection() will return a valid object at least - * once. - */ - void newConnection(); - -private: - Q_PRIVATE_SLOT(d, void _k_newConnectionActivity()) - Q_DISABLE_COPY(KLocalSocketServer) - friend class KLocalSocketServerPrivate; - KLocalSocketServerPrivate *const d; -}; - -#endif diff --git a/src/core/klocalsocket_p.h b/src/core/klocalsocket_p.h deleted file mode 100644 index c2643b36..00000000 --- a/src/core/klocalsocket_p.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * This file is part of the KDE libraries - * 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. - */ -#ifndef KLOCALSOCKET_P_H -#define KLOCALSOCKET_P_H - -#include -#include -#include "klocalsocket.h" -#define MIN_SOCKADDR_UN_LEN (sizeof(quint16) + sizeof(char)) - -class QSocketNotifier; - -class KLocalSocketPrivate -{ -public: - KLocalSocket *const q; - explicit KLocalSocketPrivate(KLocalSocket *qq) - : q(qq), type(KLocalSocket::UnknownLocalSocketType) - { } - - QString localPath; - QString peerPath; - KLocalSocket::LocalSocketType type; - - void connectToPath(const QString &path, KLocalSocket::LocalSocketType type, - QAbstractSocket::OpenMode openMode); - - void emitError(QAbstractSocket::SocketError, const QString &errorString); - - static inline KLocalSocketPrivate *d(KLocalSocket *aq) - { - return aq->d; - } -}; - -class KLocalSocketServerPrivate -{ -public: - KLocalSocketServer *const q; - explicit KLocalSocketServerPrivate(KLocalSocketServer *qq); - - int descriptor; - int maxPendingConnections; - QAbstractSocket::SocketState state; - QAbstractSocket::SocketError error; - KLocalSocket::LocalSocketType type; - QString localPath; - QString errorString; - - QSocketNotifier *readNotifier; - QQueue pendingConnections; - - bool listen(const QString &path, KLocalSocket::LocalSocketType type); - void close(); - bool waitForNewConnection(int msec, bool *timedOut); - bool processSocketActivity(); - void _k_newConnectionActivity(); - void emitError(QAbstractSocket::SocketError, const QString &errorString); -}; - -#endif diff --git a/src/core/klocalsocket_unix.cpp b/src/core/klocalsocket_unix.cpp deleted file mode 100644 index fdc463d6..00000000 --- a/src/core/klocalsocket_unix.cpp +++ /dev/null @@ -1,424 +0,0 @@ -/* - * This file is part of the KDE libraries - * 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 // HAVE_STRUCT_SOCKADDR_SA_LEN - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "klocalizedstring.h" - -static inline int kSocket(int af, int socketype, int proto) -{ - int ret; - do { - ret = ::socket(af, socketype, proto); - } while (ret == -1 && errno == EINTR); - return ret; -} - -static inline int kBind(int fd, const sockaddr *sa, int len) -{ - int ret; - do { - ret = ::bind(fd, sa, len); - } while (ret == -1 && errno == EINTR); - return ret; -} - -static inline int kConnect(int fd, const sockaddr *sa, int len) -{ - int ret; - do { - ret = ::connect(fd, sa, len); - } while (ret == -1 && errno == EINTR); - return ret; -} - -static inline int kListen(int fd, int backlog) -{ - int ret; - do { - ret = ::listen(fd, backlog); - } while (ret == -1 && errno == EINTR); - return ret; -} - -static inline int kAccept(int fd) -{ - int ret; - sockaddr sa; - socklen_t len = sizeof(sa); - do { - ret = ::accept(fd, &sa, &len); - } while (ret == -1 && errno == EINTR); - return ret; -} - -#ifdef socket -#undef socket -#endif - -#ifdef bind -#undef bind -#endif - -#ifdef listen -#undef listen -#endif - -#ifdef connect -#undef connect -#endif - -#ifdef accept -#undef accept -#endif - -#include -#include -#include - -#include "klocalsocket.h" -#include "klocalsocket_p.h" - -#if !defined(AF_UNIX) && defined(AF_LOCAL) -# define AF_UNIX AF_LOCAL -#endif - -class KSockaddrUn -{ - int datalen; - QVarLengthArray data; -public: - KSockaddrUn(const QString &path, KLocalSocket::LocalSocketType type); - bool ok() const - { - return datalen; - } - int length() const - { - return datalen; - } - const sockaddr *address() - { - return reinterpret_cast(data.data()); - } -}; - -KSockaddrUn::KSockaddrUn(const QString &path, KLocalSocket::LocalSocketType type) - : datalen(0) -{ - if (path.isEmpty()) { - return; - } - - QString path2(path); - if (!path.startsWith(QLatin1Char('/'))) - // relative path; put everything in /tmp - { - path2.prepend(QLatin1String("/tmp/")); - } - - QByteArray encodedPath = QFile::encodeName(path2); - - datalen = MIN_SOCKADDR_UN_LEN + encodedPath.length(); - if (type == KLocalSocket::AbstractUnixSocket) { - ++datalen; - } - data.resize(datalen); - - sockaddr_un *saddr = reinterpret_cast(data.data()); - saddr->sun_family = AF_UNIX; -#if HAVE_STRUCT_SOCKADDR_SA_LEN - saddr->sun_len = datalen; -#endif - - if (type == KLocalSocket::UnixSocket) { - strcpy(saddr->sun_path, encodedPath.constData()); - } else if (type == KLocalSocket::AbstractUnixSocket) { - *saddr->sun_path = '\0'; - strcpy(saddr->sun_path + 1, encodedPath.constData()); - } else { - datalen = 0; // error - } -} - -static bool setNonBlocking(int fd) -{ - int fdflags = fcntl(fd, F_GETFL, 0); - if (fdflags == -1) { - return false; // error - } - - fdflags |= O_NONBLOCK; - if (fcntl(fd, F_SETFL, fdflags) == -1) { - return false; // error - } - - return true; -} - -void KLocalSocketPrivate::connectToPath(const QString &path, KLocalSocket::LocalSocketType aType, - QAbstractSocket::OpenMode openMode) -{ - if (aType == KLocalSocket::UnixSocket || aType == KLocalSocket::AbstractUnixSocket) { - // connect to Unix socket - KSockaddrUn addr(path, aType); - if (!addr.ok()) { - emitError(QAbstractSocket::NetworkError, i18n("Specified socket path is invalid")); - return; - } - - // create the socket - int fd = kSocket(AF_UNIX, SOCK_STREAM, 0); - if (fd == -1) { - // failed - emitError(QAbstractSocket::UnsupportedSocketOperationError, - i18n("The socket operation is not supported")); - return; - } - - // try to connect - // ### support non-blocking mode! - if (kConnect(fd, addr.address(), addr.length()) == -1) { - // failed - int error = errno; - ::close(fd); - - switch (error) { - case ECONNREFUSED: - emitError(QAbstractSocket::ConnectionRefusedError, i18n("Connection refused")); - return; - - case EACCES: - case EPERM: - emitError(QAbstractSocket::SocketAccessError, i18n("Permission denied")); - return; - - case ETIMEDOUT: - emitError(QAbstractSocket::SocketTimeoutError, i18n("Connection timed out")); - return; - - default: - emitError(QAbstractSocket::UnknownSocketError, i18n("Unknown error")); - return; - } - } - - // if we got here, we succeeded in connecting - if (!setNonBlocking(fd)) { - ::close(fd); - emitError(QAbstractSocket::UnknownSocketError, i18n("Could not set non-blocking mode")); - return; - } - - // all is good - peerPath = path; - type = aType; - - // setSocketDescriptor emits stateChanged - q->setSocketDescriptor(fd, QAbstractSocket::ConnectedState, openMode); - emit q->connected(); - } else { - emitError(QAbstractSocket::UnsupportedSocketOperationError, - i18n("The socket operation is not supported")); - } -} - -bool KLocalSocketServerPrivate::listen(const QString &path, KLocalSocket::LocalSocketType aType) -{ - qDeleteAll(pendingConnections); - pendingConnections.clear(); - - if (aType == KLocalSocket::UnixSocket || aType == KLocalSocket::AbstractUnixSocket) { - KSockaddrUn addr(path, aType); - if (!addr.ok()) { - emitError(QAbstractSocket::NetworkError, i18n("Specified socket path is invalid")); - return false; - } - - // create the socket - descriptor = kSocket(AF_UNIX, SOCK_STREAM, 0); - if (descriptor == -1) { - // failed - emitError(QAbstractSocket::UnsupportedSocketOperationError, - i18n("The socket operation is not supported")); - return false; - } - - // try to bind to the address - localPath = path; - if (kBind(descriptor, addr.address(), addr.length()) == -1 || - kListen(descriptor, 5) == -1) { - int error = errno; - close(); - - switch (error) { - case EACCES: - emitError(QAbstractSocket::SocketAccessError, i18n("Permission denied")); - return false; - - case EADDRINUSE: - emitError(QAbstractSocket::AddressInUseError, i18n("Address is already in use")); - return false; - - case ELOOP: - case ENAMETOOLONG: - emitError(QAbstractSocket::NetworkError, i18n("Path cannot be used")); - return false; - - case ENOENT: - emitError(QAbstractSocket::HostNotFoundError, i18n("No such file or directory")); - return false; - - case ENOTDIR: - emitError(QAbstractSocket::HostNotFoundError, i18n("Not a directory")); - return false; - - case EROFS: - emitError(QAbstractSocket::SocketResourceError, i18n("Read-only filesystem")); - return false; - - default: - emitError(QAbstractSocket::UnknownSocketError, i18n("Unknown error")); - return false; - } - } - - // if we got here, we succeeded in connecting - if (!setNonBlocking(descriptor)) { - close(); - emitError(QAbstractSocket::UnknownSocketError, i18n("Could not set non-blocking mode")); - return false; - } - - // done - state = QAbstractSocket::ListeningState; - type = aType; - readNotifier = new QSocketNotifier(descriptor, QSocketNotifier::Read, q); - readNotifier->setEnabled(maxPendingConnections > 0); - QObject::connect(readNotifier, SIGNAL(activated(int)), - q, SLOT(_k_newConnectionActivity())); - return true; - } - - return false; -} - -void KLocalSocketServerPrivate::close() -{ - if (descriptor != -1) { - ::close(descriptor); - } - descriptor = -1; - - delete readNotifier; - readNotifier = nullptr; - - if (type == KLocalSocket::UnixSocket) { - QFile::remove(localPath); - } - localPath.clear(); - type = KLocalSocket::UnknownLocalSocketType; - - state = QAbstractSocket::UnconnectedState; - error = QAbstractSocket::UnknownSocketError; - errorString.clear(); -} - -bool KLocalSocketServerPrivate::waitForNewConnection(int msec, bool *timedOut) -{ - timeval tv; - tv.tv_sec = msec / 1000; - tv.tv_usec = (msec % 1000) * 1000; - - fd_set readset; - FD_ZERO(&readset); - FD_SET(descriptor, &readset); - - while (descriptor != -1) { - int code = ::select(descriptor + 1, &readset, nullptr, nullptr, &tv); - if (code == -1 && errno == EINTR) { - // interrupted - continue; - } else if (code == -1) { - // error - emitError(QAbstractSocket::UnknownSocketError, i18n("Unknown socket error")); - close(); - return false; - } else if (code == 0) { - // timed out - if (timedOut) { - *timedOut = true; - } - return false; - } - - // we must've got a connection. At least, there's activity. - if (processSocketActivity()) { - if (timedOut) { - *timedOut = false; - } - return true; - } - } - return false; -} - -bool KLocalSocketServerPrivate::processSocketActivity() -{ - // we got a read notification in our socket - // see if we can accept anything - int newDescriptor = kAccept(descriptor); - if (newDescriptor == -1) { - switch (errno) { - case EAGAIN: - // shouldn't have happened, but it's ok - return false; // no new socket - - default: - emitError(QAbstractSocket::UnknownSocketError, i18n("Unknown socket error")); - // fall through - } - - close(); - return false; - } - - q->incomingConnection(newDescriptor); - readNotifier->setEnabled(pendingConnections.size() < maxPendingConnections); - return true; -} - -void KLocalSocketServerPrivate::_k_newConnectionActivity() -{ - if (descriptor == -1) { - return; - } - - processSocketActivity(); -} diff --git a/src/core/klocalsocket_win.cpp b/src/core/klocalsocket_win.cpp deleted file mode 100644 index 7df5d6f7..00000000 --- a/src/core/klocalsocket_win.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * This file is part of the KDE libraries - * 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. - */ - -// This file is a placeholder -// There is no Unix socket support on Windows - -#include "klocalsocket_p.h" - -#include "klocalizedstring.h" - -void KLocalSocketPrivate::connectToPath(const QString &path, KLocalSocket::LocalSocketType aType, - QAbstractSocket::OpenMode openMode) -{ - emitError(QAbstractSocket::UnsupportedSocketOperationError, i18n("Operation not supported")); -} - -bool KLocalSocketServerPrivate::listen(const QString &path, KLocalSocket::LocalSocketType aType) -{ - emitError(QAbstractSocket::UnsupportedSocketOperationError, i18n("Operation not supported")); - return false; -} - -void KLocalSocketServerPrivate::close() -{ -} - -bool KLocalSocketServerPrivate::waitForNewConnection(int, bool *) -{ - Q_ASSERT_X(false, "KLocalSocketServer::waitForNewConnection", - "This function should never have been called!"); - return false; -} - -void KLocalSocketServerPrivate::_k_newConnectionActivity() -{ -}