From 05012f4285ac38c7975138b7f839e158a6f961a3 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 10 Aug 2017 00:22:56 -0700 Subject: [PATCH] QNetworkInterface: add MTU [ChangeLog][QtNetwork][QNetworkInterface] Added maxTransmissionUnit(). Change-Id: Iaf4157b7efa2416d898cfffd14d96b2970d6af87 Reviewed-by: Edward Welbourne Reviewed-by: Timur Pocheptsov --- src/network/kernel/qnetworkinterface.cpp | 23 +++++++++++++++++++ src/network/kernel/qnetworkinterface.h | 1 + .../kernel/qnetworkinterface_linux.cpp | 5 ++++ src/network/kernel/qnetworkinterface_p.h | 1 + src/network/kernel/qnetworkinterface_unix.cpp | 20 +++++++++++++++- src/network/kernel/qnetworkinterface_win.cpp | 1 + .../tst_qnetworkinterface.cpp | 1 + 7 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/network/kernel/qnetworkinterface.cpp b/src/network/kernel/qnetworkinterface.cpp index ec58fa65c02..3fb0dc80eed 100644 --- a/src/network/kernel/qnetworkinterface.cpp +++ b/src/network/kernel/qnetworkinterface.cpp @@ -688,6 +688,29 @@ int QNetworkInterface::index() const return d ? d->index : 0; } +/*! + \since 5.11 + + Returns the maximum transmission unit on this interface, if known, or 0 + otherwise. + + The maximum transmission unit is the largest packet that may be sent on + this interface without incurring link-level fragmentation. Applications may + use this value to calculate the size of the payload that will fit an + unfragmented UDP datagram. Remember to subtract the sizes of headers used + in your communication over the interface, e.g. TCP (20 bytes) or UDP (12), + IPv4 (20) or IPv6 (40, absent some form of header compression), when + computing how big a payload you can transmit. Also note that the MTU along + the full path (the Path MTU) to the destination may be smaller than the + interface's MTU. + + \sa QUdpSocket +*/ +int QNetworkInterface::maxTransmissionUnit() const +{ + return d ? d->mtu : 0; +} + /*! Returns the name of this network interface. On Unix systems, this is a string containing the type of the interface and optionally a diff --git a/src/network/kernel/qnetworkinterface.h b/src/network/kernel/qnetworkinterface.h index 32b358eb8f8..f7ef192dc04 100644 --- a/src/network/kernel/qnetworkinterface.h +++ b/src/network/kernel/qnetworkinterface.h @@ -153,6 +153,7 @@ public: bool isValid() const; int index() const; + int maxTransmissionUnit() const; QString name() const; QString humanReadableName() const; InterfaceFlags flags() const; diff --git a/src/network/kernel/qnetworkinterface_linux.cpp b/src/network/kernel/qnetworkinterface_linux.cpp index 5940f80dfa6..620ee7202be 100644 --- a/src/network/kernel/qnetworkinterface_linux.cpp +++ b/src/network/kernel/qnetworkinterface_linux.cpp @@ -293,6 +293,11 @@ static QList getInterfaces(int sock, char *buf) iface->name = QString::fromLatin1(payloadPtr, payloadLen - 1); break; + case IFLA_MTU: + Q_ASSERT(payloadLen == sizeof(int)); + iface->mtu = *reinterpret_cast(payloadPtr); + break; + case IFLA_OPERSTATE: // operational state if (*payloadPtr != IF_OPER_UNKNOWN) { // override the flag diff --git a/src/network/kernel/qnetworkinterface_p.h b/src/network/kernel/qnetworkinterface_p.h index b16149e12f8..87a46b75fac 100644 --- a/src/network/kernel/qnetworkinterface_p.h +++ b/src/network/kernel/qnetworkinterface_p.h @@ -88,6 +88,7 @@ public: { } int index; // interface index, if know + int mtu = 0; QNetworkInterface::InterfaceFlags flags; QNetworkInterface::InterfaceType type = QNetworkInterface::Unknown; diff --git a/src/network/kernel/qnetworkinterface_unix.cpp b/src/network/kernel/qnetworkinterface_unix.cpp index 1c2f5d335a5..2f3c940d252 100644 --- a/src/network/kernel/qnetworkinterface_unix.cpp +++ b/src/network/kernel/qnetworkinterface_unix.cpp @@ -139,6 +139,15 @@ QString QNetworkInterfaceManager::interfaceNameFromIndex(uint index) return QString::number(uint(index)); } +static int getMtu(int socket, struct ifreq *req) +{ +#ifdef SIOCGIFMTU + if (qt_safe_ioctl(socket, SIOCGIFMTU, req) == 0) + return req->ifr_mtu; +#endif + return 0; +} + #ifdef QT_NO_GETIFADDRS // getifaddrs not available @@ -278,6 +287,7 @@ static QList interfaceListing() if (qt_safe_ioctl(socket, SIOCGIFFLAGS, &req) >= 0) { iface->flags = convertFlags(req.ifr_flags); } + iface->mtu = getMtu(socket, &req); #ifdef SIOCGIFHWADDR // Get the HW address @@ -458,9 +468,16 @@ static QNetworkInterface::InterfaceType probeIfType(int socket, int iftype, stru static QList createInterfaces(ifaddrs *rawList) { QList interfaces; - struct ifmediareq mediareq; + union { + struct ifmediareq mediareq; + struct ifreq req; + }; int socket = -1; + // ensure both structs start with the name field, of size IFNAMESIZ + Q_STATIC_ASSERT(sizeof(mediareq.ifm_name) == sizeof(req.ifr_name)); + Q_ASSERT(&mediareq.ifm_name == &req.ifr_name); + // on NetBSD we use AF_LINK and sockaddr_dl // scan the list for that family for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) @@ -476,6 +493,7 @@ static QList createInterfaces(ifaddrs *rawList) strlcpy(mediareq.ifm_name, ptr->ifa_name, sizeof(mediareq.ifm_name)); iface->type = probeIfType(openSocket(socket), sdl->sdl_type, &mediareq); + iface->mtu = getMtu(socket, &req); } if (socket != -1) diff --git a/src/network/kernel/qnetworkinterface_win.cpp b/src/network/kernel/qnetworkinterface_win.cpp index 705bc24c321..857e40215c6 100644 --- a/src/network/kernel/qnetworkinterface_win.cpp +++ b/src/network/kernel/qnetworkinterface_win.cpp @@ -151,6 +151,7 @@ static QList interfaceListing() else if (ptr->IfIndex != 0) iface->index = ptr->IfIndex; + iface->mtu = ptr->Mtu; iface->flags = QNetworkInterface::CanBroadcast; if (ptr->OperStatus == IfOperStatusUp) iface->flags |= QNetworkInterface::IsUp | QNetworkInterface::IsRunning; diff --git a/tests/auto/network/kernel/qnetworkinterface/tst_qnetworkinterface.cpp b/tests/auto/network/kernel/qnetworkinterface/tst_qnetworkinterface.cpp index 2f2937fcdb5..ae5082fecb3 100644 --- a/tests/auto/network/kernel/qnetworkinterface/tst_qnetworkinterface.cpp +++ b/tests/auto/network/kernel/qnetworkinterface/tst_qnetworkinterface.cpp @@ -140,6 +140,7 @@ void tst_QNetworkInterface::dump() qDebug() << " flags: " << qPrintable(flags); qDebug() << " type: " << i.type(); qDebug() << " hw address:" << qPrintable(i.hardwareAddress()); + qDebug() << " MTU: " << i.maxTransmissionUnit(); int count = 0; foreach (const QNetworkAddressEntry &e, i.addressEntries()) {