unixdomaindatagramsocket.cpp
3.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include "unixdomaindatagramsocket.h"
#include <QVarLengthArray>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <linux/sockios.h>
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<struct sockaddr *>(&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<char, 8192> 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<struct sockaddr *>(&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<struct sockaddr *>(&address), sizeof(address));
return qint64(sendResult);
}
void UnixDomainDatagramSocket::emitReadyRead()
{
notifier->setEnabled(false);
emit readyRead();
}