| 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_ASSERT(d); |
| 485 | delete d; |
| 486 | } |
| 487 | |
| 488 | /*! \fn void QNetworkDatagram::swap(QNetworkDatagram &other) |
| 489 | \memberswap{datagram} |
| 490 | */ |
| 491 | |
| 492 | |
| 493 | QT_END_NAMESPACE |
| 494 | |
| 495 | #endif // QT_NO_UDPSOCKET |
| 496 | |