Qt 6.x
The Qt SDK
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
qtipccommon.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 Intel Corporation.
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 "qtipccommon.h"
5#include "qtipccommon_p.h"
6
8#include <qstandardpaths.h>
9#include <qstringconverter.h>
10#include <qurl.h>
11
12#if defined(Q_OS_DARWIN)
13# include "private/qcore_mac_p.h"
14# if !defined(SHM_NAME_MAX)
15 // Based on PSEMNAMLEN in XNU's posix_sem.c, which would
16 // indicate the max length is 31, _excluding_ the zero
17 // terminator. But in practice (possibly due to an off-
18 // by-one bug in the kernel) the usable bytes are only 30.
19# define SHM_NAME_MAX 30
20# endif
21#endif
22
23#if QT_CONFIG(sharedmemory) || QT_CONFIG(systemsemaphore)
24
26
27using namespace Qt::StringLiterals;
28
29static QStringView staticTypeToString(QNativeIpcKey::Type type)
30{
31 switch (type) {
32 case QNativeIpcKey::Type::SystemV:
33 return u"systemv";
34 case QNativeIpcKey::Type::PosixRealtime:
35 return u"posix";
36 case QNativeIpcKey::Type::Windows:
37 return u"windows";
38 }
39 return {};
40}
41
42static QString typeToString(QNativeIpcKey::Type type)
43{
44 QStringView typeString = staticTypeToString(type);
45 switch (type) {
46 case QNativeIpcKey::Type::SystemV:
47 case QNativeIpcKey::Type::PosixRealtime:
48 case QNativeIpcKey::Type::Windows:
49 return QString::fromRawData(typeString.constData(), typeString.size());
50 }
51
52 int value = int(type);
53 if (value >= 1 && value <= 0xff) {
54 // System V key with id different from 'Q'
55 typeString = staticTypeToString(QNativeIpcKey::Type::SystemV);
56 return typeString + QString::number(-value); // negative so it prepends a dash
57 }
58
59 return QString(); // invalid!
60}
61
62static QNativeIpcKey::Type stringToType(QStringView typeString)
63{
64 if (typeString == staticTypeToString(QNativeIpcKey::Type::PosixRealtime))
65 return QNativeIpcKey::Type::PosixRealtime;
66 if (typeString == staticTypeToString(QNativeIpcKey::Type::Windows))
67 return QNativeIpcKey::Type::Windows;
68
69 auto fromNumber = [](QStringView number, int low, int high) {
70 bool ok;
71 int n = -number.toInt(&ok, 10);
72 if (!ok || n < low || n > high)
73 return QNativeIpcKey::Type{};
74 return QNativeIpcKey::Type(n);
75 };
76
77 QStringView sysv = staticTypeToString(QNativeIpcKey::Type::SystemV);
78 if (typeString.startsWith(sysv)) {
79 if (typeString.size() == sysv.size())
80 return QNativeIpcKey::Type::SystemV;
81 return fromNumber(typeString.sliced(sysv.size()), 1, 0xff);
82 }
83
84 // invalid!
85 return QNativeIpcKey::Type{};
86}
87
99QString QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType,
100 QNativeIpcKey::Type type)
101{
102 if (key.isEmpty())
103 return QString();
104
106
107 if (type == QNativeIpcKey::Type::PosixRealtime) {
108#if defined(Q_OS_DARWIN)
109 if (qt_apple_isSandboxed()) {
110 // Sandboxed applications on Apple platforms require the shared memory name
111 // to be in the form <application group identifier>/<custom identifier>.
112 // Since we don't know which application group identifier the user wants
113 // to apply, we instead document that requirement, and use the key directly.
114 return key;
115 }
116 // The shared memory name limit on Apple platforms is very low (30 characters),
117 // so we can't use the logic below of combining the prefix, key, and a hash,
118 // to ensure a unique and valid name. Instead we use the first part of the
119 // hash, which should still long enough to avoid collisions in practice.
120 return u'/' + QLatin1StringView(hex).left(SHM_NAME_MAX - 1);
121#endif
122 }
123
125 result.reserve(1 + 18 + key.size() + 40);
126 switch (ipcType) {
127 case IpcType::SharedMemory:
128 result += "qipc_sharedmemory_"_L1;
129 break;
130 case IpcType::SystemSemaphore:
131 result += "qipc_systemsem_"_L1;
132 break;
133 }
134
135 for (QChar ch : key) {
136 if ((ch >= u'a' && ch <= u'z') ||
137 (ch >= u'A' && ch <= u'Z'))
138 result += ch;
139 }
141
142 switch (type) {
143 case QNativeIpcKey::Type::Windows:
144 if (!isIpcSupported(ipcType, QNativeIpcKey::Type::Windows))
145 return QString();
146 return result;
147 case QNativeIpcKey::Type::PosixRealtime:
148 if (!isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime))
149 return QString();
150 return result.prepend(u'/');
151 case QNativeIpcKey::Type::SystemV:
152 break;
153 }
154 if (!isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV))
155 return QString();
157}
158
159QString QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType,
160 QNativeIpcKey::Type type)
161{
162 if (key.isEmpty())
163 return key;
164
165 switch (type) {
166 case QNativeIpcKey::Type::PosixRealtime:
167 if (!isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime))
168 return QString();
169#ifdef SHM_NAME_MAX
170 // The shared memory name limit on Apple platforms is very low (30
171 // characters), so we have to cut it down to avoid ENAMETOOLONG. We
172 // hope that there won't be too many collisions...
173 return u'/' + QStringView(key).left(SHM_NAME_MAX - 1);
174#endif
175 return u'/' + key;
176
177 case QNativeIpcKey::Type::Windows:
178 if (isIpcSupported(ipcType, QNativeIpcKey::Type::Windows)) {
179 QStringView prefix;
180 QStringView payload = key;
181 // see https://learn.microsoft.com/en-us/windows/win32/termserv/kernel-object-namespaces
182 for (QStringView candidate : { u"Local\\", u"Global\\" }) {
183 if (!key.startsWith(candidate))
184 continue;
185 prefix = candidate;
186 payload = payload.sliced(prefix.size());
187 break;
188 }
189
190 QStringView mid;
191 switch (ipcType) {
192 case IpcType::SharedMemory: mid = u"shm_"; break;
193 case IpcType::SystemSemaphore: mid = u"sem_"; break;
194 }
195
196 QString result = prefix + mid + payload;
197#ifdef MAX_PATH
199#endif
200 return result;
201 }
202 return QString();
203
204 case QNativeIpcKey::Type::SystemV:
205 break;
206 }
207
208 // System V
209 if (!isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV))
210 return QString();
211 if (key.startsWith(u'/'))
212 return key;
213
215 return baseDir + u'/' + key;
216}
217
337#if defined(Q_OS_DARWIN)
338QNativeIpcKey::Type QNativeIpcKey::defaultTypeForOs_internal() noexcept
339{
341 return Type::PosixRealtime;
342 return Type::SystemV;
343}
344#endif
345
362void QNativeIpcKey::copy_internal(const QNativeIpcKey &other)
363{
364 auto copy = new QNativeIpcKeyPrivate(*other.d_func());
365 d = quintptr(copy) & 1;
366}
367
368void QNativeIpcKey::move_internal(QNativeIpcKey &&) noexcept
369{
370 // inline code already moved properly, nothing for us to do here
371}
372
373QNativeIpcKey &QNativeIpcKey::assign_internal(const QNativeIpcKey &other)
374{
375 QNativeIpcKeyPrivate *us = (d & 1) ? d_func() : nullptr;
376 const QNativeIpcKeyPrivate *them = (other.d & 1) ? other.d_func() : nullptr;
377 if (us && !them) {
378 // don't need the extra info, reset to skinny object
379 typeAndFlags = {};
380 typeAndFlags.type = us->type;
381 delete us;
382 } else {
383 // do need the extra info, so create if necessary
384 if (us)
385 *us = *them;
386 else
387 us = new QNativeIpcKeyPrivate(*them);
388 d = quintptr(us) | 1;
389 }
390 return *this;
391}
392
398void QNativeIpcKey::destroy_internal() noexcept
399{
400 Q_D(QNativeIpcKey);
401 delete d;
402}
403
447QNativeIpcKey::Type QNativeIpcKey::type_internal() const noexcept
448{
449 Q_D(const QNativeIpcKey);
450 return d->type;
451}
452
460void QNativeIpcKey::setType_internal(Type type)
461{
462 Q_D(QNativeIpcKey);
463 d->type = type;
464}
465
481void QNativeIpcKey::setNativeKey_internal(const QString &)
482{
483}
484
491int QNativeIpcKey::compare_internal(const QNativeIpcKey &lhs, const QNativeIpcKey &rhs) noexcept
492{
493 return *lhs.d_func() == *rhs.d_func() ? 0 : 1;
494}
495
506QString QNativeIpcKey::toString() const
507{
508 QString prefix = typeToString(type());
509 if (prefix.isEmpty()) {
510 Q_ASSERT(prefix.isNull());
511 return prefix;
512 }
513
514 QString copy = nativeKey();
515 copy.replace(u'%', "%25"_L1);
516 if (copy.startsWith("//"_L1))
517 copy.replace(0, 2, u"/%2F"_s); // ensure it's parsed as a URL path
518
519 QUrl u;
520 u.setScheme(prefix);
523}
524
535QNativeIpcKey QNativeIpcKey::fromString(const QString &text)
536{
538 Type invalidType = {};
539 Type type = stringToType(u.scheme());
540 if (type == invalidType || !u.isValid() || !u.userInfo().isEmpty() || !u.host().isEmpty()
541 || u.port() != -1)
542 return QNativeIpcKey(invalidType);
543
544 QNativeIpcKey result(QString(), type);
545 if (result.type() != type) // range check, just in case
546 return QNativeIpcKey(invalidType);
547
548 // decode the payload
549 result.setNativeKey(u.path());
550 return result;
551}
552
554
555#include "moc_qtipccommon.cpp"
556
557#endif // QT_CONFIG(sharedmemory) || QT_CONFIG(systemsemaphore)
\inmodule QtCore
Definition qbytearray.h:57
QByteArray toHex(char separator='\0') const
Returns a hex encoded copy of the byte array.
\inmodule QtCore
Definition qchar.h:48
static QByteArray hash(QByteArrayView data, Algorithm method)
Returns the hash of data using method.
constexpr QLatin1StringView left(qsizetype n) const
static QString writableLocation(StandardLocation type)
\inmodule QtCore
Definition qstringview.h:76
constexpr void truncate(qsizetype n) noexcept
Truncates this string view to length length.
bool startsWith(QStringView s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
constexpr qsizetype size() const noexcept
Returns the size of this string view, in UTF-16 code units (that is, surrogate pairs count as two for...
constexpr QStringView left(qsizetype n) const noexcept
constexpr QStringView sliced(qsizetype pos) const noexcept
const_pointer constData() const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition qstring.h:898
static QString fromRawData(const QChar *, qsizetype size)
Constructs a QString that uses the first size Unicode characters in the array unicode.
Definition qstring.cpp:9242
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:7822
\inmodule QtCore
Definition qurl.h:94
QString userInfo(ComponentFormattingOptions options=PrettyDecoded) const
Returns the user info of the URL, or an empty string if the user info is undefined.
Definition qurl.cpp:2126
bool isValid() const
Returns true if the URL is non-empty and valid; otherwise returns false.
Definition qurl.cpp:1874
QString host(ComponentFormattingOptions=FullyDecoded) const
Returns the host of the URL if it is defined; otherwise an empty string is returned.
Definition qurl.cpp:2337
@ TolerantMode
Definition qurl.h:97
QString scheme() const
Returns the scheme of the URL.
Definition qurl.cpp:1983
void setScheme(const QString &scheme)
Sets the scheme of the URL to scheme.
Definition qurl.cpp:1959
int port(int defaultPort=-1) const
Definition qurl.cpp:2380
@ DecodeReserved
Definition qurl.h:126
void setPath(const QString &path, ParsingMode mode=DecodedMode)
Sets the path of the URL to path.
Definition qurl.cpp:2411
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2828
QString path(ComponentFormattingOptions options=FullyDecoded) const
Returns the path of the URL.
Definition qurl.cpp:2465
QString text
Combined button and popup list for selecting options.
static jboolean copy(JNIEnv *, jobject)
bool qt_apple_isSandboxed()
Definition qcore_mac.mm:498
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GLuint64 key
GLenum type
GLfloat n
GLuint64EXT * result
[6]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define MAX_PATH
size_t quintptr
Definition qtypes.h:72
QSharedPointer< T > other(t)
[5]
Definition moc.h:24