Coverage Report

Created: 2026-04-29 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/network/socket/qudpsocket.cpp
Line
Count
Source
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"
67
#include "qnetworkdatagram.h"
68
#include "qnetworkinterface.h"
69
#include "qabstractsocket_p.h"
70
#include "qabstractsocketengine_p.h"
71
72
QT_BEGIN_NAMESPACE
73
74
#ifndef QT_NO_UDPSOCKET
75
76
0
#define QT_CHECK_BOUND(function, a) do { \
77
0
    if (!isValid()) { \
78
0
        qWarning(function" called on a QUdpSocket when not in QUdpSocket::BoundState"); \
79
0
        return (a); \
80
0
    } } while (0)
81
82
class QUdpSocketPrivate : public QAbstractSocketPrivate
83
{
84
0
    Q_DECLARE_PUBLIC(QUdpSocket)
Unexecuted instantiation: QUdpSocketPrivate::q_func()
Unexecuted instantiation: QUdpSocketPrivate::q_func() const
85
0
86
0
    bool doEnsureInitialized(const QHostAddress &bindAddress, quint16 bindPort,
87
0
                             const QHostAddress &remoteAddress);
88
0
public:
89
0
    inline bool ensureInitialized(const QHostAddress &bindAddress, quint16 bindPort)
90
0
    { return doEnsureInitialized(bindAddress, bindPort, QHostAddress()); }
91
92
    inline bool ensureInitialized(const QHostAddress &remoteAddress)
93
0
    { return doEnsureInitialized(QHostAddress(), 0, remoteAddress); }
94
};
95
96
bool QUdpSocketPrivate::doEnsureInitialized(const QHostAddress &bindAddress, quint16 bindPort,
97
                                            const QHostAddress &remoteAddress)
98
0
{
99
0
    const QHostAddress *address = &bindAddress;
100
0
    QAbstractSocket::NetworkLayerProtocol proto = address->protocol();
101
0
    if (proto == QUdpSocket::UnknownNetworkLayerProtocol) {
102
0
        address = &remoteAddress;
103
0
        proto = address->protocol();
104
0
    }
105
106
    // now check if the socket engine is initialized and to the right type
107
0
    if (!socketEngine || !socketEngine->isValid()) {
108
0
        resolveProxy(remoteAddress.toString(), bindPort);
109
0
        if (!initSocketLayer(address->protocol()))
110
0
            return false;
111
0
    }
112
113
0
    return true;
114
0
}
115
116
/*!
117
    Creates a QUdpSocket object.
118
119
    \a parent is passed to the QObject constructor.
120
121
    \sa socketType()
122
*/
123
QUdpSocket::QUdpSocket(QObject *parent)
124
0
    : QAbstractSocket(UdpSocket, *new QUdpSocketPrivate, parent)
125
0
{
126
0
    d_func()->isBuffered = false;
127
0
}
128
129
/*!
130
    Destroys the socket, closing the connection if necessary.
131
132
    \sa close()
133
*/
134
QUdpSocket::~QUdpSocket()
135
0
{
136
0
}
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
*/
160
bool QUdpSocket::joinMulticastGroup(const QHostAddress &groupAddress)
161
0
{
162
0
    return joinMulticastGroup(groupAddress, QNetworkInterface());
163
0
}
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
*/
174
bool QUdpSocket::joinMulticastGroup(const QHostAddress &groupAddress,
175
                                    const QNetworkInterface &iface)
176
0
{
177
0
    Q_D(QUdpSocket);
178
0
    QT_CHECK_BOUND("QUdpSocket::joinMulticastGroup()", false);
179
0
    return d->socketEngine->joinMulticastGroup(groupAddress, iface);
180
0
}
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
*/
197
bool QUdpSocket::leaveMulticastGroup(const QHostAddress &groupAddress)
198
0
{
199
0
    return leaveMulticastGroup(groupAddress, QNetworkInterface());
200
0
}
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
*/
214
bool QUdpSocket::leaveMulticastGroup(const QHostAddress &groupAddress,
215
                                     const QNetworkInterface &iface)
216
0
{
217
0
    QT_CHECK_BOUND("QUdpSocket::leaveMulticastGroup()", false);
218
0
    return d_func()->socketEngine->leaveMulticastGroup(groupAddress, iface);
219
0
}
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
*/
233
QNetworkInterface QUdpSocket::multicastInterface() const
234
0
{
235
0
    Q_D(const QUdpSocket);
236
0
    QT_CHECK_BOUND("QUdpSocket::multicastInterface()", QNetworkInterface());
237
0
    return d->socketEngine->multicastInterface();
238
0
}
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
*/
250
void QUdpSocket::setMulticastInterface(const QNetworkInterface &iface)
251
0
{
252
0
    Q_D(QUdpSocket);
253
0
    if (!isValid()) {
254
0
        qWarning("QUdpSocket::setMulticastInterface() called on a QUdpSocket when not in QUdpSocket::BoundState");
255
0
        return;
256
0
    }
257
0
    d->socketEngine->setMulticastInterface(iface);
258
0
}
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
*/
268
bool QUdpSocket::hasPendingDatagrams() const
269
0
{
270
0
    QT_CHECK_BOUND("QUdpSocket::hasPendingDatagrams()", false);
271
0
    return d_func()->socketEngine->hasPendingDatagrams();
272
0
}
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
*/
280
qint64 QUdpSocket::pendingDatagramSize() const
281
0
{
282
0
    QT_CHECK_BOUND("QUdpSocket::pendingDatagramSize()", -1);
283
0
    return d_func()->socketEngine->pendingDatagramSize();
284
0
}
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
*/
307
qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddress &address,
308
                                  quint16 port)
