1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the QtSerialBus module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL3$
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 http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free
28** Software Foundation and appearing in the file LICENSE.GPL included in
29** the packaging of this file. Please review the following information to
30** ensure the GNU General Public License version 2.0 requirements will be
31** met: http://www.gnu.org/licenses/gpl-2.0.html.
32**
33** $QT_END_LICENSE$
34**
35****************************************************************************/
36
37#include "qmodbustcpserver.h"
38#include "qmodbustcpserver_p.h"
39
40#include <QtCore/qurl.h>
41
42QT_BEGIN_NAMESPACE
43
44/*!
45 \class QModbusTcpServer
46 \inmodule QtSerialBus
47 \since 5.8
48
49 \brief The QModbusTcpServer class represents a Modbus server that uses a
50 TCP server for its communication with the Modbus client.
51
52 Communication via Modbus requires the interaction between a single Modbus
53 client instance and single Modbus server. This class provides the Modbus
54 server implementation via a TCP server.
55
56 Modbus TCP networks can have multiple servers. Servers are read/written by
57 a client device represented by \l QModbusTcpClient.
58*/
59
60/*!
61 Constructs a QModbusTcpServer with the specified \a parent. The
62 \l serverAddress preset is \c 255.
63*/
64QModbusTcpServer::QModbusTcpServer(QObject *parent)
65 : QModbusServer(*new QModbusTcpServerPrivate, parent)
66{
67 Q_D(QModbusTcpServer);
68 d->setupTcpServer();
69 setServerAddress(0xff);
70}
71
72/*!
73 Destroys the QModbusTcpServer instance.
74*/
75QModbusTcpServer::~QModbusTcpServer()
76{
77 close();
78}
79
80/*!
81 \internal
82*/
83QModbusTcpServer::QModbusTcpServer(QModbusTcpServerPrivate &dd, QObject *parent)
84 : QModbusServer(dd, parent)
85{
86 Q_D(QModbusTcpServer);
87 d->setupTcpServer();
88}
89
90/*!
91 \reimp
92*/
93bool QModbusTcpServer::open()
94{
95 if (state() == QModbusDevice::ConnectedState)
96 return true;
97
98 Q_D(QModbusTcpServer);
99 if (d->m_tcpServer->isListening())
100 return false;
101
102 const QUrl url = QUrl::fromUserInput(userInput: d->m_networkAddress + QStringLiteral(":")
103 + QString::number(d->m_networkPort));
104
105 if (!url.isValid()) {
106 setError(errorText: tr(s: "Invalid connection settings for TCP communication specified."),
107 error: QModbusDevice::ConnectionError);
108 qCWarning(QT_MODBUS) << "(TCP server) Invalid host:" << url.host() << "or port:"
109 << url.port();
110 return false;
111 }
112
113 if (d->m_tcpServer->listen(address: QHostAddress(url.host()), port: quint16(url.port())))
114 setState(QModbusDevice::ConnectedState);
115 else
116 setError(errorText: d->m_tcpServer->errorString(), error: QModbusDevice::ConnectionError);
117
118 return state() == QModbusDevice::ConnectedState;
119}
120
121/*!
122 \reimp
123*/
124void QModbusTcpServer::close()
125{
126 if (state() == QModbusDevice::UnconnectedState)
127 return;
128
129 Q_D(QModbusTcpServer);
130
131 if (d->m_tcpServer->isListening())
132 d->m_tcpServer->close();
133
134 for (auto socket : qAsConst(t&: d->connections))
135 socket->disconnectFromHost();
136
137 setState(QModbusDevice::UnconnectedState);
138}
139
140/*!
141 \reimp
142
143 Processes the Modbus client request specified by \a request and returns a
144 Modbus response.
145
146 The following Modbus function codes are filtered out as they are serial
147 line only according to the Modbus Application Protocol Specification 1.1b:
148 \list
149 \li \l QModbusRequest::ReadExceptionStatus
150 \li \l QModbusRequest::Diagnostics
151 \li \l QModbusRequest::GetCommEventCounter
152 \li \l QModbusRequest::GetCommEventLog
153 \li \l QModbusRequest::ReportServerId
154 \endlist
155 A request to the TCP server will be answered with a Modbus exception
156 response with the exception code QModbusExceptionResponse::IllegalFunction.
157*/
158QModbusResponse QModbusTcpServer::processRequest(const QModbusPdu &request)
159{
160 switch (request.functionCode()) {
161 case QModbusRequest::ReadExceptionStatus:
162 case QModbusRequest::Diagnostics:
163 case QModbusRequest::GetCommEventCounter:
164 case QModbusRequest::GetCommEventLog:
165 case QModbusRequest::ReportServerId:
166 return QModbusExceptionResponse(request.functionCode(),
167 QModbusExceptionResponse::IllegalFunction);
168 default:
169 break;
170 }
171 return QModbusServer::processRequest(request);
172}
173
174/*!
175 Installs an \a observer that can be used to obtain notifications when a
176 new TCP client connects to this server instance. In addition, the \a observer
177 can be used to reject the incoming TCP connection.
178
179 QModbusTcpServer takes ownership of the given \a observer. Any previously set
180 observer will be deleted. The observer can be uninstalled by calling this
181 function with \c nullptr as parameter.
182
183 \sa QModbusTcpConnectionObserver
184 \since 5.13
185*/
186void QModbusTcpServer::installConnectionObserver(QModbusTcpConnectionObserver *observer)
187{
188 Q_D(QModbusTcpServer);
189
190 d->m_observer.reset(p: observer);
191}
192
193/*!
194 \class QModbusTcpConnectionObserver
195 \inmodule QtSerialBus
196 \since 5.13
197
198 \brief The QModbusTcpConnectionObserver class represents the interface for
199 objects that can be passed to \l QModbusTcpServer::installConnectionObserver.
200
201 The interface must be implemented by the developer to be able to monitor
202 every incoming TCP connection from another Modbus client.
203
204 \sa QModbusTcpServer::installConnectionObserver
205*/
206
207QModbusTcpConnectionObserver::~QModbusTcpConnectionObserver()
208{
209}
210
211/*!
212 \fn bool QModbusTcpConnectionObserver::acceptNewConnection(QTcpSocket *newClient)
213
214 This function is a callback for every incoming TCP connection. The user should
215 provide \a newClient to receive a notification when a new client connection
216 is established and to determine whether the connection is to be accepted.
217
218 The function should return \c true if the connection is to be accepted. Otherwise,
219 the socket is closed/rejected.
220*/
221
222/*!
223 \fn void QModbusTcpServer::modbusClientDisconnected(QTcpSocket *modbusClient)
224
225 This signal is emitted when a current TCP based \a modbusClient disconnects
226 from this Modbus TCP server. Note that there might be several TCP clients
227 connected at the same time.
228
229 Notifications on incoming new connections can be received by installing a
230 QModbusTcpConnectionObserver via \l installConnectionObserver().
231
232 \sa installConnectionObserver
233 \since 5.13
234*/
235
236QT_END_NAMESPACE
237

source code of qtserialbus/src/serialbus/qmodbustcpserver.cpp