1// Copyright (C) 2016 Intel Corporation.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qnetworkdatagram.h"
5#include "qnetworkdatagram_p.h"
6
7#ifndef QT_NO_UDPSOCKET
8
9QT_BEGIN_NAMESPACE
10
11QT_IMPL_METATYPE_EXTERN(QNetworkDatagram)
12
13/*!
14 \class QNetworkDatagram
15 \brief The QNetworkDatagram class provides the data and metadata of a UDP datagram.
16 \since 5.8
17 \ingroup network
18 \inmodule QtNetwork
19 \reentrant
20
21 QNetworkDatagram can be used with the \l QUdpSocket class to represent the full
22 information contained in a UDP (User Datagram Protocol) datagram.
23 QNetworkDatagram encapsulates the following information of a datagram:
24 \list
25 \li the payload data;
26 \li the sender address and port number;
27 \li the destination address and port number;
28 \li the remaining hop count limit (on IPv4, this field is usually called "time to live" - TTL);
29 \li the network interface index the datagram was received on or to be sent on.
30 \endlist
31
32 QUdpSocket will try to match a common behavior as much as possible on all
33 operating systems, but not all of the metadata above can be obtained in
34 some operating systems. Metadata that cannot be set on the datagram when
35 sending with QUdpSocket::writeDatagram() will be silently discarded.
36
37 Upon reception, the senderAddress() and senderPort() properties contain the
38 address and port of the peer that sent the datagram, while
39 destinationAddress() and destinationPort() contain the target that was
40 contained in the datagram. That is usually an address local to the current
41 machine, but it can also be an IPv4 broadcast address (such as
42 "255.255.255.255") or an IPv4 or IPv6 multicast address. Applications may
43 find it useful to determine if the datagram was sent specifically to this
44 machine via unicast addressing or whether it was sent to multiple destinations.
45
46 When sending, the senderAddress() and senderPort() should contain the local
47 address to be used when sending. The sender address must be an address that
48 is assigned to this machine, which can be obtained using
49 \l{QNetworkInterface}, and the port number must be the port number that the
50 socket is bound to. Either field can be left unset and will be filled in by
51 the operating system with default values. The destinationAddress() and
52 destinationPort() fields may be set to a target address different from the
53 one the UDP socket is currently associated with.
54
55 Usually, when sending a datagram in reply to a datagram previously
56 received, one will set the destinationAddress() to be the senderAddress()
57 of the incoming datagram and similarly for the port numbers. To facilitate
58 this common process, QNetworkDatagram provides the function makeReply().
59
60 The hopCount() function contains, for a received datagram, the remaining
61 hop count limit for the packet. When sending, it contains the hop count
62 limit to be set. Most protocols will leave this value set to the default
63 and let the operating system decide on the best value to be used.
64 Multicasting over IPv4 often uses this field to indicate the scope of the
65 multicast group (link-local, local to an organization or global).
66
67 The interfaceIndex() function contains the index of the operating system's
68 interface that received the packet. This value is the same one that can be
69 set on a QHostAddress::scopeId() property and matches the
70 QNetworkInterface::index() property. When sending packets to global
71 addresses, it is not necessary to set the interface index as the operating
72 system will choose the correct one using the system routing table. This
73 property is important when sending datagrams to link-local destinations,
74 whether unicast or multicast.
75
76 \section1 Feature support
77
78 Some features of QNetworkDatagram are not supported in all operating systems.
79 Only the address and ports of the remote host (sender in received packets
80 and destination for outgoing packets) are supported in all systems. On most
81 operating systems, the other features are supported only for IPv6. Software
82 should check at runtime whether the rest could be determined for IPv4
83 addresses.
84
85 The current feature support is as follows:
86
87 \table
88 \header \li Operating system \li Local address \li Hop count \li Interface index
89 \row \li FreeBSD \li Supported \li Supported \li Only for IPv6
90 \row \li Linux \li Supported \li Supported \li Supported
91 \row \li OS X \li Supported \li Supported \li Only for IPv6
92 \row \li Other Unix supporting RFC 3542 \li Only for IPv6 \li Only for IPv6 \li Only for IPv6
93 \row \li Windows (desktop) \li Supported \li Supported \li Supported
94 \row \li Windows RT \li Not supported \li Not supported \li Not supported
95 \endtable
96
97 \sa QUdpSocket, QNetworkInterface
98 */
99
100/*!
101 Creates a QNetworkDatagram object with no payload data and undefined destination address.
102
103 The payload can be modified by using setData() and the destination address
104 can be set with setDestination().
105
106 If the destination address is left undefined, QUdpSocket::writeDatagram()
107 will attempt to send the datagram to the address last associated with, by
108 using QUdpSocket::connectToHost().
109 */
110QNetworkDatagram::QNetworkDatagram()
111 : d(new QNetworkDatagramPrivate)
112{
113}
114
115/*!
116 Creates a QNetworkDatagram object and sets \a data as the payload data, along with
117 \a destinationAddress and \a port as the destination address of the datagram.
118 */
119QNetworkDatagram::QNetworkDatagram(const QByteArray &data, const QHostAddress &destinationAddress, quint16 port)
120 : d(new QNetworkDatagramPrivate(data, destinationAddress, port))
121{
122}
123
124/*!
125 Creates a copy of the \a other datagram, including the payload and metadata.
126
127 To create a datagram suitable for sending in a reply, use QNetworkDatagram::makeReply();
128 */
129QNetworkDatagram::QNetworkDatagram(const QNetworkDatagram &other)
130 : d(new QNetworkDatagramPrivate(*other.d))
131{
132}
133
134/*! \internal */
135QNetworkDatagram::QNetworkDatagram(QNetworkDatagramPrivate &dd)
136 : d(&dd)
137{
138}
139
140/*!
141 Copies the \a other datagram, including the payload and metadata.
142
143 To create a datagram suitable for sending in a reply, use QNetworkDatagram::makeReply();
144 */
145QNetworkDatagram &QNetworkDatagram::operator=(const QNetworkDatagram &other)
146{
147 *d = *other.d;
148 return *this;
149}
150
151/*!
152 Clears the payload data and metadata in this QNetworkDatagram object, resetting
153 them to their default values.
154 */
155void QNetworkDatagram::clear()
156{
157 d->data.clear();
158 d->header.senderAddress.clear();
159 d->header.destinationAddress.clear();
160 d->header.hopLimit = -1;
161 d->header.ifindex = 0;
162}
163
164/*!
165 \fn QNetworkDatagram::isNull() const
166 Returns true if this QNetworkDatagram object is null. This function is the
167 opposite of isValid().
168 */
169
170/*!
171 Returns true if this QNetworkDatagram object is valid. A valid QNetworkDatagram
172 object contains at least one sender or receiver address. Valid datagrams
173 can contain empty payloads.
174 */
175bool QNetworkDatagram::isValid() const
176{
177 return d->header.senderAddress.protocol() != QAbstractSocket::UnknownNetworkLayerProtocol ||
178 d->header.destinationAddress.protocol() != QAbstractSocket::UnknownNetworkLayerProtocol;
179}
180
181/*!
182 Returns the sender address associated with this datagram. For a datagram
183 received from the network, it is the address of the peer node that sent the
184 datagram. For an outgoing datagrams, it is the local address to be used
185 when sending.
186
187 If no sender address was set on this datagram, the returned object will
188 report true to QHostAddress::isNull().
189
190 \sa destinationAddress(), senderPort(), setSender()
191*/
192QHostAddress QNetworkDatagram::senderAddress() const
193{
194 return d->header.senderAddress;
195}
196
197/*!
198 Returns the destination address associated with this datagram. For a
199 datagram received from the network, it is the address the peer node sent
200 the datagram to, which can either be a local address of this machine or a
201 multicast or broadcast address. For an outgoing datagrams, it is the
202 address the datagram should be sent to.
203
204 If no destination address was set on this datagram, the returned object
205 will report true to QHostAddress::isNull().
206
207 \sa senderAddress(), destinationPort(), setDestination()
208*/
209QHostAddress QNetworkDatagram::destinationAddress() const
210{
211 return d->header.destinationAddress;
212}
213
214/*!
215 Returns the port number of the sender associated with this datagram. For a
216 datagram received from the network, it is the port number that the peer
217 node sent the datagram from. For an outgoing datagram, it is the local port
218 the datagram should be sent from.
219
220 If no sender address was associated with this datagram, this function
221 returns -1.
222
223 \sa senderAddress(), destinationPort(), setSender()
224*/
225int QNetworkDatagram::senderPort() const
226{
227 return d->header.senderAddress.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol
228 ? -1 : d->header.senderPort;
229}
230
231/*!
232 Returns the port number of the destination associated with this datagram.
233 For a datagram received from the network, it is the local port number that
234 the peer node sent the datagram to. For an outgoing datagram, it is the
235 peer port the datagram should be sent to.
236
237 If no destination address was associated with this datagram, this function
238 returns -1.
239
240 \sa destinationAddress(), senderPort(), setDestination()
241*/
242int QNetworkDatagram::destinationPort() const
243{
244 return d->header.destinationAddress.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol
245 ? -1 : d->header.destinationPort;
246}
247
248/*!
249 Sets the sender address associated with this datagram to be the address \a
250 address and port number \a port. The sender address and port numbers are
251 usually set by \l QUdpSocket upon reception, so there's no need to call
252 this function on a received datagram.
253
254 For outgoing datagrams, this function can be used to set the address the
255 datagram should carry. The address \a address must usually be one of the
256 local addresses assigned to this machine, which can be obtained using \l
257 QNetworkInterface. If left unset, the operating system will choose the most
258 appropriate address to use given the destination in question.
259
260 The port number \a port must be the port number associated with the socket,
261 if there is one. The value of 0 can be used to indicate that the operating
262 system should choose the port number.
263
264 \sa QUdpSocket::writeDatagram(), senderAddress(), senderPort(), setDestination()
265 */
266void QNetworkDatagram::setSender(const QHostAddress &address, quint16 port)
267{
268 d->header.senderAddress = address;
269 d->header.senderPort = port;
270}
271
272/*!
273 Sets the destination address associated with this datagram to be the
274 address \a address and port number \a port. The destination address and
275 port numbers are usually set by \l QUdpSocket upon reception, so there's no
276 need to call this function on a received datagram.
277
278 For outgoing datagrams, this function can be used to set the address the
279 datagram should be sent to. It can be the unicast address used to
280 communicate with the peer or a broadcast or multicast address to send to a
281 group of devices.
282
283 \sa QUdpSocket::writeDatagram(), destinationAddress(), destinationPort(), setSender()
284 */
285void QNetworkDatagram::setDestination(const QHostAddress &address, quint16 port)
286{
287 d->header.destinationAddress = address;
288 d->header.destinationPort = port;
289}
290
291/*!
292 Returns the hop count limit associated with this datagram. The hop count
293 limit is the number of nodes that are allowed to forward the IP packet
294 before it expires and an error is sent back to the sender of the datagram.
295 In IPv4, this value is usually known as "time to live" (TTL).
296
297 If this datagram was received from the network, this is the remaining hop
298 count of the datagram after reception and was decremented by 1 by each node
299 that forwarded the packet. A value of -1 indicates that the hop limit count
300 not be obtained.
301
302 If this is an outgoing datagram, this is the value to be set in the IP header
303 upon sending. A value of -1 indicates the operating system should choose
304 the value.
305
306 \sa setHopLimit()
307 */
308int QNetworkDatagram::hopLimit() const
309{
310 return d->header.hopLimit;
311}
312
313/*!
314 Sets the hop count limit associated with this datagram to \a count. The hop
315 count limit is the number of nodes that are allowed to forward the IP
316 packet before it expires and an error is sent back to the sender of the
317 datagram. In IPv4, this value is usually known as "time to live" (TTL).
318
319 It is usually not necessary to call this function on datagrams received
320 from the network.
321
322 If this is an outgoing packet, this is the value to be set in the IP header
323 upon sending. The valid range for the value is 1 to 255. This function also
324 accepts a value of -1 to indicate that the operating system should choose
325 the value.
326
327 \sa hopLimit()
328 */
329void QNetworkDatagram::setHopLimit(int count)
330{
331 d->header.hopLimit = count;
332}
333
334/*!
335 Returns the interface index this datagram is associated with. The interface
336 index is a positive number that uniquely identifies the network interface
337 in the operating system. This number matches the value returned by
338 QNetworkInterface::index() for the interface.
339
340 If this datagram was received from the network, this is the index of the
341 interface that the packet was received from. If this is an outgoing
342 datagram, this is the index of the interface that the datagram should be
343 sent on.
344
345 A value of 0 indicates that the interface index is unknown.
346
347 \sa setInterfaceIndex()
348 */
349uint QNetworkDatagram::interfaceIndex() const
350{
351 return d->header.ifindex;
352}
353
354/*!
355 Sets the interface index this datagram is associated with to \a index. The
356 interface index is a positive number that uniquely identifies the network
357 interface in the operating system. This number matches the value returned
358 by QNetworkInterface::index() for the interface.
359
360 It is usually not necessary to call this function on datagrams received
361 from the network.
362
363 If this is an outgoing packet, this is the index of the interface the
364 datagram should be sent on. A value of 0 indicates that the operating
365 system should choose the interface based on other factors.
366
367 Note that the interface index can also be set with
368 QHostAddress::setScopeId() for IPv6 destination addresses and then with
369 setDestination(). If the scope ID set in the destination address and \a
370 index are different and neither is zero, it is undefined which interface
371 the operating system will send the datagram on.
372
373 \sa setInterfaceIndex()
374 */
375void QNetworkDatagram::setInterfaceIndex(uint index)
376{
377 d->header.ifindex = index;
378}
379
380/*!
381 Returns the data payload of this datagram. For a datagram received from the
382 network, it contains the payload of the datagram. For an outgoing datagram,
383 it is the datagram to be sent.
384
385 Note that datagrams can be transmitted with no data, so the returned
386 QByteArray may be empty.
387
388 \sa setData()
389 */
390QByteArray QNetworkDatagram::data() const
391{
392 return d->data;
393}
394
395/*!
396 Sets the data payload of this datagram to \a data. It is usually not
397 necessary to call this function on received datagrams. For outgoing
398 datagrams, this function sets the data to be sent on the network.
399
400 Since datagrams can empty, an empty QByteArray is a valid value for \a
401 data.
402
403 \sa data()
404 */
405void QNetworkDatagram::setData(const QByteArray &data)
406{
407 d->data = data;
408}
409
410/*!
411 \fn QNetworkDatagram QNetworkDatagram::makeReply(const QByteArray &payload) const &
412 \fn QNetworkDatagram QNetworkDatagram::makeReply(const QByteArray &payload) &&
413
414 Creates a new QNetworkDatagram representing a reply to this incoming datagram
415 and sets the payload data to \a payload. This function is a very convenient
416 way of responding to a datagram back to the original sender.
417
418 Example:
419 \snippet code/src_network_kernel_qnetworkdatagram.cpp 0
420
421 This function is especially convenient since it will automatically copy
422 parameters from this datagram to the new datagram as appropriate:
423
424 \list
425 \li this datagram's sender address and port are copied to the new
426 datagram's destination address and port;
427 \li this datagram's interface index, if any, is copied to the new
428 datagram's interface index;
429 \li this datagram's destination address and port are copied to the new
430 datagram's sender address and port only if the address is IPv6
431 global (non-multicast) address;
432 \li the hop count limit on the new datagram is reset to the default (-1);
433 \endlist
434
435 If QNetworkDatagram is modified in a future version of Qt to carry further
436 metadata, this function will copy that metadata as appropriate.
437
438 This datagram's destination address is not copied if it is an IPv4 address
439 because it is not possible to tell an IPv4 broadcast address apart from a
440 regular IPv4 address without an exhaustive search of all addresses assigned
441 to this machine. Attempting to send a datagram with the sender address
442 equal to the broadcast address is likely to fail. However, this should not
443 affect the communication as network interfaces with multiple IPv4 addresses
444 are uncommon, so the address the operating system will select will likely
445 be one the peer will understand.
446
447 \note This function comes with both rvalue- and lvalue-reference qualifier
448 overloads, so it is a good idea to make sure this object is rvalue, if
449 possible, before calling makeReply, so as to make better use of move
450 semantics. To achieve that, the example above would use:
451 \snippet code/src_network_kernel_qnetworkdatagram.cpp 1
452 */
453
454
455static bool isNonMulticast(const QHostAddress &addr)
456{
457 // is it a multicast address?
458 return !addr.isMulticast();
459}
460
461QNetworkDatagram QNetworkDatagram::makeReply_helper(const QByteArray &data) const
462{
463 QNetworkDatagramPrivate *x = new QNetworkDatagramPrivate(data, d->header.senderAddress, d->header.senderPort);
464 x->header.ifindex = d->header.ifindex;
465 if (isNonMulticast(addr: d->header.destinationAddress)) {
466 x->header.senderAddress = d->header.destinationAddress;
467 x->header.senderPort = d->header.destinationPort;
468 }
469 return QNetworkDatagram(*x);
470}
471
472void QNetworkDatagram::makeReply_helper_inplace(const QByteArray &data)
473{
474 d->data = data;
475 d->header.hopLimit = -1;
476 qSwap(value1&: d->header.destinationPort, value2&: d->header.senderPort);
477 qSwap(value1&: d->header.destinationAddress, value2&: d->header.senderAddress);
478 if (!isNonMulticast(addr: d->header.senderAddress))
479 d->header.senderAddress.clear();
480}
481
482void QNetworkDatagram::destroy(QNetworkDatagramPrivate *d)
483{
484 Q_ASSUME(d);
485 delete d;
486}
487
488/*! \fn void QNetworkDatagram::swap(QNetworkDatagram &other)
489 Swaps this instance with \a other.
490*/
491
492
493QT_END_NAMESPACE
494
495#endif // QT_NO_UDPSOCKET
496

source code of qtbase/src/network/kernel/qnetworkdatagram.cpp