Allow the QLocalServer to listen to a native descriptor
QLocalServer could only listen to sockets it created. Thi is not always possible as sockets may be passed by socketpair() or have to be created locally by other means. This adds a similar feature to QLocalSocket where a native descriptor maybe used. Change-Id: I43b0af179b3b868dd164d4e1fd312ff4546cf9ff Reviewed-by: Michalina Ziemba <michalina.ziemba@nokia.com> Reviewed-by: Tapani Mikola <tapani.mikola@nokia.com> Reviewed-by: Harald Fernengel <harald.fernengel@nokia.com>
This commit is contained in:
parent
fc8f92106d
commit
9809471223
@ -298,6 +298,40 @@ bool QLocalServer::listen(const QString &name)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
\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.
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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"));
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user