1/****************************************************************************
2**
3** Copyright (C) 2017 Ford Motor Company
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtRemoteObjects 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 "qconnection_tcpip_backend_p.h"
41
42#include <QtNetwork/qhostinfo.h>
43
44QT_BEGIN_NAMESPACE
45
46TcpClientIo::TcpClientIo(QObject *parent)
47 : ClientIoDevice(parent)
48 , m_socket(new QTcpSocket(this))
49{
50 connect(sender: m_socket, signal: &QTcpSocket::readyRead, receiver: this, slot: &ClientIoDevice::readyRead);
51 connect(sender: m_socket, signal: &QAbstractSocket::errorOccurred, receiver: this, slot: &TcpClientIo::onError);
52 connect(sender: m_socket, signal: &QTcpSocket::stateChanged, receiver: this, slot: &TcpClientIo::onStateChanged);
53}
54
55TcpClientIo::~TcpClientIo()
56{
57 close();
58}
59
60QIODevice *TcpClientIo::connection() const
61{
62 return m_socket;
63}
64
65void TcpClientIo::doClose()
66{
67 if (m_socket->isOpen()) {
68 connect(sender: m_socket, signal: &QTcpSocket::disconnected, receiver: this, slot: &QObject::deleteLater);
69 m_socket->disconnectFromHost();
70 } else {
71 this->deleteLater();
72 }
73}
74
75void TcpClientIo::doDisconnectFromServer()
76{
77 m_socket->disconnectFromHost();
78}
79
80void TcpClientIo::connectToServer()
81{
82 if (isOpen())
83 return;
84 QHostAddress address(url().host());
85 if (address.isNull()) {
86 const QList<QHostAddress> addresses = QHostInfo::fromName(name: url().host()).addresses();
87 Q_ASSERT_X(addresses.size() >= 1, Q_FUNC_INFO, url().toString().toLatin1().data());
88 address = addresses.first();
89 }
90
91 m_socket->connectToHost(address, port: url().port());
92}
93
94bool TcpClientIo::isOpen() const
95{
96 return (!isClosing() && (m_socket->state() == QAbstractSocket::ConnectedState
97 || m_socket->state() == QAbstractSocket::ConnectingState));
98}
99
100void TcpClientIo::onError(QAbstractSocket::SocketError error)
101{
102 qCDebug(QT_REMOTEOBJECT) << "onError" << error;
103
104 switch (error) {
105 case QAbstractSocket::HostNotFoundError: //Host not there, wait and try again
106 case QAbstractSocket::ConnectionRefusedError:
107 case QAbstractSocket::NetworkError:
108 emit shouldReconnect(this);
109 break;
110 case QAbstractSocket::AddressInUseError:
111 //... TODO error reporting
112 break;
113 default:
114 break;
115 }
116}
117
118void TcpClientIo::onStateChanged(QAbstractSocket::SocketState state)
119{
120 if (state == QAbstractSocket::ClosingState && !isClosing()) {
121 m_socket->abort();
122 emit shouldReconnect(this);
123 }
124 if (state == QAbstractSocket::ConnectedState)
125 initializeDataStream();
126}
127
128
129TcpServerIo::TcpServerIo(QTcpSocket *conn, QObject *parent)
130 : ServerIoDevice(parent), m_connection(conn)
131{
132 m_connection->setParent(this);
133 connect(sender: conn, signal: &QIODevice::readyRead, receiver: this, slot: &ServerIoDevice::readyRead);
134 connect(sender: conn, signal: &QAbstractSocket::disconnected, receiver: this, slot: &ServerIoDevice::disconnected);
135}
136
137QIODevice *TcpServerIo::connection() const
138{
139 return m_connection;
140}
141
142void TcpServerIo::doClose()
143{
144 m_connection->disconnectFromHost();
145}
146
147
148
149TcpServerImpl::TcpServerImpl(QObject *parent)
150 : QConnectionAbstractServer(parent)
151{
152 connect(sender: &m_server, signal: &QTcpServer::newConnection, receiver: this, slot: &QConnectionAbstractServer::newConnection);
153}
154
155TcpServerImpl::~TcpServerImpl()
156{
157 close();
158}
159
160ServerIoDevice *TcpServerImpl::configureNewConnection()
161{
162 if (!m_server.isListening())
163 return nullptr;
164
165 return new TcpServerIo(m_server.nextPendingConnection(), this);
166}
167
168bool TcpServerImpl::hasPendingConnections() const
169{
170 return m_server.hasPendingConnections();
171}
172
173QUrl TcpServerImpl::address() const
174{
175 return m_originalUrl;
176}
177
178bool TcpServerImpl::listen(const QUrl &address)
179{
180 QHostAddress host(address.host());
181 if (host.isNull()) {
182 if (address.host().isEmpty()) {
183 host = QHostAddress::Any;
184 } else {
185 qCWarning(QT_REMOTEOBJECT) << address.host() << " is not an IP address, trying to resolve it";
186 QHostInfo info = QHostInfo::fromName(name: address.host());
187 if (info.addresses().isEmpty())
188 host = QHostAddress::Any;
189 else
190 host = info.addresses().constFirst();
191 }
192 }
193
194 bool ret = m_server.listen(address: host, port: address.port());
195 if (ret) {
196 m_originalUrl.setScheme(QLatin1String("tcp"));
197 m_originalUrl.setHost(host: m_server.serverAddress().toString());
198 m_originalUrl.setPort(m_server.serverPort());
199 }
200 return ret;
201}
202
203QAbstractSocket::SocketError TcpServerImpl::serverError() const
204{
205 return m_server.serverError();
206}
207
208void TcpServerImpl::close()
209{
210 m_server.close();
211}
212
213QT_END_NAMESPACE
214

source code of qtremoteobjects/src/remoteobjects/qconnection_tcpip_backend.cpp