13#include <sys/socket.h>
23# include <selectLib.h>
28using namespace Qt::StringLiterals;
31QLocalServer::SocketOptions optionsForPlatform(QLocalServer::SocketOptions srcOptions)
37 if (srcOptions.testFlag(QLocalServer::AbstractNamespaceOption)) {
38 if (PlatformSupportsAbstractNamespace)
39 return QLocalServer::AbstractNamespaceOption;
41 return QLocalServer::WorldAccessOption;
47void QLocalServerPrivate::init()
51bool QLocalServerPrivate::removeServer(
const QString &name)
54 if (name.startsWith(u'/')) {
57 fileName = QDir::cleanPath(QDir::tempPath());
58 fileName += u'/' + name;
60 if (QFile::exists(fileName))
61 return QFile::remove(fileName);
66bool QLocalServerPrivate::listen(
const QString &requestedServerName)
71 auto options = optionsForPlatform(socketOptions.value());
74 if (options.testFlag(QLocalServer::AbstractNamespaceOption)
75 || requestedServerName.startsWith(u'/')) {
76 fullServerName = requestedServerName;
78 fullServerName = QDir::cleanPath(QDir::tempPath());
79 fullServerName += u'/' + requestedServerName;
81 serverName = requestedServerName;
83 QByteArray encodedTempPath;
84 const QByteArray encodedFullServerName = QFile::encodeName(fullServerName);
85 std::optional<QTemporaryDir> tempDir;
87 if (options & QLocalServer::WorldAccessOption) {
88 QFileInfo serverNameFileInfo(fullServerName);
89 tempDir.emplace(serverNameFileInfo.absolutePath() + u'/');
90 if (!tempDir->isValid()) {
91 setError(
"QLocalServer::listen"_L1);
94 encodedTempPath = QFile::encodeName(tempDir->path() +
"/s"_L1);
98 listenSocket = qt_safe_socket(PF_UNIX, SOCK_STREAM, 0);
99 if (-1 == listenSocket) {
100 setError(
"QLocalServer::listen"_L1);
106 struct ::sockaddr_un addr;
108 addr.sun_family = PF_UNIX;
109 ::memset(addr.sun_path, 0,
sizeof(addr.sun_path));
112 constexpr unsigned int extraCharacters = PlatformSupportsAbstractNamespace ? 2 : 1;
114 if (
sizeof(addr.sun_path) <
static_cast<size_t>(encodedFullServerName.size() + extraCharacters)) {
115 setError(
"QLocalServer::listen"_L1);
120 QT_SOCKLEN_T addrSize =
sizeof(::sockaddr_un);
121 if (options.testFlag(QLocalServer::AbstractNamespaceOption)) {
124 ::memcpy(addr.sun_path + 1, encodedFullServerName.constData(),
125 encodedFullServerName.size() + 1);
126 addrSize = offsetof(::sockaddr_un, sun_path) + encodedFullServerName.size() + 1;
127 }
else if (options & QLocalServer::WorldAccessOption) {
128 if (
sizeof(addr.sun_path) <
static_cast<size_t>(encodedTempPath.size() + 1)) {
129 setError(
"QLocalServer::listen"_L1);
133 ::memcpy(addr.sun_path, encodedTempPath.constData(),
134 encodedTempPath.size() + 1);
136 ::memcpy(addr.sun_path, encodedFullServerName.constData(),
137 encodedFullServerName.size() + 1);
141 if (-1 == QT_SOCKET_BIND(listenSocket, (sockaddr *)&addr, addrSize)) {
142 setError(
"QLocalServer::listen"_L1);
144 if (errno == EADDRINUSE)
145 QT_CLOSE(listenSocket);
154 if (-1 == qt_safe_listen(listenSocket, listenBacklog)) {
155 setError(
"QLocalServer::listen"_L1);
160 if (options & QLocalServer::WorldAccessOption) {
163 if (options & QLocalServer::UserAccessOption)
166 if (options & QLocalServer::GroupAccessOption)
169 if (options & QLocalServer::OtherAccessOption)
172 if (::chmod(encodedTempPath.constData(), mode) == -1) {
173 setError(
"QLocalServer::listen"_L1);
178 if (::rename(encodedTempPath.constData(), encodedFullServerName.constData()) == -1) {
179 setError(
"QLocalServer::listen"_L1);
185 Q_ASSERT(!socketNotifier);
186 socketNotifier =
new QSocketNotifier(listenSocket,
187 QSocketNotifier::Read, q);
188 q->connect(socketNotifier, SIGNAL(activated(QSocketDescriptor)),
189 q, SLOT(_q_onNewConnection()));
190 socketNotifier->setEnabled(maxPendingConnections > 0);
194bool QLocalServerPrivate::listen(qintptr socketDescriptor)
199 listenSocket = socketDescriptor;
201 ::fcntl(listenSocket, F_SETFD, FD_CLOEXEC);
202 ::fcntl(listenSocket, F_SETFL, ::fcntl(listenSocket, F_GETFL) | O_NONBLOCK);
204 bool abstractAddress =
false;
205 struct ::sockaddr_un addr;
206 QT_SOCKLEN_T len =
sizeof(addr);
207 memset(&addr, 0,
sizeof(addr));
208 if (::getsockname(socketDescriptor, (sockaddr *)&addr, &len) == 0) {
210 if (addr.sun_path[0] == 0 && addr.sun_path[1] == 0)
211 len = SUN_LEN(&addr);
213 if (QLocalSocketPrivate::parseSockaddr(addr, len, fullServerName, serverName,
215 QLocalServer::SocketOptions options = socketOptions.value();
216 socketOptions = options.setFlag(QLocalServer::AbstractNamespaceOption, abstractAddress);
220 Q_ASSERT(!socketNotifier);
221 socketNotifier =
new QSocketNotifier(listenSocket,
222 QSocketNotifier::Read, q);
223 q->connect(socketNotifier, SIGNAL(activated(QSocketDescriptor)),
224 q, SLOT(_q_onNewConnection()));
225 socketNotifier->setEnabled(maxPendingConnections > 0);
230
231
232
233
234void QLocalServerPrivate::closeServer()
236 if (socketNotifier) {
237 socketNotifier->setEnabled(
false);
238 socketNotifier->deleteLater();
239 socketNotifier =
nullptr;
242 if (-1 != listenSocket)
243 QT_CLOSE(listenSocket);
246 if (!fullServerName.isEmpty()
247 && !optionsForPlatform(socketOptions).testFlag(QLocalServer::AbstractNamespaceOption)) {
248 QFile::remove(fullServerName);
252 fullServerName.clear();
256
257
258
259
260
261void QLocalServerPrivate::_q_onNewConnection()
264 if (-1 == listenSocket)
268 QT_SOCKLEN_T length =
sizeof(sockaddr_un);
269 int connectedSocket = qt_safe_accept(listenSocket, (sockaddr *)&addr, &length);
270 if (-1 == connectedSocket) {
271 setError(
"QLocalSocket::activated"_L1);
274 socketNotifier->setEnabled(pendingConnections.size()
275 <= maxPendingConnections);
276 q->incomingConnection(connectedSocket);
280void QLocalServerPrivate::waitForNewConnection(
int msec,
bool *timedOut)
282 pollfd pfd = qt_make_pollfd(listenSocket, POLLIN);
283 switch (qt_safe_poll(&pfd, 1, QDeadlineTimer(msec))) {
291 if ((pfd.revents & POLLNVAL) == 0) {
292 _q_onNewConnection();
299 setError(
"QLocalServer::waitForNewConnection"_L1);
305void QLocalServerPrivate::setError(
const QString &function)
312 errorString = QLocalServer::tr(
"%1: Permission denied").arg(function);
313 error = QAbstractSocket::SocketAccessError;
320 errorString = QLocalServer::tr(
"%1: Name error").arg(function);
321 error = QAbstractSocket::HostNotFoundError;
324 errorString = QLocalServer::tr(
"%1: Address in use").arg(function);
325 error = QAbstractSocket::AddressInUseError;
329 errorString = QLocalServer::tr(
"%1: Unknown error %2")
330 .arg(function).arg(errno);
331 error = QAbstractSocket::UnknownSocketError;
332#if defined QLOCALSERVER_DEBUG
333 qWarning() << errorString <<
"fullServerName:" << fullServerName;