1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <private/qqmldebugserverconnection_p.h>
5#include <private/qqmldebugserver_p.h>
6
7#include <QtCore/qplugin.h>
8#include <QtNetwork/qtcpserver.h>
9#include <QtNetwork/qtcpsocket.h>
10
11QT_BEGIN_NAMESPACE
12
13class QTcpServerConnection : public QQmlDebugServerConnection
14{
15 Q_OBJECT
16 Q_DISABLE_COPY(QTcpServerConnection)
17
18public:
19 QTcpServerConnection();
20 ~QTcpServerConnection() override;
21
22 void setServer(QQmlDebugServer *server) override;
23 bool setPortRange(int portFrom, int portTo, bool block, const QString &hostaddress) override;
24 bool setFileName(const QString &fileName, bool block) override;
25
26 bool isConnected() const override;
27 void disconnect() override;
28
29 void waitForConnection() override;
30 void flush() override;
31
32private:
33 void newConnection();
34 bool listen();
35
36 int m_portFrom = 0;
37 int m_portTo = 0;
38 bool m_block = false;
39 QString m_hostaddress;
40 QTcpSocket *m_socket = nullptr;
41 QTcpServer *m_tcpServer = nullptr;
42 QQmlDebugServer *m_debugServer = nullptr;
43};
44
45QTcpServerConnection::QTcpServerConnection() {}
46
47QTcpServerConnection::~QTcpServerConnection()
48{
49 if (isConnected())
50 disconnect();
51}
52
53void QTcpServerConnection::setServer(QQmlDebugServer *server)
54{
55 m_debugServer = server;
56}
57
58bool QTcpServerConnection::isConnected() const
59{
60 return m_socket && m_socket->state() == QTcpSocket::ConnectedState;
61}
62
63void QTcpServerConnection::disconnect()
64{
65 while (m_socket && m_socket->bytesToWrite() > 0) {
66 if (!m_socket->waitForBytesWritten()) {
67 qWarning(msg: "QML Debugger: Failed to send remaining %lld bytes on disconnect.",
68 m_socket->bytesToWrite());
69 break;
70 }
71 }
72
73 m_socket->deleteLater();
74 m_socket = nullptr;
75}
76
77bool QTcpServerConnection::setPortRange(int portFrom, int portTo, bool block,
78 const QString &hostaddress)
79{
80 m_portFrom = portFrom;
81 m_portTo = portTo;
82 m_block = block;
83 m_hostaddress = hostaddress;
84
85 return listen();
86}
87
88bool QTcpServerConnection::setFileName(const QString &fileName, bool block)
89{
90 Q_UNUSED(fileName);
91 Q_UNUSED(block);
92 return false;
93}
94
95void QTcpServerConnection::waitForConnection()
96{
97 m_tcpServer->waitForNewConnection(msec: -1);
98}
99
100void QTcpServerConnection::flush()
101{
102 if (m_socket)
103 m_socket->flush();
104}
105
106bool QTcpServerConnection::listen()
107{
108 m_tcpServer = new QTcpServer(this);
109 QObject::connect(sender: m_tcpServer, signal: &QTcpServer::newConnection,
110 context: this, slot: &QTcpServerConnection::newConnection);
111 QHostAddress hostaddress;
112 if (!m_hostaddress.isEmpty()) {
113 if (!hostaddress.setAddress(m_hostaddress)) {
114 hostaddress = QHostAddress::Any;
115 qDebug(msg: "QML Debugger: Incorrect host address provided. So accepting connections "
116 "from any host.");
117 }
118 } else {
119 hostaddress = QHostAddress::Any;
120 }
121 int port = m_portFrom;
122 do {
123 if (m_tcpServer->listen(address: hostaddress, port)) {
124 qDebug(msg: "QML Debugger: Waiting for connection on port %d...", port);
125 break;
126 }
127 ++port;
128 } while (port <= m_portTo);
129 if (port > m_portTo) {
130 if (m_portFrom == m_portTo)
131 qWarning(msg: "QML Debugger: Unable to listen to port %d.", m_portFrom);
132 else
133 qWarning(msg: "QML Debugger: Unable to listen to ports %d - %d.", m_portFrom, m_portTo);
134 return false;
135 } else {
136 return true;
137 }
138}
139
140void QTcpServerConnection::newConnection()
141{
142 if (m_socket && m_socket->peerPort()) {
143 qWarning(msg: "QML Debugger: Another client is already connected.");
144 QTcpSocket *faultyConnection = m_tcpServer->nextPendingConnection();
145 delete faultyConnection;
146 return;
147 }
148
149 delete m_socket;
150 m_socket = m_tcpServer->nextPendingConnection();
151 m_socket->setParent(this);
152 m_debugServer->setDevice(m_socket);
153}
154
155
156class QTcpServerConnectionFactory : public QQmlDebugServerConnectionFactory
157{
158 Q_OBJECT
159 Q_PLUGIN_METADATA(IID QQmlDebugServerConnectionFactory_iid FILE "qtcpserverconnection.json")
160 Q_INTERFACES(QQmlDebugServerConnectionFactory)
161public:
162 QQmlDebugServerConnection *create(const QString &key) override;
163};
164
165QQmlDebugServerConnection *QTcpServerConnectionFactory::create(const QString &key)
166{
167 return (key == QLatin1String("QTcpServerConnection") ? new QTcpServerConnection : nullptr);
168}
169
170QT_END_NAMESPACE
171
172#include "qtcpserverconnection.moc"
173

source code of qtdeclarative/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp