File indexing completed on 2024-05-12 04:50:47

0001 /*
0002   This file is part of KDSingleApplication.
0003 
0004   SPDX-FileCopyrightText: 2019-2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
0005 
0006   SPDX-License-Identifier: MIT
0007 
0008   Contact KDAB at <info@kdab.com> for commercial licensing options.
0009 */
0010 
0011 #ifndef KDSINGLEAPPLICATION_LOCALSOCKET_P_H
0012 #define KDSINGLEAPPLICATION_LOCALSOCKET_P_H
0013 
0014 #include <QtCore/QObject>
0015 #include <QtCore/QByteArray>
0016 #include <QtCore/QString>
0017 
0018 QT_BEGIN_NAMESPACE
0019 class QLockFile;
0020 class QLocalServer;
0021 class QLocalSocket;
0022 class QTimer;
0023 QT_END_NAMESPACE
0024 
0025 #include <memory>
0026 #include <vector>
0027 
0028 struct QObjectDeleteLater
0029 {
0030     void operator()(QObject *o)
0031     {
0032         o->deleteLater();
0033     }
0034 };
0035 
0036 class QObjectConnectionHolder
0037 {
0038     Q_DISABLE_COPY(QObjectConnectionHolder)
0039     QMetaObject::Connection c;
0040 
0041 public:
0042     QObjectConnectionHolder()
0043     {
0044     }
0045 
0046     explicit QObjectConnectionHolder(QMetaObject::Connection _c)
0047         : c(std::move(_c))
0048     {
0049     }
0050 
0051     ~QObjectConnectionHolder()
0052     {
0053         QObject::disconnect(c);
0054     }
0055 
0056     QObjectConnectionHolder(QObjectConnectionHolder &&other) noexcept
0057         : c(std::exchange(other.c, {}))
0058     {
0059     }
0060 
0061     QObjectConnectionHolder &operator=(QObjectConnectionHolder &&other) noexcept
0062     {
0063         QObjectConnectionHolder moved(std::move(other));
0064         swap(moved);
0065         return *this;
0066     }
0067 
0068     void swap(QObjectConnectionHolder &other) noexcept
0069     {
0070         using std::swap;
0071         swap(c, other.c);
0072     }
0073 };
0074 
0075 class KDSingleApplicationLocalSocket : public QObject
0076 {
0077     Q_OBJECT
0078 
0079 public:
0080     explicit KDSingleApplicationLocalSocket(const QString &name,
0081                                             QObject *parent = nullptr);
0082     ~KDSingleApplicationLocalSocket();
0083 
0084     bool isPrimaryInstance() const;
0085 
0086 public Q_SLOTS:
0087     bool sendMessage(const QByteArray &message, int timeout);
0088 
0089 Q_SIGNALS:
0090     void messageReceived(const QByteArray &message);
0091 
0092 private:
0093     void handleNewConnection();
0094     void readDataFromSecondary();
0095     bool readDataFromSecondarySocket(QLocalSocket *socket);
0096     void secondaryDisconnected();
0097     void secondarySocketDisconnected(QLocalSocket *socket);
0098     void abortConnectionToSecondary();
0099 
0100     QString m_socketName;
0101 
0102     std::unique_ptr<QLockFile> m_lockFile; // protects m_localServer
0103     std::unique_ptr<QLocalServer> m_localServer;
0104 
0105     struct Connection
0106     {
0107         explicit Connection(QLocalSocket *s);
0108 
0109         std::unique_ptr<QLocalSocket, QObjectDeleteLater> socket;
0110         std::unique_ptr<QTimer, QObjectDeleteLater> timeoutTimer;
0111         QByteArray readData;
0112 
0113         // socket/timeoutTimer are deleted via deleteLater (as we delete them
0114         // in slots connected to their signals). Before the deleteLater is acted upon,
0115         // they may emit further signals, triggering logic that it's not supposed
0116         // to be triggered (as the Connection has already been destroyed).
0117         // Use this Holder to break the connections.
0118         QObjectConnectionHolder readDataConnection;
0119         QObjectConnectionHolder secondaryDisconnectedConnection;
0120         QObjectConnectionHolder abortConnection;
0121     };
0122 
0123     std::vector<Connection> m_clients;
0124 };
0125 
0126 #endif // KDSINGLEAPPLICATION_LOCALSOCKET_P_H