summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/network/socket/qlocalserver.cpp34
-rw-r--r--src/network/socket/qlocalserver.h1
-rw-r--r--src/network/socket/qlocalserver_p.h1
-rw-r--r--src/network/socket/qlocalserver_tcp.cpp7
-rw-r--r--src/network/socket/qlocalserver_unix.cpp42
-rw-r--r--src/network/socket/qlocalserver_win.cpp6
-rw-r--r--tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp104
7 files changed, 191 insertions, 4 deletions
diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp
index 97f5920171..05f26883d3 100644
--- a/src/network/socket/qlocalserver.cpp
+++ b/src/network/socket/qlocalserver.cpp
@@ -299,6 +299,40 @@ bool QLocalServer::listen(const QString &name)
}
/*!
+ \since 5.0
+
+ Instructs the server to listen for incoming connections on
+ \a socketDescriptor. The property returns \c false if the server is
+ currently listening. It returns \c true on success; otherwise,
+ it returns \c false. The socket must be ready to accept
+ new connections with no extra platform-specific functions
+ called. The socket is set into non-blocking mode.
+
+ serverName(), fullServerName() may return a string with
+ a name if this option is supported by the platform;
+ otherwise, they return an empty QString.
+
+ \sa isListening(), close()
+ */
+bool QLocalServer::listen(qintptr socketDescriptor)
+{
+ Q_D(QLocalServer);
+ if (isListening()) {
+ qWarning("QLocalServer::listen() called when already listening");
+ return false;
+ }
+
+ d->serverName.clear();
+ d->fullServerName.clear();
+
+ if (!d->listen(socketDescriptor)) {
+ return false;
+ }
+
+ return true;
+}
+
+/*!
Returns the maximum number of pending accepted connections.
The default is 30.
diff --git a/src/network/socket/qlocalserver.h b/src/network/socket/qlocalserver.h
index 6f883adc24..291122e10d 100644
--- a/src/network/socket/qlocalserver.h
+++ b/src/network/socket/qlocalserver.h
@@ -82,6 +82,7 @@ public:
virtual bool hasPendingConnections() const;
bool isListening() const;
bool listen(const QString &name);
+ bool listen(qintptr socketDescriptor);
int maxPendingConnections() const;
virtual QLocalSocket *nextPendingConnection();
QString serverName() const;
diff --git a/src/network/socket/qlocalserver_p.h b/src/network/socket/qlocalserver_p.h
index 03c06a42e3..84081159c7 100644
--- a/src/network/socket/qlocalserver_p.h
+++ b/src/network/socket/qlocalserver_p.h
@@ -87,6 +87,7 @@ public:
void init();
bool listen(const QString &name);
+ bool listen(qintptr socketDescriptor);
static bool removeServer(const QString &name);
void closeServer();
void waitForNewConnection(int msec, bool *timedOut);
diff --git a/src/network/socket/qlocalserver_tcp.cpp b/src/network/socket/qlocalserver_tcp.cpp
index d6c6a1af92..9ac1bfaf0e 100644
--- a/src/network/socket/qlocalserver_tcp.cpp
+++ b/src/network/socket/qlocalserver_tcp.cpp
@@ -78,6 +78,13 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName)
return true;
}
+bool QLocalServerPrivate::listen(qintptr socketDescriptor)
+{
+ Q_Q(QLocalServer);
+
+ return tcpServer.setSocketDescriptor(socketDescriptor);
+}
+
void QLocalServerPrivate::closeServer()
{
QSettings settings(QLatin1String("Trolltech"), QLatin1String("Qt"));
diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp
index ce0c283f0b..0c2edef578 100644
--- a/src/network/socket/qlocalserver_unix.cpp
+++ b/src/network/socket/qlocalserver_unix.cpp
@@ -203,6 +203,48 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName)
return true;
}
+bool QLocalServerPrivate::listen(qintptr socketDescriptor)
+{
+ Q_Q(QLocalServer);
+
+ // Attach to the localsocket
+ listenSocket = socketDescriptor;
+
+ ::fcntl(listenSocket, F_SETFD, FD_CLOEXEC);
+ ::fcntl(listenSocket, F_SETFL, ::fcntl(listenSocket, F_GETFL) | O_NONBLOCK);
+
+#ifdef Q_OS_LINUX
+ struct ::sockaddr_un addr;
+ socklen_t len;
+ memset(&addr, 0, sizeof(addr));
+ if (0 == ::getsockname(listenSocket, (sockaddr *)&addr, &len)) {
+ // check for absract sockets
+ if (addr.sun_family == PF_UNIX && addr.sun_path[0] == 0) {
+ addr.sun_path[0] = '@';
+ }
+ QString name = QString::fromLatin1(addr.sun_path);
+ if (!name.isEmpty()) {
+ fullServerName = name;
+ serverName = fullServerName.mid(fullServerName.lastIndexOf(QLatin1String("/"))+1);
+ if (serverName.isEmpty()) {
+ serverName = fullServerName;
+ }
+ }
+ }
+#else
+ serverName.clear();
+ fullServerName.clear();
+#endif
+
+ Q_ASSERT(!socketNotifier);
+ socketNotifier = new QSocketNotifier(listenSocket,
+ QSocketNotifier::Read, q);
+ q->connect(socketNotifier, SIGNAL(activated(int)),
+ q, SLOT(_q_onNewConnection()));
+ socketNotifier->setEnabled(maxPendingConnections > 0);
+ return true;
+}
+
/*!
\internal
diff --git a/src/network/socket/qlocalserver_win.cpp b/src/network/socket/qlocalserver_win.cpp
index 67e319cdbb..07357e5789 100644
--- a/src/network/socket/qlocalserver_win.cpp
+++ b/src/network/socket/qlocalserver_win.cpp
@@ -144,6 +144,12 @@ bool QLocalServerPrivate::listen(const QString &name)
return true;
}
+bool QLocalServerPrivate::listen(qintptr)
+{
+ qWarning("QLocalServer::listen(qintptr) is not supported on Windows QTBUG-24230");
+ return false;
+}
+
void QLocalServerPrivate::_q_onNewConnection()
{
Q_Q(QLocalServer);
diff --git a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp
index 03b95bfa2f..72fa9f74a4 100644
--- a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp
+++ b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp
@@ -46,6 +46,12 @@
#include <QtNetwork/qlocalsocket.h>
#include <QtNetwork/qlocalserver.h>
+#ifdef Q_OS_UNIX
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+
Q_DECLARE_METATYPE(QLocalSocket::LocalSocketError)
Q_DECLARE_METATYPE(QLocalSocket::LocalSocketState)
Q_DECLARE_METATYPE(QLocalServer::SocketOption)
@@ -109,6 +115,10 @@ private slots:
void verifySocketOptions();
void verifySocketOptions_data();
+
+ void verifyListenWithDescriptor();
+ void verifyListenWithDescriptor_data();
+
};
void tst_QLocalSocket::init()
@@ -1026,19 +1036,19 @@ void tst_QLocalSocket::verifySocketOptions_data()
QFile::Permissions p = QFile::ExeOwner|QFile::WriteOwner|QFile::ReadOwner |
QFile::ExeUser|QFile::WriteUser|QFile::ReadUser;
- QTest::newRow("user") << "userPerms" << QLocalServer::UserAccess << p;
+ QTest::newRow("user") << "userPerms" << QLocalServer::UserAccessOption << p;
p = QFile::ExeGroup|QFile::WriteGroup|QFile::ReadGroup;
- QTest::newRow("group") << "groupPerms" << QLocalServer::GroupAccess << p;
+ QTest::newRow("group") << "groupPerms" << QLocalServer::GroupAccessOption << p;
p = QFile::ExeOther|QFile::WriteOther|QFile::ReadOther;
- QTest::newRow("other") << "otherPerms" << QLocalServer::OtherAccess << p;
+ QTest::newRow("other") << "otherPerms" << QLocalServer::OtherAccessOption << p;
p = QFile::ExeOwner|QFile::WriteOwner|QFile::ReadOwner|
QFile::ExeUser|QFile::WriteUser|QFile::ReadUser |
QFile::ExeGroup|QFile::WriteGroup|QFile::ReadGroup|
QFile::ExeOther|QFile::WriteOther|QFile::ReadOther;
- QTest::newRow("all") << "worldPerms" << QLocalServer::WorldAccess << p;
+ QTest::newRow("all") << "worldPerms" << QLocalServer::WorldAccessOption << p;
#endif
}
@@ -1065,6 +1075,92 @@ void tst_QLocalSocket::verifySocketOptions()
#endif
}
+void tst_QLocalSocket::verifyListenWithDescriptor()
+{
+#ifdef Q_OS_UNIX
+ QFETCH(QString, path);
+ QFETCH(bool, abstract);
+ QFETCH(bool, bound);
+
+ qDebug() << "socket" << path << abstract;
+
+ int listenSocket;
+
+ if (bound) {
+ // create the unix socket
+ listenSocket = ::socket(PF_UNIX, SOCK_STREAM, 0);
+ QVERIFY2(listenSocket != -1, "failed to create test socket");
+
+ // Construct the unix address
+ struct ::sockaddr_un addr;
+ addr.sun_family = PF_UNIX;
+
+ QVERIFY2(sizeof(addr.sun_path) > ((uint)path.size() + 1), "path to large to create socket");
+
+ ::memset(addr.sun_path, 0, sizeof(addr.sun_path));
+ if (abstract)
+ ::memcpy(addr.sun_path+1, path.toLatin1().data(), path.toLatin1().size());
+ else
+ ::memcpy(addr.sun_path, path.toLatin1().data(), path.toLatin1().size());
+
+ if (path.startsWith(QLatin1Char('/'))) {
+ ::unlink(path.toLatin1());
+ }
+
+ QVERIFY2(-1 != ::bind(listenSocket, (sockaddr *)&addr, sizeof(sockaddr_un)), "failed to bind test socket to address");
+
+ // listen for connections
+ QVERIFY2(-1 != ::listen(listenSocket, 50), "failed to call listen on test socket");
+ } else {
+ int fds[2];
+ QVERIFY2(-1 != ::socketpair(PF_UNIX, SOCK_STREAM, 0, fds), "failed to create socket pair");
+
+ listenSocket = fds[0];
+ close(fds[1]);
+ }
+
+ QLocalServer server;
+ QVERIFY2(server.listen(listenSocket), "failed to start create QLocalServer with local socket");
+
+#ifdef Q_OS_LINUX
+ if (!bound) {
+ QVERIFY(server.serverName().at(0) == QLatin1Char('@'));
+ QVERIFY(server.fullServerName().at(0) == QLatin1Char('@'));
+ } else if (abstract) {
+ QVERIFY2(server.fullServerName().at(0) == QLatin1Char('@'), "abstract sockets should start with a '@'");
+ } else {
+ QVERIFY2(server.fullServerName() == path, "full server path doesn't match patch provided");
+ if (path.contains(QLatin1String("/"))) {
+ QVERIFY2(server.serverName() == path.mid(path.lastIndexOf(QLatin1Char('/'))+1), "server name invalid short name");
+ } else {
+ QVERIFY2(server.serverName() == path, "servier name doesn't match the path provided");
+ }
+ }
+#else
+ QVERIFY(server.serverName().isEmpty());
+ QVERIFY(server.fullServerName().isEmpty());
+#endif
+
+
+#endif
+}
+
+void tst_QLocalSocket::verifyListenWithDescriptor_data()
+{
+#ifdef Q_OS_UNIX
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<bool>("abstract");
+ QTest::addColumn<bool>("bound");
+
+ QTest::newRow("normal") << QDir::tempPath() + QLatin1Literal("/testsocket") << false << true;
+ QTest::newRow("absrtact") << QString::fromLatin1("abstractsocketname") << true << true;
+ QTest::newRow("abstractwithslash") << QString::fromLatin1("abstractsocketwitha/inthename") << true << true;
+ QTest::newRow("no path") << QString::fromLatin1("/invalid/no path name speficied") << true << false;
+
+#endif
+
+}
+
QTEST_MAIN(tst_QLocalSocket)
#include "tst_qlocalsocket.moc"