diff --git a/qt/logger.cpp b/qt/logger.cpp new file mode 100644 index 0000000..d8a3e57 --- /dev/null +++ b/qt/logger.cpp @@ -0,0 +1,45 @@ +#include "logger.h" + +#include + +Logger::Logger(QObject *parent) + : QObject(parent), + socket(Q_NULLPTR) +{ + +} + +bool Logger::init(const QString &tag) +{ + this->tag = tag; + if (socket == Q_NULLPTR) + socket = new UnixDomainDatagramSocket(this); + + return socket->open(); +} + +void Logger::print(const QString &string) +{ + QByteArray bytes(string.toLocal8Bit().data()); + bytes.prepend(' ').prepend(tag.toLocal8Bit().data()); + + qDebug() << bytes; + + socket->writeDatagram(bytes, "/tmp/logger.uds"); +} + +void Logger::hexdump(const QString &message, const QByteArray &bytes) +{ + QByteArray line; + line += tag + " " + message + " ["; + for (int i = 0; i < bytes.length(); i++) + { + line += QByteArray::number(uchar(bytes.at(i)), 16).toUpper(); + line += " "; + } + line = line.trimmed(); + line += "]\n"; + + qDebug() << line; + socket->writeDatagram(line, "/tmp/logger.uds"); +} diff --git a/qt/logger.h b/qt/logger.h new file mode 100644 index 0000000..d8920db --- /dev/null +++ b/qt/logger.h @@ -0,0 +1,29 @@ +// Logger는 pool sw의 app-logger를 사용할 수 있게 해준다. + +#ifndef LOGGER_H +#define LOGGER_H + +#include + +#include "unixdomaindatagramsocket.h" + +class Logger : public QObject +{ + Q_OBJECT +public: + explicit Logger(QObject *parent = nullptr); + + bool init(const QString &tag); + +signals: + +public slots: + void print(const QString &string); + void hexdump(const QString &message, const QByteArray &bytes); + +private: + UnixDomainDatagramSocket *socket; + QString tag; +}; + +#endif // LOGGER_H diff --git a/qt/unixdomaindatagramsocket.cpp b/qt/unixdomaindatagramsocket.cpp new file mode 100644 index 0000000..159f621 --- /dev/null +++ b/qt/unixdomaindatagramsocket.cpp @@ -0,0 +1,152 @@ +#include "unixdomaindatagramsocket.h" + +#include + +#include +#include +#include +#include +#include + +UnixDomainDatagramSocket::UnixDomainDatagramSocket(QObject *parent) + : QObject(parent), + sockfd(-1), notifier(Q_NULLPTR) +{ + +} + +UnixDomainDatagramSocket::~UnixDomainDatagramSocket() +{ + if (sockfd >= 0) + close(sockfd); + + if (!boundPath.isEmpty()) + unlink(boundPath.toLocal8Bit().data()); +} + +bool UnixDomainDatagramSocket::open() +{ + if (sockfd >= 0) + return false; + + sockfd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (sockfd < 0) + return false; + + notifier = new QSocketNotifier(sockfd, QSocketNotifier::Read, this); + connect(notifier, SIGNAL(activated(int)), SLOT(emitReadyRead())); + + return true; +} + +bool UnixDomainDatagramSocket::bind(const QString &path) +{ + return bind(path.toLocal8Bit().data()); +} + +bool UnixDomainDatagramSocket::bind(const char *path) +{ + if (sockfd < 0 && !open()) + return false; + + unlink(path); + + struct sockaddr_un address; + address.sun_family = AF_UNIX; + strncpy(address.sun_path, path, sizeof(address.sun_path)); + + int ret = ::bind(sockfd, reinterpret_cast(&address), sizeof(address)); + if (ret == -1) + return false; + + return true; +} + +bool UnixDomainDatagramSocket::hasPendingDatagrams() +{ + ssize_t readBytes; + do + { + char c; + readBytes = ::recv(sockfd, &c, 1, MSG_DONTWAIT | MSG_PEEK); + } + while (readBytes == -1 && errno == EINTR); + + return (readBytes != -1) || errno == EMSGSIZE; +} + +qint64 UnixDomainDatagramSocket::pendingDatagramSize() +{ + QVarLengthArray udpMessagePeekBuffer(8192); + ssize_t recvResult = -1; + + for (;;) + { + recvResult = ::recv(sockfd, udpMessagePeekBuffer.data(), + size_t(udpMessagePeekBuffer.size()), MSG_DONTWAIT | MSG_PEEK); + if (recvResult == -1 && errno == EINTR) + continue; + + if (recvResult != ssize_t(udpMessagePeekBuffer.size())) + break; + + udpMessagePeekBuffer.resize(udpMessagePeekBuffer.size() * 2); + } + + return qint64(recvResult); +} + +qint64 UnixDomainDatagramSocket::readDatagram(QByteArray *datagram, QString *path) +{ + return readDatagram(datagram->data(), datagram->size(), path); +} + +qint64 UnixDomainDatagramSocket::readDatagram(char *data, qint64 maxSize, QString *path) +{ + if (!notifier->isEnabled()) + notifier->setEnabled(true); + + struct sockaddr_un address; + socklen_t length; + + ssize_t recvResult; + do + { + recvResult = ::recvfrom(sockfd, data, size_t(maxSize), 0, reinterpret_cast(&address), &length); + } + while (recvResult == -1 && errno == EINTR); + + if (recvResult == -1) + return -1; + + if (path) + *path = QString::fromLocal8Bit(address.sun_path); + + return recvResult; +} + +qint64 UnixDomainDatagramSocket::writeDatagram(const QByteArray &datagram, const QString &path) +{ + return writeDatagram(datagram.data(), datagram.size(), path); +} + +qint64 UnixDomainDatagramSocket::writeDatagram(const char *data, qint64 size, const QString &path) +{ + return writeDatagram(data, size, path.toLocal8Bit().data()); +} + +qint64 UnixDomainDatagramSocket::writeDatagram(const char *data, qint64 size, const char *path) +{ + struct sockaddr_un address; + address.sun_family = AF_UNIX; + strncpy(address.sun_path, path, sizeof(address.sun_path)); + + ssize_t sendResult = ::sendto(sockfd, data, size_t(size), 0, reinterpret_cast(&address), sizeof(address)); + return qint64(sendResult); +} + +void UnixDomainDatagramSocket::emitReadyRead() +{ + notifier->setEnabled(false); + emit readyRead(); +} diff --git a/qt/unixdomaindatagramsocket.h b/qt/unixdomaindatagramsocket.h new file mode 100644 index 0000000..419f35d --- /dev/null +++ b/qt/unixdomaindatagramsocket.h @@ -0,0 +1,44 @@ +// UnixDomainDatagramSocket은 UDS를 데이터그램 형식으로 사용하는 소켓 구현체다. QUdpSocket처럼 사용하도록 구현했다. +// +// 주의: 자동 변수 대신 new로 할당하라. 소멸자에서 열린 소켓을 닫고 만든 파일을 지우기 때문에 문제가 생길 수 있다. + +#ifndef UNIXDOMAINDATAGRAMSOCKET_H +#define UNIXDOMAINDATAGRAMSOCKET_H + +#include +#include + +class UnixDomainDatagramSocket : public QObject +{ + Q_OBJECT +public: + explicit UnixDomainDatagramSocket(QObject *parent = Q_NULLPTR); + ~UnixDomainDatagramSocket(); + + bool open(); + bool bind(const QString &path); + bool bind(const char *path); + + bool hasPendingDatagrams(); + qint64 pendingDatagramSize(); + qint64 readDatagram(QByteArray *datagram, QString *path = Q_NULLPTR); + qint64 readDatagram(char *data, qint64 maxSize, QString *path = Q_NULLPTR); + qint64 writeDatagram(const QByteArray &datagram, const QString &path); + qint64 writeDatagram(const char *data, qint64 size, const QString &path); + qint64 writeDatagram(const char *data, qint64 size, const char *path); + +signals: + void readyRead(); + +public slots: + +private: + int sockfd; + QString boundPath; + QSocketNotifier *notifier; + +private slots: + void emitReadyRead(); +}; + +#endif // UNIXDOMAINDATAGRAMSOCKET_H