1/****************************************************************************
2**
3** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtWebSocket module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qqmlwebsocketserver.h"
41#include "qqmlwebsocket.h"
42
43QT_USE_NAMESPACE
44
45/*!
46 \qmltype WebSocketServer
47 \instantiates QQmlWebSocketServer
48 \since 5.3
49
50 \inqmlmodule QtWebSockets
51 \ingroup websockets-qml
52 \brief QML interface to QWebSocketServer.
53*/
54
55/*!
56 \qmlproperty QUrl WebSocketServer::url
57 Server url that client WebSockets can connect to. The url uses the \e ws:// scheme and includes the
58 port the server listens to and the host address of the server.
59 */
60
61/*!
62 \qmlproperty QString WebSocketServer::host
63 The host address of the server. By default, localhost is used.
64 */
65
66/*!
67 \qmlproperty int WebSocketServer::port
68 The port this server is listening on. The value must be in the range 0-65535.
69
70 By default, a port is chosen automatically.
71 */
72
73/*!
74 \qmlproperty QString WebSocketServer::name
75 The name of this server used during the http handshake phase.
76 */
77
78/*!
79 \qmlproperty QString WebSocketServer::errorString
80 The stringified error message in case an error occurred.
81 */
82
83/*!
84 \qmlproperty bool WebSocketServer::listen
85 Set to true when the server should listen to client connections or false otherwise.
86 When set to true, the server will listen on the specified url defined by host and port
87 and, when accept is true, accepts incoming client connections. Otherwise the server is closed.
88 By default, the server is not listening.
89 */
90
91/*!
92 \qmlproperty bool WebSocketServer::accept
93 Set to true to accept incoming client connections when the server is listening. When set to false,
94 incoming connections are rejected. By default, connections are accepted.
95 */
96
97/*!
98 \qmlsignal WebSocketServer::clientConnected(WebSocket webSocket)
99 This signal is emitted when a client connects to this server. \a webSocket is the newly created \l [QML]{WebSocket}.
100 */
101
102QQmlWebSocketServer::QQmlWebSocketServer(QObject *parent)
103 : QObject(parent)
104 , m_host(QHostAddress(QHostAddress::LocalHost).toString())
105 , m_port(0)
106 , m_listen(false)
107 , m_accept(true)
108 , m_componentCompleted(true)
109{
110}
111
112QQmlWebSocketServer::~QQmlWebSocketServer()
113{
114
115}
116
117void QQmlWebSocketServer::classBegin()
118{
119 m_componentCompleted = false;
120}
121
122void QQmlWebSocketServer::componentComplete()
123{
124 init();
125 m_componentCompleted = true;
126}
127
128QUrl QQmlWebSocketServer::url() const
129{
130 QUrl url;
131 url.setPort(m_port);
132 url.setHost(host: m_host);
133 url.setScheme(QStringLiteral("ws"));
134 return url;
135}
136
137QString QQmlWebSocketServer::host() const
138{
139 return m_host;
140}
141
142void QQmlWebSocketServer::setHost(const QString &host)
143{
144 if (host == m_host) {
145 return;
146 }
147
148 m_host = host;
149 emit hostChanged(host);
150 emit urlChanged(url: url());
151
152 updateListening();
153}
154
155int QQmlWebSocketServer::port() const
156{
157 return m_port;
158}
159
160void QQmlWebSocketServer::setPort(int port)
161{
162 if (port == m_port) {
163 return;
164 }
165
166 if (port < 0 || port > 65535) {
167 qWarning() << "QQmlWebSocketServer::setPort: port " << port << " is invalid. It must be in the range 0-65535.";
168 return;
169 }
170 m_port = port;
171 emit portChanged(port);
172 emit urlChanged(url: url());
173
174 if (m_componentCompleted && m_server->isListening()) {
175 updateListening();
176 }
177}
178
179QString QQmlWebSocketServer::errorString() const
180{
181 return m_server ? m_server->errorString() : tr(s: "QQmlWebSocketServer is not ready.");
182}
183
184QString QQmlWebSocketServer::name() const
185{
186 return m_name;
187}
188
189void QQmlWebSocketServer::setName(const QString &name)
190{
191 if (name == m_name) {
192 return;
193 }
194
195 m_name = name;
196 emit nameChanged(name);
197
198 if (m_componentCompleted) {
199 init();
200 }
201}
202
203bool QQmlWebSocketServer::listen() const
204{
205 return m_listen;
206}
207
208void QQmlWebSocketServer::setListen(bool listen)
209{
210 if (listen == m_listen) {
211 return;
212 }
213
214 m_listen = listen;
215 emit listenChanged(listen);
216
217 updateListening();
218}
219
220bool QQmlWebSocketServer::accept() const
221{
222 return m_accept;
223}
224
225void QQmlWebSocketServer::setAccept(bool accept)
226{
227 if (accept == m_accept) {
228 return;
229 }
230
231 m_accept = accept;
232 emit acceptChanged(accept);
233
234 if (m_componentCompleted) {
235 if (!accept) {
236 m_server->pauseAccepting();
237 } else {
238 m_server->resumeAccepting();
239 }
240 }
241}
242
243void QQmlWebSocketServer::init()
244{
245 // TODO: add support for wss, requires ssl configuration to be set from QML - realistic?
246 m_server.reset(other: new QWebSocketServer(m_name, QWebSocketServer::NonSecureMode));
247
248 connect(sender: m_server.data(), signal: &QWebSocketServer::newConnection,
249 receiver: this, slot: &QQmlWebSocketServer::newConnection);
250 connect(sender: m_server.data(), signal: &QWebSocketServer::serverError,
251 receiver: this, slot: &QQmlWebSocketServer::serverError);
252 connect(sender: m_server.data(), signal: &QWebSocketServer::closed,
253 receiver: this, slot: &QQmlWebSocketServer::closed);
254
255 updateListening();
256}
257
258void QQmlWebSocketServer::updateListening()
259{
260 if (!m_server) {
261 return;
262 }
263
264 if (m_server->isListening()) {
265 m_server->close();
266 }
267
268 if (!m_listen || !m_server->listen(address: QHostAddress(m_host), port: m_port)) {
269 return;
270 }
271 setPort(m_server->serverPort());
272 setHost(m_server->serverAddress().toString());
273}
274
275void QQmlWebSocketServer::newConnection()
276{
277 emit clientConnected(webSocket: new QQmlWebSocket(m_server->nextPendingConnection(), this));
278}
279
280void QQmlWebSocketServer::serverError()
281{
282 emit errorStringChanged(errorString: errorString());
283}
284
285void QQmlWebSocketServer::closed()
286{
287 setListen(false);
288}
289
290

source code of qtwebsockets/src/imports/qmlwebsockets/qqmlwebsocketserver.cpp