1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2016 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the test suite of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:GPL-EXCEPT$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU
20** General Public License version 3 as published by the Free Software
21** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30
31#include <QtTest/QtTest>
32
33#include <qtextstream.h>
34#include <qdatastream.h>
35#include <qelapsedtimer.h>
36#include <QtNetwork/qlocalsocket.h>
37#include <QtNetwork/qlocalserver.h>
38
39#ifdef Q_OS_UNIX
40#include <sys/types.h>
41#include <sys/socket.h>
42#include <sys/un.h>
43#include <unistd.h> // for unlink()
44#endif
45
46#ifdef Q_OS_WIN
47#include <QtCore/qt_windows.h>
48#endif
49
50Q_DECLARE_METATYPE(QLocalSocket::LocalSocketError)
51Q_DECLARE_METATYPE(QLocalSocket::LocalSocketState)
52Q_DECLARE_METATYPE(QLocalServer::SocketOption)
53Q_DECLARE_METATYPE(QFile::Permissions)
54
55class tst_QLocalSocket : public QObject
56{
57 Q_OBJECT
58
59public:
60 tst_QLocalSocket();
61
62private slots:
63 // basics
64 void server_basic();
65 void server_connectionsCount();
66 void socket_basic();
67
68 void listen_data();
69 void listen();
70
71 void listenAndConnect_data();
72 void listenAndConnect();
73
74 void connectWithOpen();
75 void connectWithOldOpen();
76
77 void sendData_data();
78 void sendData();
79
80 void readBufferOverflow();
81
82 void simpleCommandProtocol1();
83 void simpleCommandProtocol2();
84
85 void fullPath();
86
87 void hitMaximumConnections_data();
88 void hitMaximumConnections();
89
90 void setSocketDescriptor();
91
92 void threadedConnection_data();
93 void threadedConnection();
94
95 void processConnection_data();
96 void processConnection();
97
98 void longPath();
99 void waitForDisconnect();
100 void waitForDisconnectByServer();
101
102 void removeServer();
103
104 void recycleServer();
105 void recycleClientSocket();
106
107 void multiConnect();
108 void writeOnlySocket();
109
110 void writeToClientAndDisconnect_data();
111 void writeToClientAndDisconnect();
112
113 void debug();
114 void bytesWrittenSignal();
115 void syncDisconnectNotify();
116 void asyncDisconnectNotify();
117
118 void verifySocketOptions();
119 void verifySocketOptions_data();
120
121 void verifyListenWithDescriptor();
122 void verifyListenWithDescriptor_data();
123
124};
125
126tst_QLocalSocket::tst_QLocalSocket()
127{
128 qRegisterMetaType<QLocalSocket::LocalSocketState>(typeName: "QLocalSocket::LocalSocketState");
129 qRegisterMetaType<QLocalSocket::LocalSocketError>(typeName: "QLocalSocket::LocalSocketError");
130 qRegisterMetaType<QLocalServer::SocketOption>(typeName: "QLocalServer::SocketOption");
131 qRegisterMetaType<QFile::Permissions>(typeName: "QFile::Permissions");
132}
133
134class LocalServer : public QLocalServer
135{
136 Q_OBJECT
137
138public:
139 LocalServer() : QLocalServer()
140 {
141 connect(sender: this, SIGNAL(newConnection()), receiver: this, SLOT(slotNewConnection()));
142 }
143
144 bool listen(const QString &name)
145 {
146 removeServer(name);
147 return QLocalServer::listen(name);
148 }
149
150 QList<int> hits;
151
152protected:
153 void incomingConnection(quintptr socketDescriptor)
154 {
155 hits.append(t: socketDescriptor);
156 QLocalServer::incomingConnection(socketDescriptor);
157 }
158
159private slots:
160 void slotNewConnection() {
161 QVERIFY(!hits.isEmpty());
162 QVERIFY(hasPendingConnections());
163 }
164};
165
166class LocalSocket : public QLocalSocket
167{
168 Q_OBJECT
169
170public:
171 LocalSocket(QObject *parent = 0) : QLocalSocket(parent)
172 {
173 connect(sender: this, SIGNAL(connected()),
174 receiver: this, SLOT(slotConnected()));
175 connect(sender: this, SIGNAL(disconnected()),
176 receiver: this, SLOT(slotDisconnected()));
177 connect(sender: this, SIGNAL(errorOccurred(QLocalSocket::LocalSocketError)),
178 receiver: this, SLOT(slotErrorOccurred(QLocalSocket::LocalSocketError)));
179 connect(sender: this, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)),
180 receiver: this, SLOT(slotStateChanged(QLocalSocket::LocalSocketState)));
181 connect(sender: this, SIGNAL(readyRead()),
182 receiver: this, SLOT(slotReadyRead()));
183 }
184
185private slots:
186 void slotConnected()
187 {
188 QCOMPARE(state(), QLocalSocket::ConnectedState);
189 QVERIFY(isOpen());
190 }
191 void slotDisconnected()
192 {
193 QCOMPARE(state(), QLocalSocket::UnconnectedState);
194 }
195 void slotErrorOccurred(QLocalSocket::LocalSocketError newError)
196 {
197 QVERIFY(errorString() != QLatin1String("Unknown error"));
198 QCOMPARE(error(), newError);
199 }
200 void slotStateChanged(QLocalSocket::LocalSocketState newState)
201 {
202 QCOMPARE(state(), newState);
203 }
204 void slotReadyRead()
205 {
206 QVERIFY(bytesAvailable() > 0);
207 }
208};
209
210// basic test make sure no segfaults and check default values
211void tst_QLocalSocket::server_basic()
212{
213 LocalServer server;
214 QSignalSpy spyNewConnection(&server, SIGNAL(newConnection()));
215 server.close();
216 QCOMPARE(server.errorString(), QString());
217 QCOMPARE(server.hasPendingConnections(), false);
218 QCOMPARE(server.isListening(), false);
219 QCOMPARE(server.maxPendingConnections(), 30);
220 QCOMPARE(server.nextPendingConnection(), (QLocalSocket*)0);
221 QCOMPARE(server.serverName(), QString());
222 QCOMPARE(server.fullServerName(), QString());
223 QCOMPARE(server.serverError(), QAbstractSocket::UnknownSocketError);
224 server.setMaxPendingConnections(20);
225 bool timedOut = true;
226 QCOMPARE(server.waitForNewConnection(3000, &timedOut), false);
227 QVERIFY(!timedOut);
228 QCOMPARE(server.listen(QString()), false);
229
230 QCOMPARE(server.hits.count(), 0);
231 QCOMPARE(spyNewConnection.count(), 0);
232}
233
234void tst_QLocalSocket::server_connectionsCount()
235{
236 LocalServer server;
237 server.setMaxPendingConnections(10);
238 QCOMPARE(server.maxPendingConnections(), 10);
239}
240
241// basic test make sure no segfaults and check default values
242void tst_QLocalSocket::socket_basic()
243{
244 LocalSocket socket;
245 QSignalSpy spyConnected(&socket, SIGNAL(connected()));
246 QSignalSpy spyDisconnected(&socket, SIGNAL(disconnected()));
247 QSignalSpy spyError(&socket, SIGNAL(errorOccurred(QLocalSocket::LocalSocketError)));
248 QSignalSpy spyStateChanged(&socket, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)));
249 QSignalSpy spyReadyRead(&socket, SIGNAL(readyRead()));
250
251 QCOMPARE(socket.serverName(), QString());
252 QCOMPARE(socket.fullServerName(), QString());
253 socket.abort();
254 QCOMPARE(socket.bytesAvailable(), 0);
255 QCOMPARE(socket.bytesToWrite(), 0);
256 QCOMPARE(socket.canReadLine(), false);
257 socket.close();
258 socket.disconnectFromServer();
259 QCOMPARE(QLocalSocket::UnknownSocketError, socket.error());
260 QVERIFY(!socket.errorString().isEmpty());
261 QCOMPARE(socket.flush(), false);
262 QCOMPARE(socket.isValid(), false);
263 QCOMPARE(socket.readBufferSize(), 0);
264 socket.setReadBufferSize(0);
265 //QCOMPARE(socket.socketDescriptor(), (qintptr)-1);
266 QCOMPARE(socket.state(), QLocalSocket::UnconnectedState);
267 QCOMPARE(socket.waitForConnected(0), false);
268 QTest::ignoreMessage(type: QtWarningMsg, message: "QLocalSocket::waitForDisconnected() is not allowed in UnconnectedState");
269 QCOMPARE(socket.waitForDisconnected(0), false);
270 QCOMPARE(socket.waitForReadyRead(0), false);
271
272 QCOMPARE(spyConnected.count(), 0);
273 QCOMPARE(spyDisconnected.count(), 0);
274 QCOMPARE(spyError.count(), 0);
275 QCOMPARE(spyStateChanged.count(), 0);
276 QCOMPARE(spyReadyRead.count(), 0);
277}
278
279void tst_QLocalSocket::listen_data()
280{
281 QTest::addColumn<QString>(name: "name");
282 QTest::addColumn<bool>(name: "canListen");
283 QTest::addColumn<bool>(name: "close");
284 QTest::newRow(dataTag: "null") << QString() << false << false;
285 QTest::newRow(dataTag: "tst_localsocket") << "tst_localsocket" << true << true;
286 QTest::newRow(dataTag: "tst_localsocket") << "tst_localsocket" << true << false;
287}
288
289// start a server that listens, but don't connect a socket, make sure everything is in order
290void tst_QLocalSocket::listen()
291{
292 LocalServer server;
293 QSignalSpy spyNewConnection(&server, SIGNAL(newConnection()));
294
295 QFETCH(QString, name);
296 QFETCH(bool, canListen);
297 QFETCH(bool, close);
298 QVERIFY2((server.listen(name) == canListen), server.errorString().toLatin1().constData());
299
300 // test listening
301 QCOMPARE(server.serverName(), name);
302 QVERIFY(server.fullServerName().contains(name));
303 QCOMPARE(server.isListening(), canListen);
304 QCOMPARE(server.hasPendingConnections(), false);
305 QCOMPARE(server.nextPendingConnection(), (QLocalSocket*)0);
306 QCOMPARE(server.hits.count(), 0);
307 QCOMPARE(spyNewConnection.count(), 0);
308 if (canListen) {
309 QVERIFY(server.errorString().isEmpty());
310 QCOMPARE(server.serverError(), QAbstractSocket::UnknownSocketError);
311 // already isListening
312 QTest::ignoreMessage(type: QtWarningMsg, message: "QLocalServer::listen() called when already listening");
313 QVERIFY(!server.listen(name));
314 QVERIFY(server.socketDescriptor() != -1);
315 } else {
316 QVERIFY(!server.errorString().isEmpty());
317 QCOMPARE(server.serverError(), QAbstractSocket::HostNotFoundError);
318 QCOMPARE(server.socketDescriptor(), -1);
319 }
320 QCOMPARE(server.maxPendingConnections(), 30);
321 bool timedOut = false;
322 QCOMPARE(server.waitForNewConnection(3000, &timedOut), false);
323 QCOMPARE(timedOut, canListen);
324 if (close)
325 server.close();
326}
327
328void tst_QLocalSocket::listenAndConnect_data()
329{
330 QTest::addColumn<QString>(name: "name");
331 QTest::addColumn<bool>(name: "canListen");
332 QTest::addColumn<int>(name: "connections");
333 for (int i = 0; i < 3; ++i) {
334 int connections = i;
335 if (i == 2)
336 connections = 5;
337 const QByteArray iB = QByteArray::number(i);
338 QTest::newRow(dataTag: ("null " + iB).constData()) << QString() << false << connections;
339 QTest::newRow(dataTag: ("tst_localsocket " + iB).constData()) << "tst_localsocket" << true << connections;
340 }
341}
342
343void tst_QLocalSocket::listenAndConnect()
344{
345 LocalServer server;
346 QSignalSpy spyNewConnection(&server, SIGNAL(newConnection()));
347
348 QFETCH(QString, name);
349 QFETCH(bool, canListen);
350 QCOMPARE(server.listen(name), canListen);
351 QTRY_COMPARE(server.serverError(),
352 canListen ? QAbstractSocket::UnknownSocketError : QAbstractSocket::HostNotFoundError);
353
354 // test creating connection(s)
355 QFETCH(int, connections);
356 QList<QLocalSocket*> sockets;
357 for (int i = 0; i < connections; ++i) {
358 LocalSocket *socket = new LocalSocket;
359
360 QSignalSpy spyConnected(socket, SIGNAL(connected()));
361 QSignalSpy spyDisconnected(socket, SIGNAL(disconnected()));
362 QSignalSpy spyError(socket, SIGNAL(errorOccurred(QLocalSocket::LocalSocketError)));
363 QSignalSpy spyStateChanged(socket, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)));
364 QSignalSpy spyReadyRead(socket, SIGNAL(readyRead()));
365
366 socket->connectToServer(name);
367#if defined(QT_LOCALSOCKET_TCP)
368 QTest::qWait(250);
369#endif
370
371 QCOMPARE(socket->serverName(), name);
372 QVERIFY(socket->fullServerName().contains(name));
373 sockets.append(t: socket);
374 if (canListen) {
375 QVERIFY(socket->waitForConnected());
376 QVERIFY(socket->isValid());
377 QCOMPARE(socket->errorString(), QString("Unknown error"));
378 QCOMPARE(socket->error(), QLocalSocket::UnknownSocketError);
379 QCOMPARE(socket->state(), QLocalSocket::ConnectedState);
380 //QVERIFY(socket->socketDescriptor() != -1);
381 QCOMPARE(spyError.count(), 0);
382 } else {
383 QVERIFY(!socket->errorString().isEmpty());
384 QVERIFY(socket->error() != QLocalSocket::UnknownSocketError);
385 QCOMPARE(socket->state(), QLocalSocket::UnconnectedState);
386 //QCOMPARE(socket->socketDescriptor(), -1);
387 QCOMPARE(qvariant_cast<QLocalSocket::LocalSocketError>(spyError.first()[0]),
388 QLocalSocket::ServerNotFoundError);
389 }
390
391 QCOMPARE(socket->bytesAvailable(), 0);
392 QCOMPARE(socket->bytesToWrite(), 0);
393 QCOMPARE(socket->canReadLine(), false);
394 QCOMPARE(socket->flush(), false);
395 QCOMPARE(socket->isValid(), canListen);
396 QCOMPARE(socket->readBufferSize(), (qint64)0);
397 QCOMPARE(socket->waitForConnected(0), canListen);
398 QCOMPARE(socket->waitForReadyRead(0), false);
399
400 QTRY_COMPARE(spyConnected.count(), canListen ? 1 : 0);
401 QCOMPARE(spyDisconnected.count(), 0);
402
403 // error signals
404 QVERIFY(spyError.count() >= 0);
405 if (canListen) {
406 if (spyError.count() > 0)
407 QCOMPARE(qvariant_cast<QLocalSocket::LocalSocketError>(spyError.first()[0]),
408 QLocalSocket::SocketTimeoutError);
409 } else {
410 QCOMPARE(qvariant_cast<QLocalSocket::LocalSocketError>(spyError.first()[0]),
411 QLocalSocket::ServerNotFoundError);
412 }
413
414 // Check first and last state
415 QCOMPARE(qvariant_cast<QLocalSocket::LocalSocketState>(spyStateChanged.first()[0]),
416 QLocalSocket::ConnectingState);
417
418 if (canListen)
419 QCOMPARE(qvariant_cast<QLocalSocket::LocalSocketState>(spyStateChanged.last()[0]),
420 QLocalSocket::ConnectedState);
421 QCOMPARE(spyStateChanged.count(), 2);
422 QCOMPARE(spyReadyRead.count(), 0);
423
424 bool timedOut = true;
425 QCOMPARE(server.waitForNewConnection(3000, &timedOut), canListen);
426 QVERIFY(!timedOut);
427 QCOMPARE(server.hasPendingConnections(), canListen);
428 QCOMPARE(server.isListening(), canListen);
429 // NOTE: socket disconnecting is not tested here
430
431 // server checks post connection
432 if (canListen) {
433 QCOMPARE(server.serverName(), name);
434 QVERIFY(server.fullServerName().contains(name));
435 QVERIFY(server.nextPendingConnection() != (QLocalSocket*)0);
436 QTRY_COMPARE(server.hits.count(), i + 1);
437 QCOMPARE(spyNewConnection.count(), i + 1);
438 QVERIFY(server.errorString().isEmpty());
439 QCOMPARE(server.serverError(), QAbstractSocket::UnknownSocketError);
440 } else {
441 QVERIFY(server.serverName().isEmpty());
442 QVERIFY(server.fullServerName().isEmpty());
443 QCOMPARE(server.nextPendingConnection(), (QLocalSocket*)0);
444 QCOMPARE(spyNewConnection.count(), 0);
445 QCOMPARE(server.hits.count(), 0);
446 QVERIFY(!server.errorString().isEmpty());
447 QCOMPARE(server.serverError(), QAbstractSocket::HostNotFoundError);
448 }
449 }
450 qDeleteAll(begin: sockets.begin(), end: sockets.end());
451
452 server.close();
453
454 QCOMPARE(server.hits.count(), (canListen ? connections : 0));
455 QCOMPARE(spyNewConnection.count(), (canListen ? connections : 0));
456}
457
458void tst_QLocalSocket::connectWithOpen()
459{
460 LocalServer server;
461 QVERIFY(server.listen("tst_qlocalsocket"));
462
463 LocalSocket socket;
464 socket.setServerName("tst_qlocalsocket");
465 QVERIFY(socket.open());
466
467 bool timedOut = true;
468 QVERIFY(server.waitForNewConnection(3000, &timedOut));
469
470#if defined(QT_LOCALSOCKET_TCP)
471 QTest::qWait(250);
472#endif
473 QVERIFY(!timedOut);
474
475 socket.close();
476 server.close();
477}
478
479void tst_QLocalSocket::connectWithOldOpen()
480{
481 class OverriddenOpen : public LocalSocket
482 {
483 public:
484 virtual bool open(OpenMode mode) override
485 { return QIODevice::open(mode); }
486 };
487
488 LocalServer server;
489 QCOMPARE(server.listen("tst_qlocalsocket"), true);
490
491 OverriddenOpen socket;
492 socket.connectToServer(name: "tst_qlocalsocket");
493
494 bool timedOut = true;
495 QVERIFY(server.waitForNewConnection(3000, &timedOut));
496
497#if defined(QT_LOCALSOCKET_TCP)
498 QTest::qWait(250);
499#endif
500 QVERIFY(!timedOut);
501
502 socket.close();
503 server.close();
504}
505
506void tst_QLocalSocket::sendData_data()
507{
508 QTest::addColumn<QString>(name: "name");
509 QTest::addColumn<bool>(name: "canListen");
510
511 QTest::newRow(dataTag: "null") << QString() << false;
512 QTest::newRow(dataTag: "tst_localsocket") << "tst_localsocket" << true;
513}
514
515void tst_QLocalSocket::sendData()
516{
517 QFETCH(QString, name);
518 QFETCH(bool, canListen);
519
520 LocalServer server;
521 QSignalSpy spy(&server, SIGNAL(newConnection()));
522
523 QCOMPARE(server.listen(name), canListen);
524
525 LocalSocket socket;
526 QSignalSpy spyConnected(&socket, SIGNAL(connected()));
527 QSignalSpy spyDisconnected(&socket, SIGNAL(disconnected()));
528 QSignalSpy spyError(&socket, SIGNAL(errorOccurred(QLocalSocket::LocalSocketError)));
529 QSignalSpy spyStateChanged(&socket, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)));
530 QSignalSpy spyReadyRead(&socket, SIGNAL(readyRead()));
531
532 // test creating a connection
533 socket.connectToServer(name);
534 bool timedOut = true;
535 int expectedReadyReadSignals = 0;
536
537 QCOMPARE(server.waitForNewConnection(3000, &timedOut), canListen);
538
539#if defined(QT_LOCALSOCKET_TCP)
540 QTest::qWait(250);
541#endif
542 QVERIFY(!timedOut);
543 QCOMPARE(spyConnected.count(), canListen ? 1 : 0);
544 QCOMPARE(socket.state(), canListen ? QLocalSocket::ConnectedState : QLocalSocket::UnconnectedState);
545
546 // test sending/receiving data
547 if (server.hasPendingConnections()) {
548 QString testLine = "test";
549 for (int i = 0; i < 50000; ++i)
550 testLine += QLatin1Char('a');
551 QLocalSocket *serverSocket = server.nextPendingConnection();
552 QVERIFY(serverSocket);
553 QCOMPARE(serverSocket->state(), QLocalSocket::ConnectedState);
554 QTextStream out(serverSocket);
555 QTextStream in(&socket);
556 out << testLine << Qt::endl;
557 bool wrote = serverSocket->waitForBytesWritten(msecs: 3000);
558
559 if (!socket.canReadLine()) {
560 expectedReadyReadSignals = 1;
561 QVERIFY(socket.waitForReadyRead());
562 }
563
564 QVERIFY(socket.bytesAvailable() >= 0);
565 QCOMPARE(socket.bytesToWrite(), (qint64)0);
566 QCOMPARE(socket.flush(), false);
567 QCOMPARE(socket.isValid(), canListen);
568 QCOMPARE(socket.readBufferSize(), (qint64)0);
569 QCOMPARE(spyReadyRead.count(), expectedReadyReadSignals);
570
571 QVERIFY(testLine.startsWith(in.readLine()));
572
573 QVERIFY(wrote || serverSocket->waitForBytesWritten(1000));
574
575 QCOMPARE(serverSocket->errorString(), QString("Unknown error"));
576 QCOMPARE(socket.errorString(), QString("Unknown error"));
577 }
578
579 socket.disconnectFromServer();
580 QCOMPARE(spyConnected.count(), canListen ? 1 : 0);
581 QCOMPARE(spyDisconnected.count(), canListen ? 1 : 0);
582 QCOMPARE(spyError.count(), canListen ? 0 : 1);
583 QCOMPARE(spyStateChanged.count(), canListen ? 4 : 2);
584 QCOMPARE(spyReadyRead.count(), canListen ? expectedReadyReadSignals : 0);
585
586 server.close();
587
588 QCOMPARE(server.hits.count(), (canListen ? 1 : 0));
589 QCOMPARE(spy.count(), (canListen ? 1 : 0));
590}
591
592void tst_QLocalSocket::readBufferOverflow()
593{
594 const int readBufferSize = 128;
595 const int dataBufferSize = readBufferSize * 2;
596 const QString serverName = QLatin1String("myPreciousTestServer");
597 LocalServer server;
598 server.listen(name: serverName);
599 QVERIFY(server.isListening());
600
601 LocalSocket client;
602 client.setReadBufferSize(readBufferSize);
603 client.connectToServer(name: serverName);
604
605 bool timedOut = true;
606 QVERIFY(server.waitForNewConnection(3000, &timedOut));
607 QVERIFY(!timedOut);
608
609 QCOMPARE(client.state(), QLocalSocket::ConnectedState);
610 QVERIFY(server.hasPendingConnections());
611
612 QLocalSocket* serverSocket = server.nextPendingConnection();
613 char buffer[dataBufferSize];
614 memset(s: buffer, c: 0, n: dataBufferSize);
615 serverSocket->write(data: buffer, len: dataBufferSize);
616#ifndef Q_OS_WIN
617 // The data is not immediately sent, but buffered.
618 // On Windows, the flushing is done by an asynchronous write operation.
619 // However, this operation will never complete as long as the data is not
620 // read by the other end, so the call below always times out.
621 // On Unix, the flushing is synchronous and thus needs to be done before
622 // attempting to read the data in the same thread. Buffering by the OS
623 // prevents the deadlock seen on Windows.
624 serverSocket->waitForBytesWritten();
625#endif
626
627 // wait until the first 128 bytes are ready to read
628 QVERIFY(client.waitForReadyRead());
629 QCOMPARE(client.read(buffer, readBufferSize), qint64(readBufferSize));
630 // wait until the second 128 bytes are ready to read
631 QVERIFY(client.waitForReadyRead());
632 QCOMPARE(client.read(buffer, readBufferSize), qint64(readBufferSize));
633 // no more bytes available
634 QCOMPARE(client.bytesAvailable(), 0);
635
636#ifdef Q_OS_WIN
637 serverSocket->write(buffer, readBufferSize);
638 QVERIFY(serverSocket->waitForBytesWritten());
639
640 // ensure the read completion routine is called
641 SleepEx(100, true);
642 QVERIFY(client.waitForReadyRead());
643 QCOMPARE(client.read(buffer, readBufferSize), qint64(readBufferSize));
644
645 // Test overflow caused by an asynchronous pipe operation.
646 client.setReadBufferSize(1);
647 serverSocket->write(buffer, 2);
648
649 QVERIFY(client.waitForReadyRead());
650 // socket disconnects, if there any error on pipe
651 QCOMPARE(client.state(), QLocalSocket::ConnectedState);
652 QCOMPARE(client.bytesAvailable(), qint64(2));
653 QCOMPARE(client.read(buffer, 2), qint64(2));
654#endif
655}
656
657static qint64 writeCommand(const QVariant &command, QIODevice *device, int commandCounter)
658{
659 QByteArray block;
660 QDataStream out(&block, QIODevice::WriteOnly);
661 out << qint64(0);
662 out << commandCounter;
663 out << command;
664 out.device()->seek(pos: 0);
665 out << qint64(block.size() - sizeof(qint64));
666 return device->write(data: block);
667}
668
669static QVariant readCommand(QIODevice *ioDevice, int *readCommandCounter, bool readSize = true)
670{
671 QDataStream in(ioDevice);
672 qint64 blockSize;
673 int commandCounter;
674 if (readSize)
675 in >> blockSize;
676 in >> commandCounter;
677 *readCommandCounter = commandCounter;
678
679 QVariant command;
680 in >> command;
681
682 return command;
683}
684
685void tst_QLocalSocket::simpleCommandProtocol1()
686{
687 QLocalServer server;
688 server.listen(QStringLiteral("simpleProtocol"));
689
690 QLocalSocket localSocketWrite;
691 localSocketWrite.connectToServer(name: server.serverName());
692 QVERIFY(server.waitForNewConnection());
693 QLocalSocket *localSocketRead = server.nextPendingConnection();
694 QVERIFY(localSocketRead);
695
696 int readCounter = 0;
697 for (int i = 0; i < 2000; ++i) {
698 const QVariant command(QRect(readCounter, i, 10, 10));
699 const qint64 blockSize = writeCommand(command, device: &localSocketWrite, commandCounter: i);
700 while (localSocketWrite.bytesToWrite())
701 QVERIFY(localSocketWrite.waitForBytesWritten());
702 while (localSocketRead->bytesAvailable() < blockSize) {
703 QVERIFY(localSocketRead->waitForReadyRead(1000));
704 }
705 const QVariant variant = readCommand(ioDevice: localSocketRead, readCommandCounter: &readCounter);
706 QCOMPARE(readCounter, i);
707 QCOMPARE(variant, command);
708 }
709}
710
711void tst_QLocalSocket::simpleCommandProtocol2()
712{
713 QLocalServer server;
714 server.listen(QStringLiteral("simpleProtocol"));
715
716 QLocalSocket localSocketWrite;
717 localSocketWrite.connectToServer(name: server.serverName());
718 QVERIFY(server.waitForNewConnection());
719 QLocalSocket* localSocketRead = server.nextPendingConnection();
720 QVERIFY(localSocketRead);
721
722 int readCounter = 0;
723 qint64 writtenBlockSize = 0;
724 qint64 blockSize = 0;
725
726 QObject::connect(sender: localSocketRead, signal: &QLocalSocket::readyRead, slot: [&] {
727 forever {
728 if (localSocketRead->bytesAvailable() < qint64(sizeof(qint64)))
729 return;
730
731 if (blockSize == 0) {
732 QDataStream in(localSocketRead);
733 in >> blockSize;
734 }
735
736 if (localSocketRead->bytesAvailable() < blockSize)
737 return;
738
739 int commandNumber = 0;
740 const QVariant variant = readCommand(ioDevice: localSocketRead, readCommandCounter: &commandNumber, readSize: false);
741 QCOMPARE(writtenBlockSize, blockSize);
742 QCOMPARE(readCounter, commandNumber);
743 QCOMPARE(variant.userType(), (int)QMetaType::QRect);
744
745 readCounter++;
746 blockSize = 0;
747 }
748 });
749
750 for (int i = 0; i < 500; ++i) {
751 const QVariant command(QRect(readCounter, i, 10, 10));
752 writtenBlockSize = writeCommand(command, device: &localSocketWrite, commandCounter: i) - sizeof(qint64);
753 if (i % 10 == 0)
754 QTest::qWait(ms: 1);
755 }
756
757 localSocketWrite.abort();
758 QVERIFY(localSocketRead->waitForDisconnected(1000));
759}
760
761// QLocalSocket/Server can take a name or path, check that it works as expected
762void tst_QLocalSocket::fullPath()
763{
764 QLocalServer server;
765 QString name = "qlocalsocket_pathtest";
766#if defined(QT_LOCALSOCKET_TCP)
767 QString path = "QLocalServer";
768#elif defined(Q_OS_WIN)
769 QString path = "\\\\.\\pipe\\";
770#else
771 QString path = "/tmp";
772#endif
773 QString serverName = path + '/' + name;
774 QVERIFY2(server.listen(serverName), server.errorString().toLatin1().constData());
775 QCOMPARE(server.serverName(), serverName);
776 QCOMPARE(server.fullServerName(), serverName);
777
778 LocalSocket socket;
779 socket.connectToServer(name: serverName);
780
781 QCOMPARE(socket.serverName(), serverName);
782 QCOMPARE(socket.fullServerName(), serverName);
783 socket.disconnectFromServer();
784#ifdef QT_LOCALSOCKET_TCP
785 QTest::qWait(250);
786#endif
787 QCOMPARE(socket.serverName(), QString());
788 QCOMPARE(socket.fullServerName(), QString());
789}
790
791void tst_QLocalSocket::hitMaximumConnections_data()
792{
793 QTest::addColumn<int>(name: "max");
794 QTest::newRow(dataTag: "none") << 0;
795 QTest::newRow(dataTag: "1") << 1;
796 QTest::newRow(dataTag: "3") << 3;
797}
798
799void tst_QLocalSocket::hitMaximumConnections()
800{
801 QFETCH(int, max);
802 LocalServer server;
803 QString name = "tst_localsocket";
804 server.setMaxPendingConnections(max);
805 QVERIFY2(server.listen(name), server.errorString().toLatin1().constData());
806 int connections = server.maxPendingConnections() + 1;
807 QList<QLocalSocket*> sockets;
808 for (int i = 0; i < connections; ++i) {
809 LocalSocket *socket = new LocalSocket;
810 sockets.append(t: socket);
811 socket->connectToServer(name);
812 }
813 bool timedOut = true;
814 QVERIFY(server.waitForNewConnection(3000, &timedOut));
815 QVERIFY(!timedOut);
816 QVERIFY(server.hits.count() > 0);
817 qDeleteAll(begin: sockets.begin(), end: sockets.end());
818}
819
820// check that state and mode are kept
821void tst_QLocalSocket::setSocketDescriptor()
822{
823 LocalSocket socket;
824 qintptr minusOne = -1;
825 socket.setSocketDescriptor(socketDescriptor: minusOne, socketState: QLocalSocket::ConnectingState, openMode: QIODevice::Append);
826 QCOMPARE(socket.socketDescriptor(), minusOne);
827 QCOMPARE(socket.state(), QLocalSocket::ConnectingState);
828 QVERIFY((socket.openMode() & QIODevice::Append) != 0);
829}
830
831class Client : public QThread
832{
833
834public:
835 void run()
836 {
837 QString testLine = "test";
838 LocalSocket socket;
839 QSignalSpy spyReadyRead(&socket, SIGNAL(readyRead()));
840 socket.connectToServer(name: "qlocalsocket_threadtest");
841 QVERIFY(socket.waitForConnected(1000));
842
843 // We should *not* have this signal yet!
844 QCOMPARE(spyReadyRead.count(), 0);
845 socket.waitForReadyRead();
846 QCOMPARE(spyReadyRead.count(), 1);
847 QTextStream in(&socket);
848 QCOMPARE(in.readLine(), testLine);
849 socket.close();
850 }
851};
852
853class Server : public QThread
854{
855
856public:
857 int clients;
858 QMutex mutex;
859 QWaitCondition wc;
860 void run()
861 {
862 QString testLine = "test";
863 LocalServer server;
864 server.setMaxPendingConnections(10);
865 QVERIFY2(server.listen("qlocalsocket_threadtest"),
866 server.errorString().toLatin1().constData());
867 mutex.lock();
868 wc.wakeAll();
869 mutex.unlock();
870 int done = clients;
871 while (done > 0) {
872 bool timedOut = true;
873 QVERIFY2(server.waitForNewConnection(7000, &timedOut),
874 (QByteArrayLiteral("done=") + QByteArray::number(done)
875 + QByteArrayLiteral(", timedOut=")
876 + (timedOut ? "true" : "false")).constData());
877 QVERIFY(!timedOut);
878 QLocalSocket *serverSocket = server.nextPendingConnection();
879 QVERIFY(serverSocket);
880 QTextStream out(serverSocket);
881 out << testLine << Qt::endl;
882 QCOMPARE(serverSocket->state(), QLocalSocket::ConnectedState);
883 QVERIFY2(serverSocket->waitForBytesWritten(), serverSocket->errorString().toLatin1().constData());
884 QCOMPARE(serverSocket->errorString(), QString("Unknown error"));
885 --done;
886 delete serverSocket;
887 }
888 QCOMPARE(server.hits.count(), clients);
889 }
890};
891
892void tst_QLocalSocket::threadedConnection_data()
893{
894 QTest::addColumn<int>(name: "threads");
895 QTest::newRow(dataTag: "1 client") << 1;
896 QTest::newRow(dataTag: "2 clients") << 2;
897 QTest::newRow(dataTag: "5 clients") << 5;
898 QTest::newRow(dataTag: "10 clients") << 10;
899 QTest::newRow(dataTag: "20 clients") << 20;
900}
901
902void tst_QLocalSocket::threadedConnection()
903{
904 QFETCH(int, threads);
905 Server server;
906 server.clients = threads;
907 server.mutex.lock();
908 server.start();
909 server.wc.wait(lockedMutex: &server.mutex);
910 server.mutex.unlock();
911
912 QList<Client*> clients;
913 for (int i = 0; i < threads; ++i) {
914 clients.append(t: new Client());
915 clients.last()->start();
916 }
917
918 server.wait();
919 while (!clients.isEmpty()) {
920 QVERIFY(clients.first()->wait(3000));
921 delete clients.takeFirst();
922 }
923}
924
925void tst_QLocalSocket::processConnection_data()
926{
927 QTest::addColumn<int>(name: "processes");
928 QTest::newRow(dataTag: "1 client") << 1;
929 QTest::newRow(dataTag: "2 clients") << 2;
930 QTest::newRow(dataTag: "5 clients") << 5;
931 QTest::newRow(dataTag: "30 clients") << 30;
932}
933
934#if QT_CONFIG(process)
935class ProcessOutputDumper
936{
937public:
938 ProcessOutputDumper(QProcess *p = 0)
939 : process(p)
940 {}
941
942 ~ProcessOutputDumper()
943 {
944 if (process)
945 fputs(s: process->readAll().data(), stdout);
946 }
947
948 void clear()
949 {
950 process = 0;
951 }
952
953private:
954 QProcess *process;
955};
956#endif
957
958/*!
959 Create external processes that produce and consume.
960 */
961void tst_QLocalSocket::processConnection()
962{
963#if !QT_CONFIG(process)
964 QSKIP("No qprocess support", SkipAll);
965#else
966
967#ifdef Q_OS_WIN
968 const QString exeSuffix = QStringLiteral(".exe");
969#else
970 const QString exeSuffix;
971#endif
972
973 const QString socketProcess
974 = QFINDTESTDATA(QStringLiteral("socketprocess/socketprocess") + exeSuffix);
975 QVERIFY(QFile::exists(socketProcess));
976
977 QFETCH(int, processes);
978 QStringList serverArguments = QStringList() << "--server" << QString::number(processes);
979 QProcess producer;
980 ProcessOutputDumper producerOutputDumper(&producer);
981 QList<QProcess*> consumers;
982 producer.setProcessChannelMode(QProcess::MergedChannels);
983 producer.start(program: socketProcess, arguments: serverArguments);
984 QVERIFY2(producer.waitForStarted(-1), qPrintable(producer.errorString()));
985 for (int i = 0; i < processes; ++i) {
986 QStringList arguments = QStringList() << "--client";
987 QProcess *p = new QProcess;
988 consumers.append(t: p);
989 p->setProcessChannelMode(QProcess::MergedChannels);
990 p->start(program: socketProcess, arguments);
991 }
992
993 while (!consumers.isEmpty()) {
994 QProcess *consumer = consumers.takeFirst();
995 ProcessOutputDumper consumerOutputDumper(consumer);
996 consumer->waitForFinished(msecs: 20000);
997 QCOMPARE(consumer->exitStatus(), QProcess::NormalExit);
998 QCOMPARE(consumer->exitCode(), 0);
999 consumerOutputDumper.clear();
1000 consumer->terminate();
1001 delete consumer;
1002 }
1003 producer.waitForFinished(msecs: 15000);
1004 producerOutputDumper.clear();
1005#endif
1006}
1007
1008void tst_QLocalSocket::longPath()
1009{
1010#ifndef Q_OS_WIN
1011 QString name;
1012 for (int i = 0; i < 256; ++i)
1013 name += 'a';
1014 LocalServer server;
1015 QVERIFY(!server.listen(name));
1016
1017 LocalSocket socket;
1018 socket.connectToServer(name);
1019 QCOMPARE(socket.state(), QLocalSocket::UnconnectedState);
1020#endif
1021}
1022
1023void tst_QLocalSocket::waitForDisconnect()
1024{
1025 QString name = "tst_localsocket";
1026 LocalServer server;
1027 QVERIFY(server.listen(name));
1028 LocalSocket socket;
1029 socket.connectToServer(name);
1030 QVERIFY(socket.waitForConnected(3000));
1031 QVERIFY(server.waitForNewConnection(3000));
1032 QLocalSocket *serverSocket = server.nextPendingConnection();
1033 QVERIFY(serverSocket);
1034 socket.disconnectFromServer();
1035 QElapsedTimer timer;
1036 timer.start();
1037 QVERIFY(serverSocket->waitForDisconnected(3000));
1038 QVERIFY(timer.elapsed() < 2000);
1039}
1040
1041void tst_QLocalSocket::waitForDisconnectByServer()
1042{
1043 QString name = "tst_localsocket";
1044 LocalServer server;
1045 QVERIFY(server.listen(name));
1046 LocalSocket socket;
1047 QSignalSpy spy(&socket, SIGNAL(disconnected()));
1048 QVERIFY(spy.isValid());
1049 socket.connectToServer(name);
1050 QVERIFY(socket.waitForConnected(3000));
1051 QVERIFY(server.waitForNewConnection(3000));
1052 QLocalSocket *serverSocket = server.nextPendingConnection();
1053 QVERIFY(serverSocket);
1054 serverSocket->close();
1055 QCOMPARE(serverSocket->state(), QLocalSocket::UnconnectedState);
1056 QVERIFY(socket.waitForDisconnected(3000));
1057 QCOMPARE(spy.count(), 1);
1058}
1059
1060void tst_QLocalSocket::removeServer()
1061{
1062 // this is a hostile takeover, but recovering from a crash results in the same
1063 QLocalServer server, server2;
1064 QVERIFY(QLocalServer::removeServer("cleanuptest"));
1065 QVERIFY(server.listen("cleanuptest"));
1066#ifndef Q_OS_WIN
1067 // on Windows, there can be several sockets listening on the same pipe
1068 // on Unix, there can only be one socket instance
1069 QVERIFY(! server2.listen("cleanuptest"));
1070#endif
1071 QVERIFY(QLocalServer::removeServer("cleanuptest"));
1072 QVERIFY(server2.listen("cleanuptest"));
1073}
1074
1075void tst_QLocalSocket::recycleServer()
1076{
1077 QLocalServer server;
1078 QLocalSocket client;
1079
1080 QVERIFY(server.listen("recycletest1"));
1081 client.connectToServer(name: "recycletest1");
1082 QVERIFY(client.waitForConnected(201));
1083 QVERIFY(server.waitForNewConnection(201));
1084 QVERIFY(server.nextPendingConnection() != 0);
1085
1086 server.close();
1087 client.disconnectFromServer();
1088 qApp->processEvents();
1089
1090 QVERIFY(server.listen("recycletest2"));
1091 client.connectToServer(name: "recycletest2");
1092 QVERIFY(client.waitForConnected(202));
1093 QVERIFY(server.waitForNewConnection(202));
1094 QVERIFY(server.nextPendingConnection() != 0);
1095}
1096
1097void tst_QLocalSocket::recycleClientSocket()
1098{
1099 const QByteArrayList lines = QByteArrayList() << "Have you heard of that new band"
1100 << "\"1023 Megabytes\"?"
1101 << "They haven't made it to a gig yet.";
1102 QLocalServer server;
1103 const QString serverName = QStringLiteral("recycleClientSocket");
1104 QVERIFY(server.listen(serverName));
1105 QLocalSocket client;
1106 QSignalSpy clientReadyReadSpy(&client, SIGNAL(readyRead()));
1107 QSignalSpy clientErrorSpy(&client, SIGNAL(errorOccurred(QLocalSocket::LocalSocketError)));
1108 for (int i = 0; i < lines.count(); ++i) {
1109 client.abort();
1110 clientReadyReadSpy.clear();
1111 client.connectToServer(name: serverName);
1112 QVERIFY(client.waitForConnected());
1113 QVERIFY(server.waitForNewConnection());
1114 QLocalSocket *serverSocket = server.nextPendingConnection();
1115 QVERIFY(serverSocket);
1116 connect(sender: serverSocket, signal: &QLocalSocket::disconnected, slot: &QLocalSocket::deleteLater);
1117 serverSocket->write(data: lines.at(i));
1118 serverSocket->flush();
1119 QVERIFY(clientReadyReadSpy.wait());
1120 QCOMPARE(client.readAll(), lines.at(i));
1121 QVERIFY(clientErrorSpy.isEmpty());
1122 }
1123}
1124
1125void tst_QLocalSocket::multiConnect()
1126{
1127 QLocalServer server;
1128 QLocalSocket client1;
1129 QLocalSocket client2;
1130 QLocalSocket client3;
1131
1132 QVERIFY(server.listen("multiconnect"));
1133
1134 client1.connectToServer(name: "multiconnect");
1135 client2.connectToServer(name: "multiconnect");
1136 client3.connectToServer(name: "multiconnect");
1137
1138 QVERIFY(client1.waitForConnected(201));
1139 QVERIFY(client2.waitForConnected(202));
1140 QVERIFY(client3.waitForConnected(203));
1141
1142 QVERIFY(server.waitForNewConnection(201));
1143 QVERIFY(server.nextPendingConnection() != 0);
1144 QVERIFY(server.waitForNewConnection(202));
1145 QVERIFY(server.nextPendingConnection() != 0);
1146 QVERIFY(server.waitForNewConnection(203));
1147 QVERIFY(server.nextPendingConnection() != 0);
1148}
1149
1150void tst_QLocalSocket::writeOnlySocket()
1151{
1152 QLocalServer server;
1153 QVERIFY(server.listen("writeOnlySocket"));
1154
1155 QLocalSocket client;
1156 client.connectToServer(name: "writeOnlySocket", openMode: QIODevice::WriteOnly);
1157 QVERIFY(client.waitForConnected());
1158 QVERIFY(server.waitForNewConnection(200));
1159 QLocalSocket* serverSocket = server.nextPendingConnection();
1160 QVERIFY(serverSocket);
1161
1162 QCOMPARE(client.bytesAvailable(), qint64(0));
1163 QCOMPARE(client.state(), QLocalSocket::ConnectedState);
1164}
1165
1166void tst_QLocalSocket::writeToClientAndDisconnect_data()
1167{
1168 QTest::addColumn<int>(name: "chunks");
1169 QTest::newRow(dataTag: "one chunk") << 1;
1170 QTest::newRow(dataTag: "several chunks") << 20;
1171}
1172
1173void tst_QLocalSocket::writeToClientAndDisconnect()
1174{
1175 QFETCH(int, chunks);
1176 QLocalServer server;
1177 QLocalSocket client;
1178 QSignalSpy readChannelFinishedSpy(&client, SIGNAL(readChannelFinished()));
1179
1180 QVERIFY(server.listen("writeAndDisconnectServer"));
1181 client.connectToServer(name: "writeAndDisconnectServer");
1182 QVERIFY(client.waitForConnected(200));
1183 QVERIFY(server.waitForNewConnection(200));
1184 QLocalSocket* clientSocket = server.nextPendingConnection();
1185 QVERIFY(clientSocket);
1186
1187 char buffer[100];
1188 memset(s: buffer, c: 0, n: sizeof(buffer));
1189 for (int i = 0; i < chunks; ++i)
1190 QCOMPARE(clientSocket->write(buffer, sizeof(buffer)), qint64(sizeof(buffer)));
1191 while (clientSocket->bytesToWrite())
1192 QVERIFY(clientSocket->waitForBytesWritten());
1193 clientSocket->close();
1194 server.close();
1195
1196 client.waitForDisconnected();
1197 QCOMPARE(readChannelFinishedSpy.count(), 1);
1198 const QByteArray received = client.readAll();
1199 QCOMPARE(received.size(), qint64(sizeof(buffer) * chunks));
1200 QCOMPARE(client.state(), QLocalSocket::UnconnectedState);
1201}
1202
1203void tst_QLocalSocket::debug()
1204{
1205 // Make sure this compiles
1206 if (QLoggingCategory::defaultCategory()->isDebugEnabled())
1207 QTest::ignoreMessage(type: QtDebugMsg, message: "QLocalSocket::ConnectionRefusedError QLocalSocket::UnconnectedState");
1208 qDebug() << QLocalSocket::ConnectionRefusedError << QLocalSocket::UnconnectedState;
1209}
1210
1211class WriteThread : public QThread
1212{
1213Q_OBJECT
1214public:
1215 void run() {
1216 QLocalSocket socket;
1217 socket.connectToServer(name: "qlocalsocket_readyread");
1218
1219 if (!socket.waitForConnected(msecs: 3000))
1220 exec();
1221 connect(sender: &socket, SIGNAL(bytesWritten(qint64)),
1222 receiver: this, SLOT(bytesWritten(qint64)), Qt::QueuedConnection);
1223 socket.write(data: "testing\n");
1224 exec();
1225 }
1226signals:
1227 void bytesWrittenReceived();
1228public slots:
1229 void bytesWritten(qint64) {
1230 emit bytesWrittenReceived();
1231 exit();
1232 }
1233};
1234
1235/*
1236 Tests the emission of the bytesWritten(qint64)
1237 signal.
1238
1239 Create a thread that will write to a socket.
1240 If the bytesWritten(qint64) signal is generated,
1241 the slot connected to it will exit the thread,
1242 indicating test success.
1243
1244*/
1245void tst_QLocalSocket::bytesWrittenSignal()
1246{
1247 QLocalServer server;
1248 QVERIFY(server.listen("qlocalsocket_readyread"));
1249 WriteThread writeThread;
1250 QSignalSpy receivedSpy(&writeThread, &WriteThread::bytesWrittenReceived);
1251 writeThread.start();
1252 bool timedOut = false;
1253 QVERIFY(server.waitForNewConnection(3000, &timedOut));
1254 QVERIFY(!timedOut);
1255 QVERIFY(receivedSpy.wait(2000));
1256 QVERIFY(writeThread.wait(2000));
1257}
1258
1259void tst_QLocalSocket::syncDisconnectNotify()
1260{
1261 QLocalServer server;
1262 QVERIFY(server.listen("syncDisconnectNotify"));
1263 QLocalSocket client;
1264 client.connectToServer(name: "syncDisconnectNotify");
1265 QVERIFY(server.waitForNewConnection());
1266 QLocalSocket* serverSocket = server.nextPendingConnection();
1267 QVERIFY(serverSocket);
1268 delete serverSocket;
1269 QCOMPARE(client.waitForReadyRead(), false);
1270 QVERIFY(!client.putChar(0));
1271}
1272
1273void tst_QLocalSocket::asyncDisconnectNotify()
1274{
1275 QLocalServer server;
1276 QVERIFY(server.listen("asyncDisconnectNotify"));
1277 QLocalSocket client;
1278 QSignalSpy disconnectedSpy(&client, SIGNAL(disconnected()));
1279 client.connectToServer(name: "asyncDisconnectNotify");
1280 QVERIFY(server.waitForNewConnection());
1281 QLocalSocket* serverSocket = server.nextPendingConnection();
1282 QVERIFY(serverSocket);
1283 delete serverSocket;
1284 QTRY_VERIFY(!disconnectedSpy.isEmpty());
1285}
1286
1287void tst_QLocalSocket::verifySocketOptions_data()
1288{
1289#ifdef Q_OS_LINUX
1290 QTest::addColumn<QString>(name: "service");
1291 QTest::addColumn<QLocalServer::SocketOption>(name: "opts");
1292 QTest::addColumn<QFile::Permissions>(name: "perms");
1293
1294 QFile::Permissions p = QFile::ExeOwner|QFile::WriteOwner|QFile::ReadOwner |
1295 QFile::ExeUser|QFile::WriteUser|QFile::ReadUser;
1296 QTest::newRow(dataTag: "user") << "userPerms" << QLocalServer::UserAccessOption << p;
1297
1298 p = QFile::ExeGroup|QFile::WriteGroup|QFile::ReadGroup;
1299 QTest::newRow(dataTag: "group") << "groupPerms" << QLocalServer::GroupAccessOption << p;
1300
1301 p = QFile::ExeOther|QFile::WriteOther|QFile::ReadOther;
1302 QTest::newRow(dataTag: "other") << "otherPerms" << QLocalServer::OtherAccessOption << p;
1303
1304 p = QFile::ExeOwner|QFile::WriteOwner|QFile::ReadOwner|
1305 QFile::ExeUser|QFile::WriteUser|QFile::ReadUser |
1306 QFile::ExeGroup|QFile::WriteGroup|QFile::ReadGroup|
1307 QFile::ExeOther|QFile::WriteOther|QFile::ReadOther;
1308 QTest::newRow(dataTag: "all") << "worldPerms" << QLocalServer::WorldAccessOption << p;
1309#endif
1310}
1311
1312void tst_QLocalSocket::verifySocketOptions()
1313{
1314 // These are only guaranteed to be useful on linux at this time
1315#ifdef Q_OS_LINUX
1316 QFETCH(QString, service);
1317 QFETCH(QLocalServer::SocketOption, opts);
1318 QFETCH(QFile::Permissions, perms);
1319
1320
1321 QLocalServer::removeServer(name: service);
1322 QLocalServer server;
1323 server.setSocketOptions(opts);
1324 QVERIFY2(server.listen(service), "service failed to start listening");
1325
1326 // find the socket
1327 QString fullServerPath = QDir::cleanPath(path: QDir::tempPath());
1328 fullServerPath += QLatin1Char('/') + service;
1329
1330 QFile socketFile(fullServerPath);
1331 QVERIFY2(perms == socketFile.permissions(), "permissions on the socket don't match");
1332#endif
1333}
1334
1335void tst_QLocalSocket::verifyListenWithDescriptor()
1336{
1337#ifdef Q_OS_UNIX
1338 QFETCH(QString, path);
1339 QFETCH(bool, abstract);
1340 QFETCH(bool, bound);
1341
1342// qDebug() << "socket" << path << abstract;
1343
1344 int listenSocket;
1345
1346 if (bound) {
1347 // create the unix socket
1348 listenSocket = ::socket(PF_UNIX, SOCK_STREAM, protocol: 0);
1349 QVERIFY2(listenSocket != -1, "failed to create test socket");
1350
1351 // Construct the unix address
1352 struct ::sockaddr_un addr;
1353 addr.sun_family = PF_UNIX;
1354
1355 QVERIFY2(sizeof(addr.sun_path) > ((uint)path.size() + 1), "path to large to create socket");
1356
1357 ::memset(s: addr.sun_path, c: 0, n: sizeof(addr.sun_path));
1358 if (abstract)
1359 ::memcpy(dest: addr.sun_path+1, src: path.toLatin1().data(), n: path.toLatin1().size());
1360 else
1361 ::memcpy(dest: addr.sun_path, src: path.toLatin1().data(), n: path.toLatin1().size());
1362
1363 if (path.startsWith(c: QLatin1Char('/'))) {
1364 ::unlink(name: path.toLatin1());
1365 }
1366
1367 QVERIFY2(-1 != ::bind(listenSocket, (sockaddr *)&addr, sizeof(sockaddr_un)), "failed to bind test socket to address");
1368
1369 // listen for connections
1370 QVERIFY2(-1 != ::listen(listenSocket, 50), "failed to call listen on test socket");
1371 } else {
1372 int fds[2];
1373 QVERIFY2(-1 != ::socketpair(PF_UNIX, SOCK_STREAM, 0, fds), "failed to create socket pair");
1374
1375 listenSocket = fds[0];
1376 close(fd: fds[1]);
1377 }
1378
1379 QLocalServer server;
1380 QVERIFY2(server.listen(listenSocket), "failed to start create QLocalServer with local socket");
1381
1382#ifdef Q_OS_LINUX
1383 const QChar at(QLatin1Char('@'));
1384 if (!bound) {
1385 QCOMPARE(server.serverName().at(0), at);
1386 QCOMPARE(server.fullServerName().at(0), at);
1387 } else if (abstract) {
1388 QVERIFY2(server.fullServerName().at(0) == at, "abstract sockets should start with a '@'");
1389 } else {
1390 QCOMPARE(server.fullServerName(), path);
1391 if (path.contains(c: QLatin1Char('/'))) {
1392 QVERIFY2(server.serverName() == path.mid(path.lastIndexOf(QLatin1Char('/'))+1), "server name invalid short name");
1393 } else {
1394 QVERIFY2(server.serverName() == path, "servier name doesn't match the path provided");
1395 }
1396 }
1397#else
1398 QVERIFY(server.serverName().isEmpty());
1399 QVERIFY(server.fullServerName().isEmpty());
1400#endif
1401
1402
1403#endif
1404}
1405
1406void tst_QLocalSocket::verifyListenWithDescriptor_data()
1407{
1408#ifdef Q_OS_UNIX
1409 QTest::addColumn<QString>(name: "path");
1410 QTest::addColumn<bool>(name: "abstract");
1411 QTest::addColumn<bool>(name: "bound");
1412
1413 QTest::newRow(dataTag: "normal") << QDir::tempPath() + QLatin1String("/testsocket") << false << true;
1414#ifdef Q_OS_LINUX
1415 QTest::newRow(dataTag: "abstract") << QString::fromLatin1(str: "abstractsocketname") << true << true;
1416 QTest::newRow(dataTag: "abstractwithslash") << QString::fromLatin1(str: "abstractsocketwitha/inthename") << true << true;
1417#endif
1418 QTest::newRow(dataTag: "no path") << QString::fromLatin1(str: "/invalid/no path name specified") << true << false;
1419
1420#endif
1421
1422}
1423
1424QTEST_MAIN(tst_QLocalSocket)
1425#include "tst_qlocalsocket.moc"
1426
1427

source code of qtbase/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp