Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qlocalserver_unix.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
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 "qlocalserver.h"
5#include "qlocalserver_p.h"
6#include "qlocalsocket.h"
7#include "qlocalsocket_p.h"
8#include "qnet_unix_p.h"
9#include "qtemporarydir.h"
10
11#include <stddef.h>
12#include <sys/socket.h>
13#include <sys/un.h>
14
15#include <qdebug.h>
16#include <qdir.h>
17#include <qdatetime.h>
18
19#include <optional>
20
21#ifdef Q_OS_VXWORKS
22# include <selectLib.h>
23#endif
24
26
27using namespace Qt::StringLiterals;
28
29namespace {
30QLocalServer::SocketOptions optionsForPlatform(QLocalServer::SocketOptions srcOptions)
31{
32 // For OS that does not support abstract namespace the AbstractNamespaceOption
33 // means that we go for WorldAccessOption - as it is the closest option in
34 // regards of access rights. In Linux/Android case we clean-up the access rights.
35
36 if (srcOptions.testFlag(QLocalServer::AbstractNamespaceOption)) {
39 else
41 }
42 return srcOptions;
43}
44}
45
47{
48}
49
51{
53 if (name.startsWith(u'/')) {
54 fileName = name;
55 } else {
57 fileName += u'/' + name;
58 }
60 return QFile::remove(fileName);
61 else
62 return true;
63}
64
65bool QLocalServerPrivate::listen(const QString &requestedServerName)
66{
67 Q_Q(QLocalServer);
68
69 // socket options adjusted for current platform
70 auto options = optionsForPlatform(socketOptions.value());
71
72 // determine the full server path
73 if (options.testFlag(QLocalServer::AbstractNamespaceOption)
74 || requestedServerName.startsWith(u'/')) {
75 fullServerName = requestedServerName;
76 } else {
78 fullServerName += u'/' + requestedServerName;
79 }
80 serverName = requestedServerName;
81
82 QByteArray encodedTempPath;
83 const QByteArray encodedFullServerName = QFile::encodeName(fullServerName);
84 std::optional<QTemporaryDir> tempDir;
85
86 if (options & QLocalServer::WorldAccessOption) {
87 QFileInfo serverNameFileInfo(fullServerName);
88 tempDir.emplace(serverNameFileInfo.absolutePath() + u'/');
89 if (!tempDir->isValid()) {
90 setError("QLocalServer::listen"_L1);
91 return false;
92 }
93 encodedTempPath = QFile::encodeName(tempDir->path() + "/s"_L1);
94 }
95
96 // create the unix socket
97 listenSocket = qt_safe_socket(PF_UNIX, SOCK_STREAM, 0);
98 if (-1 == listenSocket) {
99 setError("QLocalServer::listen"_L1);
100 closeServer();
101 return false;
102 }
103
104 // Construct the unix address
105 struct ::sockaddr_un addr;
106
107 addr.sun_family = PF_UNIX;
108 ::memset(addr.sun_path, 0, sizeof(addr.sun_path));
109
110 // for abstract namespace add 2 to length, to take into account trailing AND leading null
111 constexpr unsigned int extraCharacters = PlatformSupportsAbstractNamespace ? 2 : 1;
112
113 if (sizeof(addr.sun_path) < static_cast<size_t>(encodedFullServerName.size() + extraCharacters)) {
114 setError("QLocalServer::listen"_L1);
115 closeServer();
116 return false;
117 }
118
119 QT_SOCKLEN_T addrSize = sizeof(::sockaddr_un);
120 if (options.testFlag(QLocalServer::AbstractNamespaceOption)) {
121 // Abstract socket address is distinguished by the fact
122 // that sun_path[0] is a null byte ('\0')
123 ::memcpy(addr.sun_path + 1, encodedFullServerName.constData(),
124 encodedFullServerName.size() + 1);
125 addrSize = offsetof(::sockaddr_un, sun_path) + encodedFullServerName.size() + 1;
126 } else if (options & QLocalServer::WorldAccessOption) {
127 if (sizeof(addr.sun_path) < static_cast<size_t>(encodedTempPath.size() + 1)) {
128 setError("QLocalServer::listen"_L1);
129 closeServer();
130 return false;
131 }
132 ::memcpy(addr.sun_path, encodedTempPath.constData(),
133 encodedTempPath.size() + 1);
134 } else {
135 ::memcpy(addr.sun_path, encodedFullServerName.constData(),
136 encodedFullServerName.size() + 1);
137 }
138
139 // bind
140 if (-1 == QT_SOCKET_BIND(listenSocket, (sockaddr *)&addr, addrSize)) {
141 setError("QLocalServer::listen"_L1);
142 // if address is in use already, just close the socket, but do not delete the file
143 if (errno == EADDRINUSE)
145 // otherwise, close the socket and delete the file
146 else
147 closeServer();
148 listenSocket = -1;
149 return false;
150 }
151
152 // listen for connections
154 setError("QLocalServer::listen"_L1);
155 closeServer();
156 return false;
157 }
158
159 if (options & QLocalServer::WorldAccessOption) {
160 mode_t mode = 000;
161
162 if (options & QLocalServer::UserAccessOption)
163 mode |= S_IRWXU;
164
166 mode |= S_IRWXG;
167
169 mode |= S_IRWXO;
170
171 if (::chmod(encodedTempPath.constData(), mode) == -1) {
172 setError("QLocalServer::listen"_L1);
173 closeServer();
174 return false;
175 }
176
177 if (::rename(encodedTempPath.constData(), encodedFullServerName.constData()) == -1) {
178 setError("QLocalServer::listen"_L1);
179 closeServer();
180 return false;
181 }
182 }
183
187 q->connect(socketNotifier, SIGNAL(activated(QSocketDescriptor)),
190 return true;
191}
192
193bool QLocalServerPrivate::listen(qintptr socketDescriptor)
194{
195 Q_Q(QLocalServer);
196
197 // Attach to the localsocket
198 listenSocket = socketDescriptor;
199
200 ::fcntl(listenSocket, F_SETFD, FD_CLOEXEC);
201 ::fcntl(listenSocket, F_SETFL, ::fcntl(listenSocket, F_GETFL) | O_NONBLOCK);
202
203 bool abstractAddress = false;
204 struct ::sockaddr_un addr;
205 QT_SOCKLEN_T len = sizeof(addr);
206 memset(&addr, 0, sizeof(addr));
207 if (::getsockname(socketDescriptor, (sockaddr *)&addr, &len) == 0) {
208#if defined(Q_OS_QNX)
209 if (addr.sun_path[0] == 0 && addr.sun_path[1] == 0)
210 len = SUN_LEN(&addr);
211#endif
213 abstractAddress)) {
214 QLocalServer::SocketOptions options = socketOptions.value();
215 socketOptions = options.setFlag(QLocalServer::AbstractNamespaceOption, abstractAddress);
216 }
217 }
218
222 q->connect(socketNotifier, SIGNAL(activated(QSocketDescriptor)),
225 return true;
226}
227
234{
235 if (socketNotifier) {
236 socketNotifier->setEnabled(false); // Otherwise, closed socket is checked before deleter runs
238 socketNotifier = nullptr;
239 }
240
241 if (-1 != listenSocket)
243 listenSocket = -1;
244
246 && !optionsForPlatform(socketOptions).testFlag(QLocalServer::AbstractNamespaceOption)) {
248 }
249
252}
253
261{
262 Q_Q(QLocalServer);
263 if (-1 == listenSocket)
264 return;
265
266 ::sockaddr_un addr;
267 QT_SOCKLEN_T length = sizeof(sockaddr_un);
268 int connectedSocket = qt_safe_accept(listenSocket, (sockaddr *)&addr, &length);
269 if (-1 == connectedSocket) {
270 setError("QLocalSocket::activated"_L1);
271 closeServer();
272 } else {
275 q->incomingConnection(connectedSocket);
276 }
277}
278
279void QLocalServerPrivate::waitForNewConnection(int msec, bool *timedOut)
280{
281 pollfd pfd = qt_make_pollfd(listenSocket, POLLIN);
282 switch (qt_safe_poll(&pfd, 1, QDeadlineTimer(msec))) {
283 case 0:
284 if (timedOut)
285 *timedOut = true;
286
287 return;
288 break;
289 default:
290 if ((pfd.revents & POLLNVAL) == 0) {
292 return;
293 }
294
295 errno = EBADF;
297 case -1:
298 setError("QLocalServer::waitForNewConnection"_L1);
299 closeServer();
300 break;
301 }
302}
303
305{
306 if (EAGAIN == errno)
307 return;
308
309 switch (errno) {
310 case EACCES:
311 errorString = QLocalServer::tr("%1: Permission denied").arg(function);
313 break;
314 case ELOOP:
315 case ENOENT:
316 case ENAMETOOLONG:
317 case EROFS:
318 case ENOTDIR:
319 errorString = QLocalServer::tr("%1: Name error").arg(function);
321 break;
322 case EADDRINUSE:
323 errorString = QLocalServer::tr("%1: Address in use").arg(function);
325 break;
326
327 default:
328 errorString = QLocalServer::tr("%1: Unknown error %2")
329 .arg(function).arg(errno);
331#if defined QLOCALSERVER_DEBUG
332 qWarning() << errorString << "fullServerName:" << fullServerName;
333#endif
334 }
335}
336
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
static QString tempPath()
Returns the absolute canonical path of the system's temporary directory.
Definition qdir.cpp:2133
static QString cleanPath(const QString &path)
Returns path with directory separators normalized (that is, platform-native separators converted to "...
Definition qdir.cpp:2398
bool remove()
Removes the file specified by fileName().
Definition qfile.cpp:419
static QByteArray encodeName(const QString &fileName)
Converts fileName to an 8-bit encoding that you can use in native APIs.
Definition qfile.h:158
bool exists() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qfile.cpp:351
qsizetype size() const noexcept
Definition qlist.h:397
void waitForNewConnection(int msec, bool *timedOut)
static bool removeServer(const QString &name)
void setError(const QString &function)
QQueue< QLocalSocket * > pendingConnections
QAbstractSocket::SocketError error
bool listen(const QString &name)
QSocketNotifier * socketNotifier
The QLocalServer class provides a local socket based server.
@ AbstractNamespaceOption
static bool parseSockaddr(const sockaddr_un &addr, uint len, QString &fullServerName, QString &serverName, bool &abstractNamespace)
void deleteLater()
\threadsafe
Definition qobject.cpp:2435
\inmodule QtCore
\inmodule QtCore
void setEnabled(bool)
If enable is true, the notifier is enabled; otherwise the notifier is disabled.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1252
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8870
Combined button and popup list for selecting options.
#define Q_FALLTHROUGH()
int qt_safe_poll(struct pollfd *fds, nfds_t nfds, QDeadlineTimer deadline)
static struct pollfd qt_make_pollfd(int fd, short events)
#define QT_CLOSE
#define qWarning
Definition qlogging.h:166
static int qt_safe_listen(int s, int backlog)
static int qt_safe_socket(int domain, int type, int protocol, int flags=0)
Definition qnet_unix_p.h:45
static int qt_safe_accept(int s, struct sockaddr *addr, QT_SOCKLEN_T *addrlen, int flags=0)
Definition qnet_unix_p.h:71
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLenum mode
GLenum GLuint GLenum GLsizei length
GLuint name
GLenum const void * addr
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLenum GLsizei len
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
@ PlatformSupportsAbstractNamespace
ptrdiff_t qintptr
Definition qtypes.h:166
bool testFlag(MaskType mask, FlagType flag)