1// Copyright (C) 2017 Ford Motor Company
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:insecure-local-connections
4
5#include "qconnection_local_backend_p.h"
6
7QT_BEGIN_NAMESPACE
8
9LocalClientIo::LocalClientIo(QObject *parent)
10 : QtROClientIoDevice(parent)
11 , m_socket(new QLocalSocket(this))
12{
13 connect(sender: m_socket, signal: &QLocalSocket::readyRead, context: this, slot: &QtROClientIoDevice::readyRead);
14 connect(sender: m_socket, signal: &QLocalSocket::errorOccurred, context: this, slot: &LocalClientIo::onError);
15 connect(sender: m_socket, signal: &QLocalSocket::stateChanged, context: this, slot: &LocalClientIo::onStateChanged);
16}
17
18LocalClientIo::~LocalClientIo()
19{
20 close();
21}
22
23QIODevice *LocalClientIo::connection() const
24{
25 return m_socket;
26}
27
28void LocalClientIo::doClose()
29{
30 if (m_socket->isOpen()) {
31 connect(sender: m_socket, signal: &QLocalSocket::disconnected, context: this, slot: &QObject::deleteLater);
32 m_socket->disconnectFromServer();
33 } else {
34 this->deleteLater();
35 }
36}
37
38void LocalClientIo::doDisconnectFromServer()
39{
40 m_socket->disconnectFromServer();
41}
42
43void LocalClientIo::connectToServer()
44{
45#ifdef Q_OS_ANDROID
46 if (!m_socket->socketOptions().testFlag(QLocalSocket::AbstractNamespaceOption))
47 qWarning() << "It is recommended to use 'localabstract' over 'local' on Android.";
48#endif
49 if (!isOpen())
50 m_socket->connectToServer(name: url().path());
51}
52
53bool LocalClientIo::isOpen() const
54{
55 return !isClosing() && (m_socket->state() == QLocalSocket::ConnectedState
56 || m_socket->state() == QLocalSocket::ConnectingState);
57}
58
59void LocalClientIo::onError(QLocalSocket::LocalSocketError error)
60{
61 qCDebug(QT_REMOTEOBJECT) << "onError" << error << m_socket->serverName();
62
63 switch (error) {
64 case QLocalSocket::ServerNotFoundError:
65 case QLocalSocket::UnknownSocketError:
66 case QLocalSocket::PeerClosedError:
67 //Host not there, wait and try again
68 emit shouldReconnect(this);
69 break;
70 case QLocalSocket::ConnectionError:
71 case QLocalSocket::ConnectionRefusedError:
72 //... TODO error reporting
73#ifdef Q_OS_UNIX
74 emit shouldReconnect(this);
75#endif
76 break;
77 case QLocalSocket::SocketAccessError:
78 emit setError(QRemoteObjectNode::SocketAccessError);
79 break;
80 default:
81 break;
82 }
83}
84
85void LocalClientIo::onStateChanged(QLocalSocket::LocalSocketState state)
86{
87 if (state == QLocalSocket::ClosingState && !isClosing()) {
88 m_socket->abort();
89 emit shouldReconnect(this);
90 }
91 if (state == QLocalSocket::ConnectedState)
92 initializeDataStream();
93}
94
95LocalServerIo::LocalServerIo(QLocalSocket *conn, QObject *parent)
96 : QtROServerIoDevice(parent), m_connection(conn)
97{
98 m_connection->setParent(this);
99 connect(sender: conn, signal: &QIODevice::readyRead, context: this, slot: &QtROServerIoDevice::readyRead);
100 connect(sender: conn, signal: &QLocalSocket::disconnected, context: this, slot: &QtROServerIoDevice::disconnected);
101}
102
103QIODevice *LocalServerIo::connection() const
104{
105 return m_connection;
106}
107
108void LocalServerIo::doClose()
109{
110 m_connection->disconnectFromServer();
111}
112
113LocalServerImpl::LocalServerImpl(QObject *parent)
114 : QConnectionAbstractServer(parent)
115{
116 connect(sender: &m_server, signal: &QLocalServer::newConnection, context: this, slot: &QConnectionAbstractServer::newConnection);
117}
118
119LocalServerImpl::~LocalServerImpl()
120{
121 m_server.close();
122}
123
124QtROServerIoDevice *LocalServerImpl::configureNewConnection()
125{
126 if (!m_server.isListening())
127 return nullptr;
128
129 return new LocalServerIo(m_server.nextPendingConnection(), this);
130}
131
132bool LocalServerImpl::hasPendingConnections() const
133{
134 return m_server.hasPendingConnections();
135}
136
137QUrl LocalServerImpl::address() const
138{
139 QUrl result;
140 result.setPath(path: m_server.serverName());
141 result.setScheme(QRemoteObjectStringLiterals::local());
142
143 return result;
144}
145
146bool LocalServerImpl::listen(const QUrl &address)
147{
148#ifdef Q_OS_ANDROID
149 if (!m_server.socketOptions().testFlag(QLocalServer::AbstractNamespaceOption))
150 qWarning() << "It is recommended to use 'localabstract' over 'local' on Android.";
151#endif
152#ifdef Q_OS_UNIX
153 bool res = m_server.listen(name: address.path());
154 if (!res) {
155 QLocalServer::removeServer(name: address.path());
156 res = m_server.listen(name: address.path());
157 }
158 return res;
159#else
160 return m_server.listen(address.path());
161#endif
162}
163
164QAbstractSocket::SocketError LocalServerImpl::serverError() const
165{
166 return m_server.serverError();
167}
168
169void LocalServerImpl::close()
170{
171 m_server.close();
172}
173
174void LocalServerImpl::setSocketOptions(QLocalServer::SocketOptions options)
175{
176 m_server.setSocketOptions(options);
177}
178
179#ifdef Q_OS_LINUX
180
181AbstractLocalClientIo::AbstractLocalClientIo(QObject *parent)
182 : LocalClientIo(parent)
183{
184 m_socket->setSocketOptions(QLocalSocket::AbstractNamespaceOption);
185}
186
187AbstractLocalServerImpl::AbstractLocalServerImpl(QObject *parent)
188 : LocalServerImpl(parent)
189{
190 m_server.setSocketOptions(QLocalServer::AbstractNamespaceOption);
191}
192
193QUrl AbstractLocalServerImpl::address() const
194{
195 QUrl result;
196 result.setPath(path: m_server.serverName());
197 result.setScheme(QRemoteObjectStringLiterals::localabstract());
198
199 return result;
200}
201
202#endif // Q_OS_LINUX
203
204QT_END_NAMESPACE
205

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