Refactor QNetworkAddress not to keep a full QHostAddress
QHostAddressPrivate is one QString and 24 bytes, allocated on the heap, which is WAY too heavy for something that fits into 8 bits. So instead of storing the expanded netmask inside QNetworkAddressEntryPrivate, we store the simple prefix length and calculate the mask only if asked. Change-Id: Ie05c6480d8a44fda817ffffd14d9ad4707aa8a92 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
parent
758982bd74
commit
8656ee950b
@ -206,18 +206,8 @@ void QHostAddressPrivate::clear()
|
||||
}
|
||||
|
||||
|
||||
bool QNetmaskAddress::setAddress(const QString &address)
|
||||
bool QNetmask::setAddress(const QHostAddress &address)
|
||||
{
|
||||
d.detach();
|
||||
length = -1;
|
||||
QHostAddress other;
|
||||
return other.setAddress(address) && setAddress(other);
|
||||
}
|
||||
|
||||
bool QNetmaskAddress::setAddress(const QHostAddress &address)
|
||||
{
|
||||
d.detach();
|
||||
|
||||
static const quint8 zeroes[16] = { 0 };
|
||||
union {
|
||||
quint32 v4;
|
||||
@ -229,16 +219,13 @@ bool QNetmaskAddress::setAddress(const QHostAddress &address)
|
||||
quint8 *end;
|
||||
length = -1;
|
||||
|
||||
QHostAddress::operator=(address);
|
||||
|
||||
if (d->protocol == QAbstractSocket::IPv4Protocol) {
|
||||
ip.v4 = qToBigEndian(d->a);
|
||||
if (address.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||
ip.v4 = qToBigEndian(address.toIPv4Address());
|
||||
end = ptr + 4;
|
||||
} else if (d->protocol == QAbstractSocket::IPv6Protocol) {
|
||||
memcpy(ip.v6, d->a6.c, 16);
|
||||
} else if (address.protocol() == QAbstractSocket::IPv6Protocol) {
|
||||
memcpy(ip.v6, address.toIPv6Address().c, 16);
|
||||
end = ptr + 16;
|
||||
} else {
|
||||
d->clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -250,7 +237,6 @@ bool QNetmaskAddress::setAddress(const QHostAddress &address)
|
||||
continue;
|
||||
|
||||
default:
|
||||
d->clear();
|
||||
return false; // invalid IP-style netmask
|
||||
|
||||
case 254:
|
||||
@ -281,10 +267,8 @@ bool QNetmaskAddress::setAddress(const QHostAddress &address)
|
||||
}
|
||||
|
||||
// confirm that the rest is only zeroes
|
||||
if (ptr < end && memcmp(ptr + 1, zeroes, end - ptr - 1) != 0) {
|
||||
d->clear();
|
||||
if (ptr < end && memcmp(ptr + 1, zeroes, end - ptr - 1) != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
length = netmask;
|
||||
return true;
|
||||
@ -304,35 +288,25 @@ static void clearBits(quint8 *where, int start, int end)
|
||||
memset(where + (start + 7) / 8, 0, end / 8 - (start + 7) / 8);
|
||||
}
|
||||
|
||||
int QNetmaskAddress::prefixLength() const
|
||||
QHostAddress QNetmask::address(QAbstractSocket::NetworkLayerProtocol protocol) const
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
void QNetmaskAddress::setPrefixLength(QAbstractSocket::NetworkLayerProtocol proto, int newLength)
|
||||
{
|
||||
d.detach();
|
||||
length = newLength;
|
||||
if (length < 0 || length > (proto == QAbstractSocket::IPv4Protocol ? 32 :
|
||||
proto == QAbstractSocket::IPv6Protocol ? 128 : -1)) {
|
||||
// invalid information, reject
|
||||
d->protocol = QAbstractSocket::UnknownNetworkLayerProtocol;
|
||||
length = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
d->protocol = proto;
|
||||
if (d->protocol == QAbstractSocket::IPv4Protocol) {
|
||||
if (length == 0) {
|
||||
d->a = 0;
|
||||
} else if (length == 32) {
|
||||
d->a = quint32(0xffffffff);
|
||||
} else {
|
||||
d->a = quint32(0xffffffff) >> (32 - length) << (32 - length);
|
||||
}
|
||||
if (length == 255 || protocol == QAbstractSocket::AnyIPProtocol ||
|
||||
protocol == QAbstractSocket::UnknownNetworkLayerProtocol) {
|
||||
return QHostAddress();
|
||||
} else if (protocol == QAbstractSocket::IPv4Protocol) {
|
||||
quint32 a;
|
||||
if (length == 0)
|
||||
a = 0;
|
||||
else if (length == 32)
|
||||
a = quint32(0xffffffff);
|
||||
else
|
||||
a = quint32(0xffffffff) >> (32 - length) << (32 - length);
|
||||
return QHostAddress(a);
|
||||
} else {
|
||||
memset(d->a6.c, 0xFF, sizeof(d->a6));
|
||||
clearBits(d->a6.c, length, 128);
|
||||
Q_IPV6ADDR a6;
|
||||
memset(a6.c, 0xFF, sizeof(a6));
|
||||
clearBits(a6.c, length, 128);
|
||||
return QHostAddress(a6);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1104,8 +1078,11 @@ QPair<QHostAddress, int> QHostAddress::parseSubnet(const QString &subnet)
|
||||
// is the netmask given in IP-form or in bit-count form?
|
||||
if (!isIpv6 && subnet.indexOf(QLatin1Char('.'), slash + 1) != -1) {
|
||||
// IP-style, convert it to bit-count form
|
||||
QNetmaskAddress parser;
|
||||
if (!parser.setAddress(subnet.mid(slash + 1)))
|
||||
QHostAddress mask;
|
||||
QNetmask parser;
|
||||
if (!mask.setAddress(subnet.mid(slash + 1)))
|
||||
return invalid;
|
||||
if (!parser.setAddress(mask))
|
||||
return invalid;
|
||||
netmask = parser.prefixLength();
|
||||
} else {
|
||||
|
@ -57,17 +57,32 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QNetmaskAddress: public QHostAddress
|
||||
class QNetmask
|
||||
{
|
||||
int length;
|
||||
// stores 0-32 for IPv4, 0-128 for IPv6, or 255 for invalid
|
||||
quint8 length;
|
||||
public:
|
||||
QNetmaskAddress() : QHostAddress(), length(-1) { }
|
||||
Q_DECL_CONSTEXPR QNetmask() : length(255) {}
|
||||
|
||||
bool setAddress(const QString &address);
|
||||
bool setAddress(const QHostAddress &address);
|
||||
QHostAddress address(QAbstractSocket::NetworkLayerProtocol protocol) const;
|
||||
|
||||
int prefixLength() const;
|
||||
void setPrefixLength(QAbstractSocket::NetworkLayerProtocol proto, int len);
|
||||
int prefixLength() const { return length == 255 ? -1 : length; }
|
||||
void setPrefixLength(QAbstractSocket::NetworkLayerProtocol proto, int len)
|
||||
{
|
||||
int maxlen = -1;
|
||||
if (proto == QAbstractSocket::IPv4Protocol)
|
||||
maxlen = 32;
|
||||
else if (proto == QAbstractSocket::IPv6Protocol)
|
||||
maxlen = 128;
|
||||
if (len > maxlen || len < 0)
|
||||
length = 255U;
|
||||
else
|
||||
length = unsigned(len);
|
||||
}
|
||||
|
||||
friend bool operator==(QNetmask n1, QNetmask n2)
|
||||
{ return n1.length == n2.length; }
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -257,7 +257,7 @@ void QNetworkAddressEntry::setIp(const QHostAddress &newIp)
|
||||
*/
|
||||
QHostAddress QNetworkAddressEntry::netmask() const
|
||||
{
|
||||
return d->netmask;
|
||||
return d->netmask.address(d->address.protocol());
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -270,7 +270,7 @@ QHostAddress QNetworkAddressEntry::netmask() const
|
||||
void QNetworkAddressEntry::setNetmask(const QHostAddress &newNetmask)
|
||||
{
|
||||
if (newNetmask.protocol() != ip().protocol()) {
|
||||
d->netmask = QNetmaskAddress();
|
||||
d->netmask = QNetmask();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -68,8 +68,8 @@ class QNetworkAddressEntryPrivate
|
||||
{
|
||||
public:
|
||||
QHostAddress address;
|
||||
QNetmaskAddress netmask;
|
||||
QHostAddress broadcast;
|
||||
QNetmask netmask;
|
||||
};
|
||||
|
||||
class QNetworkInterfacePrivate: public QSharedData
|
||||
|
Loading…
Reference in New Issue
Block a user