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 | |
9 | QT_BEGIN_NAMESPACE |
10 | |
11 | QT_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 | */ |
110 | QNetworkDatagram::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 | */ |
119 | QNetworkDatagram::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 | */ |
129 | QNetworkDatagram::QNetworkDatagram(const QNetworkDatagram &other) |
130 | : d(new QNetworkDatagramPrivate(*other.d)) |
131 | { |
132 | } |
133 | |
134 | /*! \internal */ |
135 | QNetworkDatagram::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 | */ |
145 | QNetworkDatagram &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 | */ |
155 | void 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 | */ |
175 | bool 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 | */ |
192 | QHostAddress 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 | */ |
209 | QHostAddress 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 | */ |
225 | int 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 | */ |
242 | int 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 | */ |
266 | void 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 | */ |
285 | void 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 | */ |
308 | int 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 | */ |
329 | void 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 | */ |
349 | uint 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 | */ |
375 | void 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 | */ |
390 | QByteArray 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 | */ |
405 | void 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 | |
455 | static bool isNonMulticast(const QHostAddress &addr) |
456 | { |
457 | // is it a multicast address? |
458 | return !addr.isMulticast(); |
459 | } |
460 | |
461 | QNetworkDatagram 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 | |
472 | void 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 | |
482 | void 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 | |
493 | QT_END_NAMESPACE |
494 | |
495 | #endif // QT_NO_UDPSOCKET |
496 | |