Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qudpsocket.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
6//#define QUDPSOCKET_DEBUG
7
8/*! \class QUdpSocket
9
10 \reentrant
11 \brief The QUdpSocket class provides a UDP socket.
12
13 \ingroup network
14 \inmodule QtNetwork
15
16 UDP (User Datagram Protocol) is a lightweight, unreliable,
17 datagram-oriented, connectionless protocol. It can be used when
18 reliability isn't important. QUdpSocket is a subclass of
19 QAbstractSocket that allows you to send and receive UDP
20 datagrams.
21
22 The most common way to use this class is to bind to an address and port
23 using bind(), then call writeDatagram() and readDatagram() /
24 receiveDatagram() to transfer data. If you want to use the standard
25 QIODevice functions read(), readLine(), write(), etc., you must first
26 connect the socket directly to a peer by calling connectToHost().
27
28 The socket emits the bytesWritten() signal every time a datagram
29 is written to the network. If you just want to send datagrams,
30 you don't need to call bind().
31
32 The readyRead() signal is emitted whenever datagrams arrive. In
33 that case, hasPendingDatagrams() returns \c true. Call
34 pendingDatagramSize() to obtain the size of the first pending
35 datagram, and readDatagram() or receiveDatagram() to read it.
36
37 \note An incoming datagram should be read when you receive the readyRead()
38 signal, otherwise this signal will not be emitted for the next datagram.
39
40 Example:
41
42 \snippet code/src_network_socket_qudpsocket.cpp 0
43
44 QUdpSocket also supports UDP multicast. Use joinMulticastGroup() and
45 leaveMulticastGroup() to control group membership, and
46 QAbstractSocket::MulticastTtlOption and
47 QAbstractSocket::MulticastLoopbackOption to set the TTL and loopback socket
48 options. Use setMulticastInterface() to control the outgoing interface for
49 multicast datagrams, and multicastInterface() to query it.
50
51 With QUdpSocket, you can also establish a virtual connection to a
52 UDP server using connectToHost() and then use read() and write()
53 to exchange datagrams without specifying the receiver for each
54 datagram.
55
56 The \l{broadcastsender}{Broadcast Sender},
57 \l{broadcastreceiver}{Broadcast Receiver},
58 \l{multicastsender}{Multicast Sender}, and
59 \l{multicastreceiver}{Multicast Receiver} examples illustrate how
60 to use QUdpSocket in applications.
61
62 \sa QTcpSocket, QNetworkDatagram
63*/
64
65#include "qudpsocket.h"
66#include "qhostaddress.h"
71
72QT_BEGIN_NAMESPACE
73
74#ifndef QT_NO_UDPSOCKET
75
76#define QT_CHECK_BOUND(function, a) do {
77 if (!isValid()) {
78 qWarning(function" called on a QUdpSocket when not in QUdpSocket::BoundState");
79 return (a);
80 } } while (0)
81
82class QUdpSocketPrivate : public QAbstractSocketPrivate
83{
84 Q_DECLARE_PUBLIC(QUdpSocket)
85
86 bool doEnsureInitialized(const QHostAddress &bindAddress, quint16 bindPort,
87 const QHostAddress &remoteAddress);
88public:
89 inline bool ensureInitialized(const QHostAddress &bindAddress, quint16 bindPort)
90 { return doEnsureInitialized(bindAddress, bindPort, QHostAddress()); }
91
92 inline bool ensureInitialized(const QHostAddress &remoteAddress)
93 { return doEnsureInitialized(QHostAddress(), 0, remoteAddress); }
94};
95
96bool QUdpSocketPrivate::doEnsureInitialized(const QHostAddress &bindAddress, quint16 bindPort,
97 const QHostAddress &remoteAddress)
98{
99 const QHostAddress *address = &bindAddress;
100 QAbstractSocket::NetworkLayerProtocol proto = address->protocol();
101 if (proto == QUdpSocket::UnknownNetworkLayerProtocol) {
102 address = &remoteAddress;
103 proto = address->protocol();
104 }
105
106 // now check if the socket engine is initialized and to the right type
107 if (!socketEngine || !socketEngine->isValid()) {
108 resolveProxy(remoteAddress.toString(), bindPort);
109 if (!initSocketLayer(address->protocol()))
110 return false;
111 }
112
113 return true;
114}
115
116/*!
117 Creates a QUdpSocket object.
118
119 \a parent is passed to the QObject constructor.
120
121 \sa socketType()
122*/
123QUdpSocket::QUdpSocket(QObject *parent)
124 : QAbstractSocket(UdpSocket, *new QUdpSocketPrivate, parent)
125{
126 d_func()->isBuffered = false;
127}
128
129/*!
130 Destroys the socket, closing the connection if necessary.
131
132 \sa close()
133*/
134QUdpSocket::~QUdpSocket()
135{
136}
137
138#ifndef QT_NO_NETWORKINTERFACE
139
140/*!
141 \since 4.8
142
143 Joins the multicast group specified by \a groupAddress on the default
144 interface chosen by the operating system. The socket must be in BoundState,
145 otherwise an error occurs.
146
147 Note that if you are attempting to join an IPv4 group, your socket must not
148 be bound using IPv6 (or in dual mode, using QHostAddress::Any). You must use
149 QHostAddress::AnyIPv4 instead.
150
151 This function returns \c true if successful; otherwise it returns \c false
152 and sets the socket error accordingly.
153
154 \note Joining IPv6 multicast groups without an interface selection is not
155 supported in all operating systems. Consider using the overload where the
156 interface is specified.
157
158 \sa leaveMulticastGroup()
159*/
160bool QUdpSocket::joinMulticastGroup(const QHostAddress &groupAddress)
161{
162 return joinMulticastGroup(groupAddress, QNetworkInterface());
163}
164
165/*!
166 \since 4.8
167 \overload
168
169 Joins the multicast group address \a groupAddress on the interface \a
170 iface.
171
172 \sa leaveMulticastGroup()
173*/
174bool QUdpSocket::joinMulticastGroup(const QHostAddress &groupAddress,
175 const QNetworkInterface &iface)
176{
177 Q_D(QUdpSocket);
178 QT_CHECK_BOUND("QUdpSocket::joinMulticastGroup()", false);
179 return d->socketEngine->joinMulticastGroup(groupAddress, iface);
180}
181
182/*!
183 \since 4.8
184
185 Leaves the multicast group specified by \a groupAddress on the default
186 interface chosen by the operating system. The socket must be in BoundState,
187 otherwise an error occurs.
188
189 This function returns \c true if successful; otherwise it returns \c false and
190 sets the socket error accordingly.
191
192 \note This function should be called with the same arguments as were passed
193 to joinMulticastGroup().
194
195 \sa joinMulticastGroup()
196*/
197bool QUdpSocket::leaveMulticastGroup(const QHostAddress &groupAddress)
198{
199 return leaveMulticastGroup(groupAddress, QNetworkInterface());
200}
201
202/*!
203 \since 4.8
204 \overload
205
206 Leaves the multicast group specified by \a groupAddress on the interface \a
207 iface.
208
209 \note This function should be called with the same arguments as were passed
210 to joinMulticastGroup().
211
212 \sa joinMulticastGroup()
213*/
214bool QUdpSocket::leaveMulticastGroup(const QHostAddress &groupAddress,
215 const QNetworkInterface &iface)
216{
217 QT_CHECK_BOUND("QUdpSocket::leaveMulticastGroup()", false);
218 return d_func()->socketEngine->leaveMulticastGroup(groupAddress, iface);
219}
220
221/*!
222 \since 4.8
223
224 Returns the interface for the outgoing interface for multicast datagrams.
225 This corresponds to the IP_MULTICAST_IF socket option for IPv4 sockets and
226 the IPV6_MULTICAST_IF socket option for IPv6 sockets. If no interface has
227 been previously set, this function returns an invalid QNetworkInterface.
228 The socket must be in BoundState, otherwise an invalid QNetworkInterface is
229 returned.
230
231 \sa setMulticastInterface()
232*/
233QNetworkInterface QUdpSocket::multicastInterface() const
234{
235 Q_D(const QUdpSocket);
236 QT_CHECK_BOUND("QUdpSocket::multicastInterface()", QNetworkInterface());
237 return d->socketEngine->multicastInterface();
238}
239
240/*!
241 \since 4.8
242
243 Sets the outgoing interface for multicast datagrams to the interface \a
244 iface. This corresponds to the IP_MULTICAST_IF socket option for IPv4
245 sockets and the IPV6_MULTICAST_IF socket option for IPv6 sockets. The
246 socket must be in BoundState, otherwise this function does nothing.
247
248 \sa multicastInterface(), joinMulticastGroup(), leaveMulticastGroup()
249*/
250void QUdpSocket::setMulticastInterface(const QNetworkInterface &iface)
251{
252 Q_D(QUdpSocket);
253 if (!isValid()) {
254 qWarning("QUdpSocket::setMulticastInterface() called on a QUdpSocket when not in QUdpSocket::BoundState");
255 return;
256 }
257 d->socketEngine->setMulticastInterface(iface);
258}
259
260#endif // QT_NO_NETWORKINTERFACE
261
262/*!
263 Returns \c true if at least one datagram is waiting to be read;
264 otherwise returns \c false.
265
266 \sa pendingDatagramSize(), readDatagram()
267*/
268bool QUdpSocket::hasPendingDatagrams() const
269{
270 QT_CHECK_BOUND("QUdpSocket::hasPendingDatagrams()", false);
271 return d_func()->socketEngine->hasPendingDatagrams();
272}
273
274/*!
275 Returns the size of the first pending UDP datagram. If there is
276 no datagram available, this function returns -1.
277
278 \sa hasPendingDatagrams(), readDatagram()
279*/
280qint64 QUdpSocket::pendingDatagramSize() const
281{
282 QT_CHECK_BOUND("QUdpSocket::pendingDatagramSize()", -1);
283 return d_func()->socketEngine->pendingDatagramSize();
284}
285
286/*!
287 Sends the datagram at \a data of size \a size to the host
288 address \a address at port \a port. Returns the number of
289 bytes sent on success; otherwise returns -1.
290
291 Datagrams are always written as one block. The maximum size of a
292 datagram is highly platform-dependent, but can be as low as 8192
293 bytes. If the datagram is too large, this function will return -1
294 and error() will return DatagramTooLargeError.
295
296 Sending datagrams larger than 512 bytes is in general disadvised,
297 as even if they are sent successfully, they are likely to be
298 fragmented by the IP layer before arriving at their final
299 destination.
300
301 \warning Calling this function on a connected UDP socket may
302 result in an error and no packet being sent. If you are using a
303 connected socket, use write() to send datagrams.
304
305 \sa readDatagram(), write()
306*/
307qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddress &address,
308 quint16 port)
309{
310 Q_D(QUdpSocket);
311#if defined QUDPSOCKET_DEBUG
312 qDebug("QUdpSocket::writeDatagram(%p, %llu, \"%s\", %i)", data, size,
313 address.toString().toLatin1().constData(), port);
314#endif
315 if (!d->doEnsureInitialized(QHostAddress::Any, 0, address))
316 return -1;
317 if (state() == UnconnectedState)
318 bind();
319
320 qint64 sent = d->socketEngine->writeDatagram(data, size, QIpPacketHeader(address, port));
321 d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
322
323 if (sent >= 0) {
324 emit bytesWritten(sent);
325 } else {
326 if (sent == -2) {
327 // Socket engine reports EAGAIN. Treat as a temporary error.
328 d->setErrorAndEmit(QAbstractSocket::TemporaryError,
329 tr("Unable to send a datagram"));
330 return -1;
331 }
332 d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
333 }
334 return sent;
335}
336
337/*!
338 \fn qint64 QUdpSocket::writeDatagram(const QByteArray &datagram,
339 const QHostAddress &host, quint16 port)
340 \overload
341
342 Sends the datagram \a datagram to the host address \a host and at
343 port \a port.
344
345 The function returns the number of bytes sent if it succeeded or -1 if it
346 encountered an error.
347*/
348
349/*!
350 \since 5.8
351 \overload
352
353 Sends the datagram \a datagram to the host address and port numbers
354 contained in \a datagram, using the network interface and hop count limits
355 also set there. If the destination address and port numbers are unset, this
356 function will send to the address that was passed to connectToHost().
357
358 If the destination address is IPv6 with a non-empty
359 \l{QHostAddress::scopeId()}{scope id} but differs from the interface index
360 in \a datagram, it is undefined which interface the operating system will
361 choose to send on.
362
363 The function returns the number of bytes sent if it succeeded or -1 if it
364 encountered an error.
365
366 \warning Calling this function on a connected UDP socket may
367 result in an error and no packet being sent. If you are using a
368 connected socket, use write() to send datagrams.
369
370 \sa QNetworkDatagram::setDestination(), QNetworkDatagram::setHopLimit(), QNetworkDatagram::setInterfaceIndex()
371*/
372qint64 QUdpSocket::writeDatagram(const QNetworkDatagram &datagram)
373{
374 Q_D(QUdpSocket);
375#if defined QUDPSOCKET_DEBUG
376 qDebug("QUdpSocket::writeDatagram(%p, %i, \"%s\", %i)",
377 datagram.d->data.constData(),
378 datagram.d->data.size(),
379 datagram.destinationAddress().toString().toLatin1().constData(),
380 datagram.destinationPort());
381#endif
382 if (!d->doEnsureInitialized(QHostAddress::Any, 0, datagram.destinationAddress()))
383 return -1;
384 if (state() == UnconnectedState)
385 bind();
386
387 qint64 sent = d->socketEngine->writeDatagram(datagram.d->data.constData(),
388 datagram.d->data.size(),
389 datagram.d->header);
390 d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
391
392 if (sent >= 0) {
393 emit bytesWritten(sent);
394 } else {
395 d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
396 }
397 return sent;
398}
399
400/*!
401 \since 5.8
402
403 Receives a datagram no larger than \a maxSize bytes and returns it in the
404 QNetworkDatagram object, along with the sender's host address and port. If
405 possible, this function will also try to determine the datagram's
406 destination address, port, and the number of hop counts at reception time.
407
408 On failure, returns a QNetworkDatagram that reports \l
409 {QNetworkDatagram::isValid()}{not valid}.
410
411 If \a maxSize is too small, the rest of the datagram will be lost. If \a
412 maxSize is 0, the datagram will be discarded. If \a maxSize is -1 (the
413 default), this function will attempt to read the entire datagram.
414
415 \sa writeDatagram(), hasPendingDatagrams(), pendingDatagramSize()
416*/
417QNetworkDatagram QUdpSocket::receiveDatagram(qint64 maxSize)
418{
419 Q_D(QUdpSocket);
420
421#if defined QUDPSOCKET_DEBUG
422 qDebug("QUdpSocket::receiveDatagram(%lld)", maxSize);
423#endif
424 QT_CHECK_BOUND("QUdpSocket::receiveDatagram()", QNetworkDatagram());
425
426 if (maxSize < 0)
427 maxSize = d->socketEngine->pendingDatagramSize();
428 if (maxSize < 0)
429 return QNetworkDatagram();
430
431 QNetworkDatagram result(QByteArray(maxSize, Qt::Uninitialized));
432 qint64 readBytes = d->socketEngine->readDatagram(result.d->data.data(), maxSize, &result.d->header,
433 QAbstractSocketEngine::WantAll);
434 d->hasPendingData = false;
435 d->hasPendingDatagram = false;
436 d->socketEngine->setReadNotificationEnabled(true);
437 if (readBytes < 0) {
438 d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
439 readBytes = 0;
440 }
441
442 result.d->data.truncate(readBytes);
443 return result;
444}
445
446/*!
447 Receives a datagram no larger than \a maxSize bytes and stores
448 it in \a data. The sender's host address and port is stored in
449 *\a address and *\a port (unless the pointers are \nullptr).
450
451 Returns the size of the datagram on success; otherwise returns
452 -1.
453
454 If \a maxSize is too small, the rest of the datagram will be
455 lost. To avoid loss of data, call pendingDatagramSize() to
456 determine the size of the pending datagram before attempting to
457 read it. If \a maxSize is 0, the datagram will be discarded.
458
459 \sa writeDatagram(), hasPendingDatagrams(), pendingDatagramSize()
460*/
461qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *address,
462 quint16 *port)
463{
464 Q_D(QUdpSocket);
465
466#if defined QUDPSOCKET_DEBUG
467 qDebug("QUdpSocket::readDatagram(%p, %llu, %p, %p)", data, maxSize, address, port);
468#endif
469 QT_CHECK_BOUND("QUdpSocket::readDatagram()", -1);
470
471 qint64 readBytes;
472 if (address || port) {
473 QIpPacketHeader header;
474 readBytes = d->socketEngine->readDatagram(data, maxSize, &header,
475 QAbstractSocketEngine::WantDatagramSender);
476 if (address)
477 *address = header.senderAddress;
478 if (port)
479 *port = header.senderPort;
480 } else {
481 readBytes = d->socketEngine->readDatagram(data, maxSize);
482 }
483
484 d->hasPendingData = false;
485 d->hasPendingDatagram = false;
486 d->socketEngine->setReadNotificationEnabled(true);
487 if (readBytes < 0) {
488 if (readBytes == -2) {
489 // No pending datagram. Treat as a temporary error.
490 d->setErrorAndEmit(QAbstractSocket::TemporaryError,
491 tr("No datagram available for reading"));
492 return -1;
493 }
494 d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
495 }
496 return readBytes;
497}
498
499#endif // QT_NO_UDPSOCKET
500
501QT_END_NAMESPACE
502
503#include "moc_qudpsocket.cpp"
#define QT_CHECK_BOUND(function, a)