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
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#include <qurlquery.h>
12
13#if defined(Q_OS_DARWIN)
14# include "private/qcore_mac_p.h"
15# if !defined(SHM_NAME_MAX)
16 // Based on PSEMNAMLEN in XNU's posix_sem.c, which would
17 // indicate the max length is 31, _excluding_ the zero
18 // terminator. But in practice (possibly due to an off-
19 // by-one bug in the kernel) the usable bytes are only 30.
20# define SHM_NAME_MAX 30
21# endif
22#elif defined(Q_OS_WINDOWS)
23# include "qt_windows.h"
24#endif
25
26#if QT_CONFIG(sharedmemory) || QT_CONFIG(systemsemaphore)
27
29
30using namespace Qt::StringLiterals;
31
32static QStringView staticTypeToString(QNativeIpcKey::Type type)
33{
34 switch (type) {
35 case QNativeIpcKey::Type::SystemV:
36 return u"systemv";
37 case QNativeIpcKey::Type::PosixRealtime:
38 return u"posix";
39 case QNativeIpcKey::Type::Windows:
40 return u"windows";
41 }
42 return {};
43}
44
45static QString typeToString(QNativeIpcKey::Type type)
46{
47 QStringView typeString = staticTypeToString(type);
48 switch (type) {
49 case QNativeIpcKey::Type::SystemV:
50 case QNativeIpcKey::Type::PosixRealtime:
51 case QNativeIpcKey::Type::Windows:
52 return QString::fromRawData(typeString.constData(), typeString.size());
53 }
54
55 int value = int(type);
56 if (value >= 1 && value <= 0xff) {
57 // System V key with id different from 'Q'
58 typeString = staticTypeToString(QNativeIpcKey::Type::SystemV);
59 return typeString + QString::number(-value); // negative so it prepends a dash
60 }
61
62 return QString(); // invalid!
63}
64
65static QNativeIpcKey::Type stringToType(QStringView typeString)
66{
67 if (typeString == staticTypeToString(QNativeIpcKey::Type::PosixRealtime))
68 return QNativeIpcKey::Type::PosixRealtime;
69 if (typeString == staticTypeToString(QNativeIpcKey::Type::Windows))
70 return QNativeIpcKey::Type::Windows;
71
72 auto fromNumber = [](QStringView number, int low, int high) {
73 bool ok;
74 int n = -number.toInt(&ok, 10);
75 if (!ok || n < low || n > high)
76 return QNativeIpcKey::Type{};
77 return QNativeIpcKey::Type(n);
78 };
79
80 QStringView sysv = staticTypeToString(QNativeIpcKey::Type::SystemV);
81 if (typeString.startsWith(sysv)) {
82 if (typeString.size() == sysv.size())
83 return QNativeIpcKey::Type::SystemV;
84 return fromNumber(typeString.sliced(sysv.size()), 1, 0xff);
85 }
86
87 // invalid!
88 return QNativeIpcKey::Type{};
89}
90
103QNativeIpcKey QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType,
104 QNativeIpcKey::Type type)
105{
106 QNativeIpcKey k(type);
107 if (key.isEmpty())
108 return k;
109
111
112 if (type == QNativeIpcKey::Type::PosixRealtime) {
113#if defined(Q_OS_DARWIN)
114 if (qt_apple_isSandboxed()) {
115 // Sandboxed applications on Apple platforms require the shared memory name
116 // to be in the form <application group identifier>/<custom identifier>.
117 // Since we don't know which application group identifier the user wants
118 // to apply, we instead document that requirement, and use the key directly.
119 QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, key, key);
120 } else {
121 // The shared memory name limit on Apple platforms is very low (30 characters),
122 // so we can't use the logic below of combining the prefix, key, and a hash,
123 // to ensure a unique and valid name. Instead we use the first part of the
124 // hash, which should still long enough to avoid collisions in practice.
125 QString native = u'/' + QLatin1StringView(hex).left(SHM_NAME_MAX - 1);
126 QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, native, key);
127 }
128 return k;
129#endif
130 }
131
133 result.reserve(1 + 18 + key.size() + 40);
134 switch (ipcType) {
135 case IpcType::SharedMemory:
136 result += "qipc_sharedmemory_"_L1;
137 break;
138 case IpcType::SystemSemaphore:
139 result += "qipc_systemsem_"_L1;
140 break;
141 }
142
143 for (QChar ch : key) {
144 if ((ch >= u'a' && ch <= u'z') ||
145 (ch >= u'A' && ch <= u'Z'))
146 result += ch;
147 }
149
150 switch (type) {
151 case QNativeIpcKey::Type::Windows:
152 if (isIpcSupported(ipcType, QNativeIpcKey::Type::Windows))
153 QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, result, key);
154 return k;
155 case QNativeIpcKey::Type::PosixRealtime:
156 result.prepend(u'/');
157 if (isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime))
158 QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, result, key);
159 return k;
160 case QNativeIpcKey::Type::SystemV:
161 break;
162 }
163 if (isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV)) {
165 QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, result, key);
166 }
167 return k;
168}
169
177QNativeIpcKey QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType,
178 QNativeIpcKey::Type type)
179{
180 QNativeIpcKey k(type);
181 if (key.isEmpty())
182 return k;
183
184 switch (type) {
185 case QNativeIpcKey::Type::PosixRealtime:
186 if (isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime)) {
187#ifdef SHM_NAME_MAX
188 // The shared memory name limit on Apple platforms is very low (30
189 // characters), so we have to cut it down to avoid ENAMETOOLONG. We
190 // hope that there won't be too many collisions...
191 k.setNativeKey(u'/' + QStringView(key).left(SHM_NAME_MAX - 1));
192#else
193 k.setNativeKey(u'/' + key);
194#endif
195 }
196 return k;
197
198 case QNativeIpcKey::Type::Windows:
199 if (isIpcSupported(ipcType, QNativeIpcKey::Type::Windows)) {
200 QStringView prefix;
201 QStringView payload = key;
202 // see https://learn.microsoft.com/en-us/windows/win32/termserv/kernel-object-namespaces
203 for (QStringView candidate : { u"Local\\", u"Global\\" }) {
204 if (!key.startsWith(candidate))
205 continue;
206 prefix = candidate;
207 payload = payload.sliced(prefix.size());
208 break;
209 }
210
211 QStringView mid;
212 switch (ipcType) {
213 case IpcType::SharedMemory: mid = u"shm_"; break;
214 case IpcType::SystemSemaphore: mid = u"sem_"; break;
215 }
216
217 QString result = prefix + mid + payload;
218#ifdef Q_OS_WINDOWS
220#endif
221 k.setNativeKey(result);
222 }
223 return k;
224
225 case QNativeIpcKey::Type::SystemV:
226 break;
227 }
228
229 // System V
230 if (isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV)) {
231 if (key.startsWith(u'/')) {
232 k.setNativeKey(key);
233 } else {
235 k.setNativeKey(baseDir + u'/' + key);
236 }
237 }
238 return k;
239}
240
362#if defined(Q_OS_DARWIN)
363QNativeIpcKey::Type QNativeIpcKey::defaultTypeForOs_internal() noexcept
364{
366 return Type::PosixRealtime;
367 return Type::SystemV;
368}
369#endif
370
393void QNativeIpcKey::copy_internal(const QNativeIpcKey &other)
394{
395 d = new QNativeIpcKeyPrivate(*other.d);
396}
397
398void QNativeIpcKey::move_internal(QNativeIpcKey &&) noexcept
399{
400 // inline code already moved properly, nothing for us to do here
401}
402
403QNativeIpcKey &QNativeIpcKey::assign_internal(const QNativeIpcKey &other)
404{
405 Q_ASSERT(d || other.d); // only 3 cases to handle
406 if (d && !other.d)
407 *d = {};
408 else if (d)
409 *d = *other.d;
410 else
411 d = new QNativeIpcKeyPrivate(*other.d);
412 return *this;
413}
414
420void QNativeIpcKey::destroy_internal() noexcept
421{
422 delete d;
423}
424
476void QNativeIpcKey::setType_internal(Type type)
477{
478 Q_UNUSED(type);
479}
480
496void QNativeIpcKey::setNativeKey_internal(const QString &)
497{
498 d->legacyKey_.clear();
499}
500
512size_t qHash(const QNativeIpcKey &ipcKey, size_t seed) noexcept
513{
514 // by *choice*, we're not including d->legacyKey_ in the hash -- it's
515 // already partially encoded in the key
516 return qHashMulti(seed, ipcKey.key, ipcKey.type());
517}
518
525int QNativeIpcKey::compare_internal(const QNativeIpcKey &lhs, const QNativeIpcKey &rhs) noexcept
526{
527 return (QNativeIpcKeyPrivate::legacyKey(lhs) == QNativeIpcKeyPrivate::legacyKey(rhs)) ? 0 : 1;
528}
529
540QString QNativeIpcKey::toString() const
541{
542 QString prefix = typeToString(type());
543 if (prefix.isEmpty()) {
544 Q_ASSERT(prefix.isNull());
545 return prefix;
546 }
547
548 QString copy = nativeKey();
549 copy.replace(u'%', "%25"_L1);
550 if (copy.startsWith("//"_L1))
551 copy.replace(0, 2, u"/%2F"_s); // ensure it's parsed as a URL path
552
553 QUrl u;
554 u.setScheme(prefix);
556 if (isSlowPath()) {
557 QUrlQuery q;
558 if (!d->legacyKey_.isEmpty())
559 q.addQueryItem(u"legacyKey"_s, QString(d->legacyKey_).replace(u'%', "%25"_L1));
560 u.setQuery(q);
561 }
563}
564
575QNativeIpcKey QNativeIpcKey::fromString(const QString &text)
576{
578 Type invalidType = {};
579 Type type = stringToType(u.scheme());
580 if (type == invalidType || !u.isValid() || !u.userInfo().isEmpty() || !u.host().isEmpty()
581 || u.port() != -1)
582 return QNativeIpcKey(invalidType);
583
584 QNativeIpcKey result(QString(), type);
585 if (result.type() != type) // range check, just in case
586 return QNativeIpcKey(invalidType);
587
588 // decode the payload
589 result.setNativeKey(u.path());
590
591 if (u.hasQuery()) {
592 const QList items = QUrlQuery(u).queryItems();
593 for (const auto &item : items) {
594 if (item.first == u"legacyKey"_s) {
595 QString legacyKey = QUrl::fromPercentEncoding(item.second.toUtf8());
596 QNativeIpcKeyPrivate::setLegacyKey(result, std::move(legacyKey));
597 } else {
598 // unknown query item
599 return QNativeIpcKey(invalidType);
600 }
601 }
602 }
603 return result;
604}
605
607
608#include "moc_qtipccommon.cpp"
609
610#endif // QT_CONFIG(sharedmemory) || QT_CONFIG(systemsemaphore)
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
static QByteArray hash(QByteArrayView data, Algorithm method)
Returns the hash of data using method.
constexpr QLatin1StringView left(qsizetype n) const
Definition qlist.h:75
static QString writableLocation(StandardLocation type)
\inmodule QtCore
Definition qstringview.h:78
constexpr void truncate(qsizetype n) noexcept
Truncates this string view to length length.
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 sliced(qsizetype pos) const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3824
void reserve(qsizetype size)
Ensures the string has space for at least size characters.
Definition qstring.h:1325
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition qstring.h:994
static QString fromRawData(const QChar *, qsizetype size)
Constructs a QString that uses the first size Unicode characters in the array unicode.
Definition qstring.cpp:9482
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:8084
\inmodule QtCore
Definition qurlquery.h:20
void addQueryItem(const QString &key, const QString &value)
Appends the pair key = value to the end of the query string of the URL.
QList< std::pair< QString, QString > > queryItems(QUrl::ComponentFormattingOptions encoding=QUrl::PrettyDecoded) const
Returns the query string of the URL, as a map of keys and values, using the options specified in enco...
\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:2129
bool hasQuery() const
Definition qurl.cpp:2513
static QString fromPercentEncoding(const QByteArray &)
Returns a decoded copy of input.
Definition qurl.cpp:3001
bool isValid() const
Returns true if the URL is non-empty and valid; otherwise returns false.
Definition qurl.cpp:1882
QString host(ComponentFormattingOptions=FullyDecoded) const
Returns the host of the URL if it is defined; otherwise an empty string is returned.
Definition qurl.cpp:2340
void setQuery(const QString &query, ParsingMode mode=TolerantMode)
Sets the query string of the URL to query.
Definition qurl.cpp:2550
@ TolerantMode
Definition qurl.h:97
QString scheme() const
Returns the scheme of the URL.
Definition qurl.cpp:1991
void setScheme(const QString &scheme)
Sets the scheme of the URL to scheme.
Definition qurl.cpp:1967
int port(int defaultPort=-1) const
Definition qurl.cpp:2383
@ DecodeReserved
Definition qurl.h:126
void setPath(const QString &path, ParsingMode mode=DecodedMode)
Sets the path of the URL to path.
Definition qurl.cpp:2414
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2831
QString path(ComponentFormattingOptions options=FullyDecoded) const
Returns the path of the URL.
Definition qurl.cpp:2468
QString text
Combined button and popup list for selecting options.
static jboolean copy(JNIEnv *, jobject)
bool qt_apple_isSandboxed()
Definition qcore_mac.mm:499
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
size_t qHash(const QFileSystemWatcherPathKey &key, size_t seed=0)
constexpr QtPrivate::QHashMultiReturnType< T... > qHashMulti(size_t seed, const T &... args) noexcept(std::conjunction_v< QtPrivate::QNothrowHashable< T >... >)
GLuint64 key
GLint left
GLenum type
GLfloat n
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Definition qrandom.cpp:196
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define MAX_PATH
#define Q_UNUSED(x)
QSharedPointer< T > other(t)
[5]
QGraphicsItem * item
QList< QTreeWidgetItem * > items
Definition moc.h:23