309
0
{
310
0
    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
0
    if (!d->doEnsureInitialized(QHostAddress::Any, 0, address))
316
0
        return -1;
317
0
    if (state() == UnconnectedState)
318
0
        bind();
319
320
0
    qint64 sent = d->socketEngine->writeDatagram(data, size, QIpPacketHeader(address, port));
321
0
    d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
322
323
0
    if (sent >= 0) {
324
0
        emit bytesWritten(sent);
325
0
    } else {
326
0
        if (sent == -2) {
327
            // Socket engine reports EAGAIN. Treat as a temporary error.
328
0
            d->setErrorAndEmit(QAbstractSocket::TemporaryError,
329
0
                               tr("Unable to send a datagram"));
330
0
            return -1;
331
0
        }
332
0
        d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
333
0
    }
334
0
    return sent;
335
0
}
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
*/
372
qint64 QUdpSocket::writeDatagram(const QNetworkDatagram &datagram)
373
0
{
374
0
    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
0
    if (!d->doEnsureInitialized(QHostAddress::Any, 0, datagram.destinationAddress()))
383
0
        return -1;
384
0
    if (state() == UnconnectedState)
385
0
        bind();
386
387
0
    qint64 sent = d->socketEngine->writeDatagram(datagram.d->data.constData(),
388
0
                                                 datagram.d->data.size(),
389
0
                                                 datagram.d->header);
390
0
    d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
391
392
0
    if (sent >= 0) {
393
0
        emit bytesWritten(sent);
394
0
    } else {
395
0
        d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
396
0
    }
397
0
    return sent;
398
0
}
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
*/
417
QNetworkDatagram QUdpSocket::receiveDatagram(qint64 maxSize)
418
0
{
419
0
    Q_D(QUdpSocket);
420
421
#if defined QUDPSOCKET_DEBUG
422
    qDebug("QUdpSocket::receiveDatagram(%lld)", maxSize);
423
#endif
424
0
    QT_CHECK_BOUND("QUdpSocket::receiveDatagram()", QNetworkDatagram());
425
426
0
    if (maxSize < 0)
427
0
        maxSize = d->socketEngine->pendingDatagramSize();
428
0
    if (maxSize < 0)
429
0
        return QNetworkDatagram();
430
431
0
    QNetworkDatagram result(QByteArray(maxSize, Qt::Uninitialized));
432
0
    qint64 readBytes = d->socketEngine->readDatagram(result.d->data.data(), maxSize, &result.d->header,
433
0
                                                     QAbstractSocketEngine::WantAll);
434
0
    d->hasPendingData = false;
435
0
    d->hasPendingDatagram = false;
436
0
    d->socketEngine->setReadNotificationEnabled(true);
437
0
    if (readBytes < 0) {
438
0
        d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
439
0
        readBytes = 0;
440
0
    }
441
442
0
    result.d->data.truncate(readBytes);
443
0
    return result;
444
0
}
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
*/
461
qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *address,
462
                                    quint16 *port)
463
0
{
464
0
    Q_D(QUdpSocket);
465
466
#if defined QUDPSOCKET_DEBUG
467
    qDebug("QUdpSocket::readDatagram(%p, %llu, %p, %p)", data, maxSize, address, port);
468
#endif
469
0
    QT_CHECK_BOUND("QUdpSocket::readDatagram()", -1);
470
471
0
    qint64 readBytes;
472
0
    if (address || port) {
473
0
        QIpPacketHeader header;
474
0
        readBytes = d->socketEngine->readDatagram(data, maxSize, &header,
475
0
                                                  QAbstractSocketEngine::WantDatagramSender);
476
0
        if (address)
477
0
            *address = header.senderAddress;
478
0
        if (port)
479
0
            *port = header.senderPort;
480
0
    } else {
481
0
        readBytes = d->socketEngine->readDatagram(data, maxSize);
482
0
    }
483
484
0
    d->hasPendingData = false;
485
0
    d->hasPendingDatagram = false;
486
0
    d->socketEngine->setReadNotificationEnabled(true);
487
0
    if (readBytes < 0) {
488
0
        if (readBytes == -2) {
489
            // No pending datagram. Treat as a temporary error.
490
0
            d->setErrorAndEmit(QAbstractSocket::TemporaryError,
491
0
                               tr("No datagram available for reading"));
492
0
            return -1;
493
0
        }
494
0
        d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
495
0
    }
496
0
    return readBytes;
497
0
}
498
499
#endif // QT_NO_UDPSOCKET
500
501
QT_END_NAMESPACE
502
503
#include "moc_qudpsocket.cpp"