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