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

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