File indexing completed on 2024-04-28 16:51:32
0001 /* 0002 SPDX-FileCopyrightText: 2017 Kai Uwe Broulik <kde@privat.broulik.de> 0003 SPDX-FileCopyrightText: 2017 David Edmundson <davidedmundson@kde.org> 0004 0005 SPDX-License-Identifier: MIT 0006 */ 0007 0008 #include "connection.h" 0009 #include <QCoreApplication> 0010 #include <QJsonDocument> 0011 #include <QSocketNotifier> 0012 0013 #include <QDebug> 0014 #include <poll.h> 0015 #include <unistd.h> 0016 0017 Connection::Connection() 0018 : QObject() 0019 { 0020 // Make really sure no one but us, who uses the correct format, prints to stdout 0021 int newStdout = dup(STDOUT_FILENO); 0022 // redirect it to stderr so it's not just swallowed 0023 dup2(STDERR_FILENO, STDOUT_FILENO); 0024 m_stdOut.open(newStdout, QIODevice::WriteOnly); 0025 0026 m_stdIn.open(STDIN_FILENO, QIODevice::ReadOnly | QIODevice::Unbuffered); 0027 0028 auto notifier = new QSocketNotifier(STDIN_FILENO, QSocketNotifier::Read, this); 0029 connect(notifier, &QSocketNotifier::activated, this, &Connection::readData); 0030 } 0031 0032 void Connection::sendData(const QJsonObject &data) 0033 { 0034 const QByteArray rawData = QJsonDocument(data).toJson(QJsonDocument::Compact); 0035 // note, don't use QDataStream as we need to control the binary format used 0036 quint32 len = rawData.count(); 0037 m_stdOut.write((char *)&len, sizeof(len)); 0038 m_stdOut.write(rawData); 0039 m_stdOut.flush(); 0040 } 0041 0042 Connection *Connection::self() 0043 { 0044 static Connection *s = nullptr; 0045 if (!s) { 0046 s = new Connection(); 0047 } 0048 return s; 0049 } 0050 0051 void Connection::readData() 0052 { 0053 /* Qt does not recognize POLLHUP as an error and 0054 * as that flag never gets cleared, we enter an 0055 * infinite busy loop polling STDIN. 0056 * So we need to check for this condition ourselves 0057 * and exit. */ 0058 0059 struct pollfd poll_stdin = {}; 0060 poll_stdin.fd = STDIN_FILENO; 0061 poll_stdin.events = POLLHUP; 0062 poll_stdin.revents = 0; 0063 0064 if (poll(&poll_stdin, 1, 0) != 0) { 0065 // STDIN has HUP/ERR/NVAL condition 0066 qApp->exit(0); 0067 return; 0068 } 0069 0070 m_stdIn.startTransaction(); 0071 quint32 length = 0; 0072 auto rc = m_stdIn.read((char *)(&length), sizeof(quint32)); 0073 if (rc == -1) { 0074 m_stdIn.rollbackTransaction(); 0075 return; 0076 } 0077 0078 QByteArray data = m_stdIn.read(length); 0079 if (data.length() != int(length)) { 0080 m_stdIn.rollbackTransaction(); 0081 return; 0082 } 0083 0084 if (data.isEmpty()) { 0085 m_stdIn.rollbackTransaction(); 0086 return; 0087 } 0088 0089 m_stdIn.commitTransaction(); 0090 const QJsonObject json = QJsonDocument::fromJson(data).object(); 0091 Q_EMIT dataReceived(json); 0092 }