#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(); }