summaryrefslogtreecommitdiffstats
path: root/src/corelib/ipc/qtipccommon.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/ipc/qtipccommon.cpp')
-rw-r--r--src/corelib/ipc/qtipccommon.cpp202
1 files changed, 131 insertions, 71 deletions
diff --git a/src/corelib/ipc/qtipccommon.cpp b/src/corelib/ipc/qtipccommon.cpp
index 1dcc774c85..b2ae9172fa 100644
--- a/src/corelib/ipc/qtipccommon.cpp
+++ b/src/corelib/ipc/qtipccommon.cpp
@@ -8,6 +8,7 @@
#include <qstandardpaths.h>
#include <qstringconverter.h>
#include <qurl.h>
+#include <qurlquery.h>
#if defined(Q_OS_DARWIN)
# include "private/qcore_mac_p.h"
@@ -18,6 +19,8 @@
// by-one bug in the kernel) the usable bytes are only 30.
# define SHM_NAME_MAX 30
# endif
+#elif defined(Q_OS_WINDOWS)
+# include "qt_windows.h"
#endif
#if QT_CONFIG(sharedmemory) || QT_CONFIG(systemsemaphore)
@@ -91,16 +94,18 @@ static QNativeIpcKey::Type stringToType(QStringView typeString)
Legacy: this exists for compatibility with QSharedMemory and
QSystemSemaphore between 4.4 and 6.6.
- Generate a string from the key which can be any unicode string into
- the subset that the win/unix kernel allows.
-
- On Unix this will be a file name
+ Returns a QNativeIpcKey that contains a platform-safe key using rules
+ similar to QtIpcCommon::platformSafeKey() below, but using an algorithm
+ that is compatible with Qt 4.4 to 6.6. Additionally, the returned
+ QNativeIpcKey will record the input \a key so it can be included in the
+ string form if necessary to pass to other processes.
*/
-QString QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType,
- QNativeIpcKey::Type type)
+QNativeIpcKey QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType,
+ QNativeIpcKey::Type type)
{
+ QNativeIpcKey k(type);
if (key.isEmpty())
- return QString();
+ return k;
QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex();
@@ -111,13 +116,16 @@ QString QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcT
// to be in the form <application group identifier>/<custom identifier>.
// Since we don't know which application group identifier the user wants
// to apply, we instead document that requirement, and use the key directly.
- return key;
+ QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, key, key);
+ } else {
+ // The shared memory name limit on Apple platforms is very low (30 characters),
+ // so we can't use the logic below of combining the prefix, key, and a hash,
+ // to ensure a unique and valid name. Instead we use the first part of the
+ // hash, which should still long enough to avoid collisions in practice.
+ QString native = u'/' + QLatin1StringView(hex).left(SHM_NAME_MAX - 1);
+ QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, native, key);
}
- // The shared memory name limit on Apple platforms is very low (30 characters),
- // so we can't use the logic below of combining the prefix, key, and a hash,
- // to ensure a unique and valid name. Instead we use the first part of the
- // hash, which should still long enough to avoid collisions in practice.
- return u'/' + QLatin1StringView(hex).left(SHM_NAME_MAX - 1);
+ return k;
#endif
}
@@ -141,38 +149,51 @@ QString QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcT
switch (type) {
case QNativeIpcKey::Type::Windows:
- if (!isIpcSupported(ipcType, QNativeIpcKey::Type::Windows))
- return QString();
- return result;
+ if (isIpcSupported(ipcType, QNativeIpcKey::Type::Windows))
+ QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, result, key);
+ return k;
case QNativeIpcKey::Type::PosixRealtime:
- if (!isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime))
- return QString();
- return result.prepend(u'/');
+ result.prepend(u'/');
+ if (isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime))
+ QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, result, key);
+ return k;
case QNativeIpcKey::Type::SystemV:
break;
}
- if (!isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV))
- return QString();
- return QStandardPaths::writableLocation(QStandardPaths::TempLocation) + u'/' + result;
+ if (isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV)) {
+ result = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + u'/' + result;
+ QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, result, key);
+ }
+ return k;
}
-QString QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType,
- QNativeIpcKey::Type type)
+/*!
+ \internal
+ Returns a QNativeIpcKey of type \a type, suitable for QSystemSemaphore or
+ QSharedMemory depending on \a ipcType. The returned native key is generated
+ from the Unicode input \a key and is safe for use on for the key type in
+ question in the current OS.
+*/
+QNativeIpcKey QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType,
+ QNativeIpcKey::Type type)
{
+ QNativeIpcKey k(type);
if (key.isEmpty())
- return key;
+ return k;
switch (type) {
case QNativeIpcKey::Type::PosixRealtime:
- if (!isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime))
- return QString();
+ if (isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime)) {
#ifdef SHM_NAME_MAX
- // The shared memory name limit on Apple platforms is very low (30
- // characters), so we have to cut it down to avoid ENAMETOOLONG. We
- // hope that there won't be too many collisions...
- return u'/' + QStringView(key).left(SHM_NAME_MAX - 1);
+ // The shared memory name limit on Apple platforms is very low (30
+ // characters), so we have to cut it down to avoid ENAMETOOLONG. We
+ // hope that there won't be too many collisions...
+ k.setNativeKey(u'/' + QStringView(key).left(SHM_NAME_MAX - 1));
+#else
+ k.setNativeKey(u'/' + key);
#endif
- return u'/' + key;
+ }
+ return k;
case QNativeIpcKey::Type::Windows:
if (isIpcSupported(ipcType, QNativeIpcKey::Type::Windows)) {
@@ -194,25 +215,27 @@ QString QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcType ip
}
QString result = prefix + mid + payload;
-#ifdef MAX_PATH
+#ifdef Q_OS_WINDOWS
result.truncate(MAX_PATH);
#endif
- return result;
+ k.setNativeKey(result);
}
- return QString();
+ return k;
case QNativeIpcKey::Type::SystemV:
break;
}
// System V
- if (!isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV))
- return QString();
- if (key.startsWith(u'/'))
- return key;
-
- QString baseDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
- return baseDir + u'/' + key;
+ if (isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV)) {
+ if (key.startsWith(u'/')) {
+ k.setNativeKey(key);
+ } else {
+ QString baseDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
+ k.setNativeKey(baseDir + u'/' + key);
+ }
+ }
+ return k;
}
/*!
@@ -221,6 +244,8 @@ QString QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcType ip
\since 6.6
\brief The QNativeIpcKey class holds a native key used by QSystemSemaphore and QSharedMemory.
+ \compares equality
+
The \l QSharedMemory and \l QSystemSemaphore classes identify their
resource using a system-wide identifier known as a "key". The low-level key
value as well as the key type are encapsulated in Qt using the \l
@@ -344,6 +369,12 @@ QNativeIpcKey::Type QNativeIpcKey::defaultTypeForOs_internal() noexcept
#endif
/*!
+ \fn QNativeIpcKey::QNativeIpcKey() noexcept
+
+ Constructs a QNativeIpcKey object of type \l DefaultTypeForOs with an empty key.
+*/
+
+/*!
\fn QNativeIpcKey::QNativeIpcKey(Type type) noexcept
\fn QNativeIpcKey::QNativeIpcKey(const QString &key, Type type)
@@ -361,8 +392,7 @@ QNativeIpcKey::Type QNativeIpcKey::defaultTypeForOs_internal() noexcept
*/
void QNativeIpcKey::copy_internal(const QNativeIpcKey &other)
{
- auto copy = new QNativeIpcKeyPrivate(*other.d_func());
- d = quintptr(copy) & 1;
+ d = new QNativeIpcKeyPrivate(*other.d);
}
void QNativeIpcKey::move_internal(QNativeIpcKey &&) noexcept
@@ -372,21 +402,13 @@ void QNativeIpcKey::move_internal(QNativeIpcKey &&) noexcept
QNativeIpcKey &QNativeIpcKey::assign_internal(const QNativeIpcKey &other)
{
- QNativeIpcKeyPrivate *us = (d & 1) ? d_func() : nullptr;
- const QNativeIpcKeyPrivate *them = (other.d & 1) ? other.d_func() : nullptr;
- if (us && !them) {
- // don't need the extra info, reset to skinny object
- typeAndFlags = {};
- typeAndFlags.type = us->type;
- delete us;
- } else {
- // do need the extra info, so create if necessary
- if (us)
- *us = *them;
- else
- us = new QNativeIpcKeyPrivate(*them);
- d = quintptr(us) | 1;
- }
+ Q_ASSERT(d || other.d); // only 3 cases to handle
+ if (d && !other.d)
+ *d = {};
+ else if (d)
+ *d = *other.d;
+ else
+ d = new QNativeIpcKeyPrivate(*other.d);
return *this;
}
@@ -397,16 +419,22 @@ QNativeIpcKey &QNativeIpcKey::assign_internal(const QNativeIpcKey &other)
*/
void QNativeIpcKey::destroy_internal() noexcept
{
- Q_D(QNativeIpcKey);
delete d;
}
/*!
\fn QNativeIpcKey::swap(QNativeIpcKey &other) noexcept
- \fn swap(QNativeIpcKey &lhs, QNativeIpcKey &rhs) noexcept
- Swaps the native IPC key and type \a other with this object, or \a lhs with
- \a rhs. This operation is very fast and never fails.
+ Swaps the native IPC key and type \a other with this object.
+ This operation is very fast and never fails.
+*/
+
+/*!
+ \fn swap(QNativeIpcKey &value1, QNativeIpcKey &value2) noexcept
+ \relates QNativeIpcKey
+
+ Swaps the native IPC key and type \a value1 with \a value2.
+ This operation is very fast and never fails.
*/
/*!
@@ -437,11 +465,6 @@ void QNativeIpcKey::destroy_internal() noexcept
\sa nativeKey(), setType()
*/
-QNativeIpcKey::Type QNativeIpcKey::type_internal() const noexcept
-{
- Q_D(const QNativeIpcKey);
- return d->type;
-}
/*!
\fn QNativeIpcKey::setType(Type type)
@@ -452,8 +475,7 @@ QNativeIpcKey::Type QNativeIpcKey::type_internal() const noexcept
*/
void QNativeIpcKey::setType_internal(Type type)
{
- Q_D(QNativeIpcKey);
- d->type = type;
+ Q_UNUSED(type);
}
/*!
@@ -473,6 +495,25 @@ void QNativeIpcKey::setType_internal(Type type)
*/
void QNativeIpcKey::setNativeKey_internal(const QString &)
{
+ d->legacyKey_.clear();
+}
+
+/*!
+ \fn size_t QNativeIpcKey::qHash(const QNativeIpcKey &ipcKey) noexcept
+
+ Returns the hash value for \a ipcKey, using a default seed of \c 0.
+*/
+
+/*!
+ \fn size_t QNativeIpcKey::qHash(const QNativeIpcKey &ipcKey, size_t seed) noexcept
+
+ Returns the hash value for \a ipcKey, using \a seed to seed the calculation.
+*/
+size_t qHash(const QNativeIpcKey &ipcKey, size_t seed) noexcept
+{
+ // by *choice*, we're not including d->legacyKey_ in the hash -- it's
+ // already partially encoded in the key
+ return qHashMulti(seed, ipcKey.key, ipcKey.type());
}
/*!
@@ -483,7 +524,7 @@ void QNativeIpcKey::setNativeKey_internal(const QString &)
*/
int QNativeIpcKey::compare_internal(const QNativeIpcKey &lhs, const QNativeIpcKey &rhs) noexcept
{
- return *lhs.d_func() == *rhs.d_func() ? 0 : 1;
+ return (QNativeIpcKeyPrivate::legacyKey(lhs) == QNativeIpcKeyPrivate::legacyKey(rhs)) ? 0 : 1;
}
/*!
@@ -512,6 +553,12 @@ QString QNativeIpcKey::toString() const
QUrl u;
u.setScheme(prefix);
u.setPath(copy, QUrl::TolerantMode);
+ if (isSlowPath()) {
+ QUrlQuery q;
+ if (!d->legacyKey_.isEmpty())
+ q.addQueryItem(u"legacyKey"_s, QString(d->legacyKey_).replace(u'%', "%25"_L1));
+ u.setQuery(q);
+ }
return u.toString(QUrl::DecodeReserved);
}
@@ -540,6 +587,19 @@ QNativeIpcKey QNativeIpcKey::fromString(const QString &text)
// decode the payload
result.setNativeKey(u.path());
+
+ if (u.hasQuery()) {
+ const QList items = QUrlQuery(u).queryItems();
+ for (const auto &item : items) {
+ if (item.first == u"legacyKey"_s) {
+ QString legacyKey = QUrl::fromPercentEncoding(item.second.toUtf8());
+ QNativeIpcKeyPrivate::setLegacyKey(result, std::move(legacyKey));
+ } else {
+ // unknown query item
+ return QNativeIpcKey(invalidType);
+ }
+ }
+ }
return result;
}