source: trunk/src/network/kernel/qhostaddress.cpp@ 187

Last change on this file since 187 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 31.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtNetwork module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qhostaddress.h"
43#include "qhostaddress_p.h"
44#include "qdebug.h"
45#include "qplatformdefs.h"
46#include "qstringlist.h"
47#include "qendian.h"
48#ifndef QT_NO_DATASTREAM
49#include <qdatastream.h>
50#endif
51#if defined(Q_OS_WINCE)
52#include <winsock.h>
53#endif
54
55#ifdef QT_LINUXBASE
56# include <arpa/inet.h>
57#endif
58
59QT_BEGIN_NAMESPACE
60
61#define QT_ENSURE_PARSED(a) \
62 do { \
63 if (!(a)->d->isParsed) \
64 (a)->d->parse(); \
65 } while (0)
66
67#ifdef Q_OS_WIN
68# if !defined (QT_NO_IPV6)
69// sockaddr_in6 size changed between old and new SDK
70// Only the new version is the correct one, so always
71// use this structure.
72#if defined(Q_OS_WINCE)
73# if !defined(u_char)
74# define u_char unsigned char
75# endif
76# if !defined(u_short)
77# define u_short unsigned short
78# endif
79# if !defined(u_long)
80# define u_long unsigned long
81# endif
82#endif
83struct qt_in6_addr {
84 u_char qt_s6_addr[16];
85};
86typedef struct {
87 short sin6_family; /* AF_INET6 */
88 u_short sin6_port; /* Transport level port number */
89 u_long sin6_flowinfo; /* IPv6 flow information */
90 struct qt_in6_addr sin6_addr; /* IPv6 address */
91 u_long sin6_scope_id; /* set of interfaces for a scope */
92} qt_sockaddr_in6;
93# else
94typedef void * qt_sockaddr_in6 ;
95# endif
96# ifndef AF_INET6
97# define AF_INET6 23 /* Internetwork Version 6 */
98# endif
99#else
100#define qt_sockaddr_in6 sockaddr_in6
101#define qt_s6_addr s6_addr
102#endif
103
104
105class QHostAddressPrivate
106{
107public:
108 QHostAddressPrivate();
109
110 void setAddress(quint32 a_ = 0);
111 void setAddress(const quint8 *a_);
112 void setAddress(const Q_IPV6ADDR &a_);
113
114 bool parse();
115 void clear();
116
117 quint32 a; // IPv4 address
118 Q_IPV6ADDR a6; // IPv6 address
119 QAbstractSocket::NetworkLayerProtocol protocol;
120
121 QString ipString;
122 bool isParsed;
123 QString scopeId;
124
125 friend class QHostAddress;
126};
127
128QHostAddressPrivate::QHostAddressPrivate()
129 : a(0), protocol(QAbstractSocket::UnknownNetworkLayerProtocol), isParsed(true)
130{
131 memset(&a6, 0, sizeof(a6));
132}
133
134void QHostAddressPrivate::setAddress(quint32 a_)
135{
136 a = a_;
137 protocol = QAbstractSocket::IPv4Protocol;
138 isParsed = true;
139}
140
141void QHostAddressPrivate::setAddress(const quint8 *a_)
142{
143 for (int i = 0; i < 16; i++)
144 a6[i] = a_[i];
145 protocol = QAbstractSocket::IPv6Protocol;
146 isParsed = true;
147}
148
149void QHostAddressPrivate::setAddress(const Q_IPV6ADDR &a_)
150{
151 a6 = a_;
152 a = 0;
153 protocol = QAbstractSocket::IPv6Protocol;
154 isParsed = true;
155}
156
157static bool parseIp4(const QString& address, quint32 *addr)
158{
159 QStringList ipv4 = address.split(QLatin1String("."));
160 if (ipv4.count() != 4)
161 return false;
162
163 quint32 ipv4Address = 0;
164 for (int i = 0; i < 4; ++i) {
165 bool ok = false;
166 uint byteValue = ipv4.at(i).toUInt(&ok);
167 if (!ok || byteValue > 255)
168 return false;
169
170 ipv4Address <<= 8;
171 ipv4Address += byteValue;
172 }
173
174 *addr = ipv4Address;
175 return true;
176}
177
178static bool parseIp6(const QString &address, quint8 *addr, QString *scopeId)
179{
180 QString tmp = address;
181 int scopeIdPos = tmp.lastIndexOf(QLatin1Char('%'));
182 if (scopeIdPos != -1) {
183 *scopeId = tmp.mid(scopeIdPos + 1);
184 tmp.chop(tmp.size() - scopeIdPos);
185 } else {
186 scopeId->clear();
187 }
188
189 QStringList ipv6 = tmp.split(QLatin1String(":"));
190 int count = ipv6.count();
191 if (count < 3 || count > 8)
192 return false;
193
194 int colonColon = tmp.count(QLatin1String("::"));
195 if(count == 8 && colonColon > 1)
196 return false;
197
198 // address can be compressed with a "::", but that
199 // may only appear once (see RFC 1884)
200 // the statement below means:
201 // if(shortened notation is not used AND
202 // ((pure IPv6 notation AND less than 8 parts) OR
203 // ((mixed IPv4/6 notation AND less than 7 parts)))
204 if(colonColon != 1 && count < (tmp.contains(QLatin1Char('.')) ? 7 : 8))
205 return false;
206
207 int mc = 16;
208 int fillCount = 9 - count; // number of 0 words to fill in the middle
209 for (int i = count - 1; i >= 0; --i) {
210 if (mc <= 0)
211 return false;
212
213 if (ipv6.at(i).isEmpty()) {
214 if (i == count - 1) {
215 // special case: ":" is last character
216 if (!ipv6.at(i - 1).isEmpty())
217 return false;
218 addr[--mc] = 0;
219 addr[--mc] = 0;
220 } else if (i == 0) {
221 // special case: ":" is first character
222 if (!ipv6.at(i + 1).isEmpty())
223 return false;
224 addr[--mc] = 0;
225 addr[--mc] = 0;
226 } else {
227 for (int j = 0; j < fillCount; ++j) {
228 if (mc <= 0)
229 return false;
230 addr[--mc] = 0;
231 addr[--mc] = 0;
232 }
233 }
234 } else {
235 bool ok = false;
236 uint byteValue = ipv6.at(i).toUInt(&ok, 16);
237 if (ok && byteValue <= 0xffff) {
238 addr[--mc] = byteValue & 0xff;
239 addr[--mc] = (byteValue >> 8) & 0xff;
240 } else {
241 if (i != count - 1)
242 return false;
243
244 // parse the ipv4 part of a mixed type
245 quint32 maybeIp4;
246 if (!parseIp4(ipv6.at(i), &maybeIp4))
247 return false;
248
249 addr[--mc] = maybeIp4 & 0xff;
250 addr[--mc] = (maybeIp4 >> 8) & 0xff;
251 addr[--mc] = (maybeIp4 >> 16) & 0xff;
252 addr[--mc] = (maybeIp4 >> 24) & 0xff;
253 --fillCount;
254 }
255 }
256 }
257
258 return true;
259}
260
261bool QHostAddressPrivate::parse()
262{
263 isParsed = true;
264 protocol = QAbstractSocket::UnknownNetworkLayerProtocol;
265 QString a = ipString.simplified();
266
267 // All IPv6 addresses contain a ':', and may contain a '.'.
268 if (a.contains(QLatin1Char(':'))) {
269 quint8 maybeIp6[16];
270 if (parseIp6(a, maybeIp6, &scopeId)) {
271 setAddress(maybeIp6);
272 protocol = QAbstractSocket::IPv6Protocol;
273 return true;
274 }
275 }
276
277 // All IPv4 addresses contain a '.'.
278 if (a.contains(QLatin1Char('.'))) {
279 quint32 maybeIp4 = 0;
280 if (parseIp4(a, &maybeIp4)) {
281 setAddress(maybeIp4);
282 protocol = QAbstractSocket::IPv4Protocol;
283 return true;
284 }
285 }
286
287 return false;
288}
289
290void QHostAddressPrivate::clear()
291{
292 a = 0;
293 protocol = QAbstractSocket::UnknownNetworkLayerProtocol;
294 isParsed = true;
295 memset(&a6, 0, sizeof(a6));
296}
297
298
299bool QNetmaskAddress::setAddress(const QString &address)
300{
301 length = -1;
302 QHostAddress other;
303 return other.setAddress(address) && setAddress(other);
304}
305
306bool QNetmaskAddress::setAddress(const QHostAddress &address)
307{
308 static const quint8 zeroes[16] = { 0 };
309 union {
310 quint32 v4;
311 quint8 v6[16];
312 } ip;
313
314 int netmask = 0;
315 quint8 *ptr = ip.v6;
316 quint8 *end;
317 length = -1;
318
319 QHostAddress::operator=(address);
320
321 if (d->protocol == QAbstractSocket::IPv4Protocol) {
322 ip.v4 = qToBigEndian(d->a);
323 end = ptr + 4;
324 } else if (d->protocol == QAbstractSocket::IPv6Protocol) {
325 memcpy(ip.v6, d->a6.c, 16);
326 end = ptr + 16;
327 } else {
328 d->clear();
329 return false;
330 }
331
332 while (ptr < end) {
333 switch (*ptr) {
334 case 255:
335 netmask += 8;
336 ++ptr;
337 continue;
338
339 default:
340 d->clear();
341 return false; // invalid IP-style netmask
342
343 // the rest always falls through
344 case 254:
345 ++netmask;
346 case 252:
347 ++netmask;
348 case 248:
349 ++netmask;
350 case 240:
351 ++netmask;
352 case 224:
353 ++netmask;
354 case 192:
355 ++netmask;
356 case 128:
357 ++netmask;
358 case 0:
359 break;
360 }
361 break;
362 }
363
364 // confirm that the rest is only zeroes
365 if (ptr < end && memcmp(ptr + 1, zeroes, end - ptr - 1) != 0) {
366 d->clear();
367 return false;
368 }
369
370 length = netmask;
371 return true;
372}
373
374static void clearBits(quint8 *where, int start, int end)
375{
376 Q_ASSERT(end == 32 || end == 128);
377 if (start == end)
378 return;
379
380 // for the byte where 'start' is, clear the lower bits only
381 quint8 bytemask = 256 - (1 << (8 - (start & 7)));
382 where[start / 8] &= bytemask;
383
384 // for the tail part, clear everything
385 memset(where + (start + 7) / 8, 0, end / 8 - (start + 7) / 8);
386}
387
388int QNetmaskAddress::prefixLength() const
389{
390 return length;
391}
392
393void QNetmaskAddress::setPrefixLength(QAbstractSocket::NetworkLayerProtocol proto, int newLength)
394{
395 length = newLength;
396 if (length < 0 || length > (proto == QAbstractSocket::IPv4Protocol ? 32 :
397 proto == QAbstractSocket::IPv6Protocol ? 128 : -1)) {
398 // invalid information, reject
399 d->protocol = QAbstractSocket::UnknownNetworkLayerProtocol;
400 length = -1;
401 return;
402 }
403
404 d->protocol = proto;
405 if (d->protocol == QAbstractSocket::IPv4Protocol) {
406 if (length == 0) {
407 d->a = 0;
408 } else if (length == 32) {
409 d->a = quint32(0xffffffff);
410 } else {
411 d->a = quint32(0xffffffff) >> (32 - length) << (32 - length);
412 }
413 } else {
414 memset(d->a6.c, 0xFF, sizeof(d->a6));
415 clearBits(d->a6.c, length, 128);
416 }
417}
418
419/*!
420 \class QHostAddress
421 \brief The QHostAddress class provides an IP address.
422 \ingroup io
423 \inmodule QtNetwork
424
425 This class holds an IPv4 or IPv6 address in a platform- and
426 protocol-independent manner.
427
428 QHostAddress is normally used with the QTcpSocket, QTcpServer,
429 and QUdpSocket to connect to a host or to set up a server.
430
431 A host address is set with setAddress(), checked for its type
432 using isIPv4Address() or isIPv6Address(), and retrieved with
433 toIPv4Address(), toIPv6Address(), or toString().
434
435 The class also supports common predefined addresses: \l Null, \l
436 LocalHost, \l LocalHostIPv6, \l Broadcast, and \l Any.
437
438 \sa QHostInfo, QTcpSocket, QTcpServer, QUdpSocket
439*/
440
441/*! \enum QHostAddress::SpecialAddress
442
443 \value Null The null address object. Equivalent to QHostAddress().
444 \value LocalHost The IPv4 localhost address. Equivalent to QHostAddress("127.0.0.1").
445 \value LocalHostIPv6 The IPv6 localhost address. Equivalent to QHostAddress("::1").
446 \value Broadcast The IPv4 broadcast address. Equivalent to QHostAddress("255.255.255.255").
447 \value Any The IPv4 any-address. Equivalent to QHostAddress("0.0.0.0").
448 \value AnyIPv6 The IPv6 any-address. Equivalent to QHostAddress("::").
449*/
450
451/*! Constructs a host address object with the IP address 0.0.0.0.
452
453 \sa clear()
454*/
455QHostAddress::QHostAddress()
456 : d(new QHostAddressPrivate)
457{
458}
459
460/*!
461 Constructs a host address object with the IPv4 address \a ip4Addr.
462*/
463QHostAddress::QHostAddress(quint32 ip4Addr)
464 : d(new QHostAddressPrivate)
465{
466 setAddress(ip4Addr);
467}
468
469/*!
470 Constructs a host address object with the IPv6 address \a ip6Addr.
471
472 \a ip6Addr must be a 16-byte array in network byte order (big
473 endian).
474*/
475QHostAddress::QHostAddress(quint8 *ip6Addr)
476 : d(new QHostAddressPrivate)
477{
478 setAddress(ip6Addr);
479}
480
481/*!
482 Constructs a host address object with the IPv6 address \a ip6Addr.
483*/
484QHostAddress::QHostAddress(const Q_IPV6ADDR &ip6Addr)
485 : d(new QHostAddressPrivate)
486{
487 setAddress(ip6Addr);
488}
489
490/*!
491 Constructs an IPv4 or IPv6 address based on the string \a address
492 (e.g., "127.0.0.1").
493
494 \sa setAddress()
495*/
496QHostAddress::QHostAddress(const QString &address)
497 : d(new QHostAddressPrivate)
498{
499 d->ipString = address;
500 d->isParsed = false;
501}
502
503/*!
504 \fn QHostAddress::QHostAddress(const sockaddr *sockaddr)
505
506 Constructs an IPv4 or IPv6 address using the address specified by
507 the native structure \a sockaddr.
508
509 \sa setAddress()
510*/
511QHostAddress::QHostAddress(const struct sockaddr *sockaddr)
512 : d(new QHostAddressPrivate)
513{
514 if (sockaddr->sa_family == AF_INET)
515 setAddress(htonl(((sockaddr_in *)sockaddr)->sin_addr.s_addr));
516#ifndef QT_NO_IPV6
517 else if (sockaddr->sa_family == AF_INET6)
518 setAddress(((qt_sockaddr_in6 *)sockaddr)->sin6_addr.qt_s6_addr);
519#endif
520}
521
522/*!
523 Constructs a copy of the given \a address.
524*/
525QHostAddress::QHostAddress(const QHostAddress &address)
526 : d(new QHostAddressPrivate(*address.d))
527{
528}
529
530/*!
531 Constructs a QHostAddress object for \a address.
532*/
533QHostAddress::QHostAddress(SpecialAddress address)
534 : d(new QHostAddressPrivate)
535{
536 switch (address) {
537 case Null:
538 break;
539 case Broadcast:
540 setAddress(QLatin1String("255.255.255.255"));
541 break;
542 case LocalHost:
543 setAddress(QLatin1String("127.0.0.1"));
544 break;
545 case LocalHostIPv6:
546 setAddress(QLatin1String("::1"));
547 break;
548 case Any:
549 setAddress(QLatin1String("0.0.0.0"));
550 break;
551 case AnyIPv6:
552 setAddress(QLatin1String("::"));
553 break;
554 }
555}
556
557/*!
558 Destroys the host address object.
559*/
560QHostAddress::~QHostAddress()
561{
562 delete d;
563}
564
565/*!
566 Assigns another host \a address to this object, and returns a reference
567 to this object.
568*/
569QHostAddress &QHostAddress::operator=(const QHostAddress &address)
570{
571 *d = *address.d;
572 return *this;
573}
574
575/*!
576 Assigns the host address \a address to this object, and returns a
577 reference to this object.
578
579 \sa setAddress()
580*/
581QHostAddress &QHostAddress::operator=(const QString &address)
582{
583 setAddress(address);
584 return *this;
585}
586
587/*!
588 \fn bool QHostAddress::operator!=(const QHostAddress &other) const
589 \since 4.2
590
591 Returns true if this host address is not the same as the \a other
592 address given; otherwise returns false.
593*/
594
595/*!
596 \fn bool QHostAddress::operator!=(SpecialAddress other) const
597
598 Returns true if this host address is not the same as the \a other
599 address given; otherwise returns false.
600*/
601
602/*!
603 Sets the host address to 0.0.0.0.
604*/
605void QHostAddress::clear()
606{
607 d->clear();
608}
609
610/*!
611 Set the IPv4 address specified by \a ip4Addr.
612*/
613void QHostAddress::setAddress(quint32 ip4Addr)
614{
615 d->setAddress(ip4Addr);
616}
617
618/*!
619 \overload
620
621 Set the IPv6 address specified by \a ip6Addr.
622
623 \a ip6Addr must be an array of 16 bytes in network byte order
624 (high-order byte first).
625*/
626void QHostAddress::setAddress(quint8 *ip6Addr)
627{
628 d->setAddress(ip6Addr);
629}
630
631/*!
632 \overload
633
634 Set the IPv6 address specified by \a ip6Addr.
635*/
636void QHostAddress::setAddress(const Q_IPV6ADDR &ip6Addr)
637{
638 d->setAddress(ip6Addr);
639}
640
641/*!
642 \overload
643
644 Sets the IPv4 or IPv6 address specified by the string
645 representation specified by \a address (e.g. "127.0.0.1").
646 Returns true and sets the address if the address was successfully
647 parsed; otherwise returns false.
648*/
649bool QHostAddress::setAddress(const QString &address)
650{
651 d->ipString = address;
652 return d->parse();
653}
654
655/*!
656 \fn void QHostAddress::setAddress(const sockaddr *sockaddr)
657 \overload
658
659 Sets the IPv4 or IPv6 address specified by the native structure \a
660 sockaddr. Returns true and sets the address if the address was
661 successfully parsed; otherwise returns false.
662*/
663void QHostAddress::setAddress(const struct sockaddr *sockaddr)
664{
665 clear();
666 if (sockaddr->sa_family == AF_INET)
667 setAddress(htonl(((sockaddr_in *)sockaddr)->sin_addr.s_addr));
668#ifndef QT_NO_IPV6
669 else if (sockaddr->sa_family == AF_INET6)
670 setAddress(((qt_sockaddr_in6 *)sockaddr)->sin6_addr.qt_s6_addr);
671#endif
672}
673
674/*!
675 Returns the IPv4 address as a number.
676
677 For example, if the address is 127.0.0.1, the returned value is
678 2130706433 (i.e. 0x7f000001).
679
680 This value is only valid if isIp4Addr() returns true.
681
682 \sa toString()
683*/
684quint32 QHostAddress::toIPv4Address() const
685{
686 QT_ENSURE_PARSED(this);
687 return d->a;
688}
689
690/*!
691 Returns the network layer protocol of the host address.
692*/
693QAbstractSocket::NetworkLayerProtocol QHostAddress::protocol() const
694{
695 QT_ENSURE_PARSED(this);
696 return d->protocol;
697}
698
699/*!
700 Returns the IPv6 address as a Q_IPV6ADDR structure. The structure
701 consists of 16 unsigned characters.
702
703 \snippet doc/src/snippets/code/src_network_kernel_qhostaddress.cpp 0
704
705 This value is only valid if isIPv6Address() returns true.
706
707 \sa toString()
708*/
709Q_IPV6ADDR QHostAddress::toIPv6Address() const
710{
711 QT_ENSURE_PARSED(this);
712 return d->a6;
713}
714
715/*!
716 Returns the address as a string.
717
718 For example, if the address is the IPv4 address 127.0.0.1, the
719 returned string is "127.0.0.1".
720
721 \sa toIPv4Address()
722*/
723QString QHostAddress::toString() const
724{
725 QT_ENSURE_PARSED(this);
726 if (d->protocol == QAbstractSocket::IPv4Protocol) {
727 quint32 i = toIPv4Address();
728 QString s;
729 s.sprintf("%d.%d.%d.%d", (i>>24) & 0xff, (i>>16) & 0xff,
730 (i >> 8) & 0xff, i & 0xff);
731 return s;
732 }
733
734 if (d->protocol == QAbstractSocket::IPv6Protocol) {
735 quint16 ugle[8];
736 for (int i = 0; i < 8; i++) {
737 ugle[i] = (quint16(d->a6[2*i]) << 8) | quint16(d->a6[2*i+1]);
738 }
739 QString s;
740 s.sprintf("%X:%X:%X:%X:%X:%X:%X:%X",
741 ugle[0], ugle[1], ugle[2], ugle[3], ugle[4], ugle[5], ugle[6], ugle[7]);
742 if (!d->scopeId.isEmpty())
743 s.append(QLatin1Char('%') + d->scopeId);
744 return s;
745 }
746
747 return QString();
748}
749
750/*!
751 \since 4.1
752
753 Returns the scope ID of an IPv6 address. For IPv4 addresses, or if the
754 address does not contain a scope ID, an empty QString is returned.
755
756 The IPv6 scope ID specifies the scope of \e reachability for non-global
757 IPv6 addresses, limiting the area in which the address can be used. All
758 IPv6 addresses are associated with such a reachability scope. The scope ID
759 is used to disambiguate addresses that are not guaranteed to be globally
760 unique.
761
762 IPv6 specifies the following four levels of reachability:
763
764 \list
765
766 \o Node-local: Addresses that are only used for communicating with
767 services on the same interface (e.g., the loopback interface "::1").
768
769 \o Link-local: Addresses that are local to the network interface
770 (\e{link}). There is always one link-local address for each IPv6 interface
771 on your host. Link-local addresses ("fe80...") are generated from the MAC
772 address of the local network adaptor, and are not guaranteed to be unique.
773
774 \o Site-local: Addresses that are local to the site / private network
775 (e.g., the company intranet). Site-local addresses ("fec0...") are
776 usually distributed by the site router, and are not guaranteed to be
777 unique outside of the local site.
778
779 \o Global: For globally routable addresses, such as public servers on the
780 Internet.
781
782 \endlist
783
784 When using a link-local or site-local address for IPv6 connections, you
785 must specify the scope ID. The scope ID for a link-local address is
786 usually the same as the interface name (e.g., "eth0", "en1") or number
787 (e.g., "1", "2").
788
789 \sa setScopeId()
790*/
791QString QHostAddress::scopeId() const
792{
793 QT_ENSURE_PARSED(this);
794 return (d->protocol == QAbstractSocket::IPv6Protocol) ? d->scopeId : QString();
795}
796
797/*!
798 \since 4.1
799
800 Sets the IPv6 scope ID of the address to \a id. If the address
801 protocol is not IPv6, this function does nothing.
802*/
803void QHostAddress::setScopeId(const QString &id)
804{
805 QT_ENSURE_PARSED(this);
806 if (d->protocol == QAbstractSocket::IPv6Protocol)
807 d->scopeId = id;
808}
809
810/*!
811 Returns true if this host address is the same as the \a other address
812 given; otherwise returns false.
813*/
814bool QHostAddress::operator==(const QHostAddress &other) const
815{
816 QT_ENSURE_PARSED(this);
817 QT_ENSURE_PARSED(&other);
818
819 if (d->protocol == QAbstractSocket::IPv4Protocol)
820 return other.d->protocol == QAbstractSocket::IPv4Protocol && d->a == other.d->a;
821 if (d->protocol == QAbstractSocket::IPv6Protocol) {
822 return other.d->protocol == QAbstractSocket::IPv6Protocol
823 && memcmp(&d->a6, &other.d->a6, sizeof(Q_IPV6ADDR)) == 0;
824 }
825 return d->protocol == other.d->protocol;
826}
827
828/*!
829 Returns true if this host address is the same as the \a other
830 address given; otherwise returns false.
831*/
832bool QHostAddress::operator ==(SpecialAddress other) const
833{
834 QT_ENSURE_PARSED(this);
835 QHostAddress otherAddress(other);
836 QT_ENSURE_PARSED(&otherAddress);
837
838 if (d->protocol == QAbstractSocket::IPv4Protocol)
839 return otherAddress.d->protocol == QAbstractSocket::IPv4Protocol && d->a == otherAddress.d->a;
840 if (d->protocol == QAbstractSocket::IPv6Protocol) {
841 return otherAddress.d->protocol == QAbstractSocket::IPv6Protocol
842 && memcmp(&d->a6, &otherAddress.d->a6, sizeof(Q_IPV6ADDR)) == 0;
843 }
844 return int(other) == int(Null);
845}
846
847/*!
848 Returns true if this host address is null (INADDR_ANY or in6addr_any).
849 The default constructor creates a null address, and that address is
850 not valid for any host or interface.
851*/
852bool QHostAddress::isNull() const
853{
854 QT_ENSURE_PARSED(this);
855 return d->protocol == QAbstractSocket::UnknownNetworkLayerProtocol;
856}
857
858/*!
859 \fn quint32 QHostAddress::ip4Addr() const
860
861 Use toIPv4Address() instead.
862*/
863
864/*!
865 \fn bool QHostAddress::isIp4Addr() const
866
867 Use protocol() instead.
868*/
869
870/*!
871 \fn bool QHostAddress::isIPv4Address() const
872
873 Use protocol() instead.
874*/
875
876/*!
877 \fn bool QHostAddress::isIPv6Address() const
878
879 Use protocol() instead.
880*/
881
882/*!
883 \since 4.5
884
885 Returns true if this IP is in the subnet described by the network
886 prefix \a subnet and netmask \a netmask.
887
888 An IP is considered to belong to a subnet if it is contained
889 between the lowest and the highest address in that subnet. In the
890 case of IP version 4, the lowest address is the network address,
891 while the highest address is the broadcast address.
892
893 The \a subnet argument does not have to be the actual network
894 address (the lowest address in the subnet). It can be any valid IP
895 belonging to that subnet. In particular, if it is equal to the IP
896 address held by this object, this function will always return true
897 (provided the netmask is a valid value).
898
899 \sa parseSubnet()
900*/
901bool QHostAddress::isInSubnet(const QHostAddress &subnet, int netmask) const
902{
903 QT_ENSURE_PARSED(this);
904 if (subnet.protocol() != d->protocol || netmask < 0)
905 return false;
906
907 union {
908 quint32 ip;
909 quint8 data[4];
910 } ip4, net4;
911 const quint8 *ip;
912 const quint8 *net;
913 if (d->protocol == QAbstractSocket::IPv4Protocol) {
914 if (netmask > 32)
915 netmask = 32;
916 ip4.ip = qToBigEndian(d->a);
917 net4.ip = qToBigEndian(subnet.d->a);
918 ip = ip4.data;
919 net = net4.data;
920 } else if (d->protocol == QAbstractSocket::IPv6Protocol) {
921 if (netmask > 128)
922 netmask = 128;
923 ip = d->a6.c;
924 net = subnet.d->a6.c;
925 } else {
926 return false;
927 }
928
929 if (netmask >= 8 && memcmp(ip, net, netmask / 8) != 0)
930 return false;
931 if ((netmask & 7) == 0)
932 return true;
933
934 // compare the last octet now
935 quint8 bytemask = 256 - (1 << (8 - (netmask & 7)));
936 quint8 ipbyte = ip[netmask / 8];
937 quint8 netbyte = net[netmask / 8];
938 return (ipbyte & bytemask) == (netbyte & bytemask);
939}
940
941/*!
942 \since 4.5
943 \overload
944
945 Returns true if this IP is in the subnet described by \a
946 subnet. The QHostAddress member of \a subnet contains the network
947 prefix and the int (second) member contains the netmask (prefix
948 length).
949*/
950bool QHostAddress::isInSubnet(const QPair<QHostAddress, int> &subnet) const
951{
952 return isInSubnet(subnet.first, subnet.second);
953}
954
955
956/*!
957 \since 4.5
958
959 Parses the IP and subnet information contained in \a subnet and
960 returns the network prefix for that network and its prefix length.
961
962 The IP address and the netmask must be separated by a slash
963 (/).
964
965 This function supports arguments in the form:
966 \list
967 \o 123.123.123.123/n where n is any value between 0 and 32
968 \o 123.123.123.123/255.255.255.255
969 \o <ipv6-address>/n where n is any value between 0 and 128
970 \endlist
971
972 For IP version 4, this function accepts as well missing trailing
973 components (i.e., less than 4 octets, like "192.168.1"), followed
974 or not by a dot. If the netmask is also missing in that case, it
975 is set to the number of octets actually passed (in the example
976 above, it would be 24, for 3 octets).
977
978 \sa isInSubnet()
979*/
980QPair<QHostAddress, int> QHostAddress::parseSubnet(const QString &subnet)
981{
982 // We support subnets in the form:
983 // ddd.ddd.ddd.ddd/nn
984 // ddd.ddd.ddd/nn
985 // ddd.ddd/nn
986 // ddd/nn
987 // ddd.ddd.ddd.
988 // ddd.ddd.ddd
989 // ddd.ddd.
990 // ddd.ddd
991 // ddd.
992 // ddd
993 // <ipv6-address>/nn
994 //
995 // where nn can be an IPv4-style netmask for the IPv4 forms
996
997 const QPair<QHostAddress, int> invalid = qMakePair(QHostAddress(), -1);
998 if (subnet.isEmpty())
999 return invalid;
1000
1001 int slash = subnet.indexOf(QLatin1Char('/'));
1002 QString netStr = subnet;
1003 if (slash != -1)
1004 netStr.truncate(slash);
1005
1006 int netmask = -1;
1007 bool isIpv6 = netStr.contains(QLatin1Char(':'));
1008
1009 if (slash != -1) {
1010 // is the netmask given in IP-form or in bit-count form?
1011 if (!isIpv6 && subnet.indexOf(QLatin1Char('.'), slash + 1) != -1) {
1012 // IP-style, convert it to bit-count form
1013 QNetmaskAddress parser;
1014 if (!parser.setAddress(subnet.mid(slash + 1)))
1015 return invalid;
1016 netmask = parser.prefixLength();
1017 } else {
1018 bool ok;
1019 netmask = subnet.mid(slash + 1).toUInt(&ok);
1020 if (!ok)
1021 return invalid; // failed to parse the subnet
1022 }
1023 }
1024
1025 if (isIpv6) {
1026 // looks like it's an IPv6 address
1027 if (netmask > 128)
1028 return invalid; // invalid netmask
1029 if (netmask < 0)
1030 netmask = 128;
1031
1032 QHostAddress net;
1033 if (!net.setAddress(netStr))
1034 return invalid; // failed to parse the IP
1035
1036 clearBits(net.d->a6.c, netmask, 128);
1037 return qMakePair(net, netmask);
1038 }
1039
1040 if (netmask > 32)
1041 return invalid; // invalid netmask
1042
1043 // parse the address manually
1044 QStringList parts = netStr.split(QLatin1Char('.'));
1045 if (parts.isEmpty() || parts.count() > 4)
1046 return invalid; // invalid IPv4 address
1047
1048 if (parts.last().isEmpty())
1049 parts.removeLast();
1050
1051 quint32 addr = 0;
1052 for (int i = 0; i < parts.count(); ++i) {
1053 bool ok;
1054 uint byteValue = parts.at(i).toUInt(&ok);
1055 if (!ok || byteValue > 255)
1056 return invalid; // invalid IPv4 address
1057
1058 addr <<= 8;
1059 addr += byteValue;
1060 }
1061 addr <<= 8 * (4 - parts.count());
1062 if (netmask == -1) {
1063 netmask = 8 * parts.count();
1064 } else if (netmask == 0) {
1065 // special case here
1066 // x86's instructions "shr" and "shl" do not operate when
1067 // their argument is 32, so the code below doesn't work as expected
1068 addr = 0;
1069 } else if (netmask != 32) {
1070 // clear remaining bits
1071 quint32 mask = quint32(0xffffffff) >> (32 - netmask) << (32 - netmask);
1072 addr &= mask;
1073 }
1074
1075 return qMakePair(QHostAddress(addr), netmask);
1076}
1077
1078#ifndef QT_NO_DEBUG_STREAM
1079QDebug operator<<(QDebug d, const QHostAddress &address)
1080{
1081 d.maybeSpace() << "QHostAddress(" << address.toString() << ")";
1082 return d.space();
1083}
1084#endif
1085
1086uint qHash(const QHostAddress &key)
1087{
1088 return qHash(key.toString());
1089}
1090
1091#ifndef QT_NO_DATASTREAM
1092
1093/*! \relates QHostAddress
1094
1095 Writes host address \a address to the stream \a out and returns a reference
1096 to the stream.
1097
1098 \sa {Format of the QDataStream operators}
1099*/
1100QDataStream &operator<<(QDataStream &out, const QHostAddress &address)
1101{
1102 qint8 prot;
1103 prot = qint8(address.protocol());
1104 out << prot;
1105 switch (address.protocol()) {
1106 case QAbstractSocket::UnknownNetworkLayerProtocol:
1107 break;
1108 case QAbstractSocket::IPv4Protocol:
1109 out << address.toIPv4Address();
1110 break;
1111 case QAbstractSocket::IPv6Protocol:
1112 {
1113 Q_IPV6ADDR ipv6 = address.toIPv6Address();
1114 for (int i = 0; i < 16; ++i)
1115 out << ipv6[i];
1116 out << address.scopeId();
1117 }
1118 break;
1119 }
1120 return out;
1121}
1122
1123/*! \relates QHostAddress
1124
1125 Reads a host address into \a address from the stream \a in and returns a
1126 reference to the stream.
1127
1128 \sa {Format of the QDataStream operators}
1129*/
1130QDataStream &operator>>(QDataStream &in, QHostAddress &address)
1131{
1132 qint8 prot;
1133 in >> prot;
1134 switch (QAbstractSocket::NetworkLayerProtocol(prot)) {
1135 case QAbstractSocket::UnknownNetworkLayerProtocol:
1136 address.clear();
1137 break;
1138 case QAbstractSocket::IPv4Protocol:
1139 {
1140 quint32 ipv4;
1141 in >> ipv4;
1142 address.setAddress(ipv4);
1143 }
1144 break;
1145 case QAbstractSocket::IPv6Protocol:
1146 {
1147 Q_IPV6ADDR ipv6;
1148 for (int i = 0; i < 16; ++i)
1149 in >> ipv6[i];
1150 address.setAddress(ipv6);
1151
1152 QString scope;
1153 in >> scope;
1154 address.setScopeId(scope);
1155 }
1156 break;
1157 default:
1158 address.clear();
1159 in.setStatus(QDataStream::ReadCorruptData);
1160 }
1161 return in;
1162}
1163
1164#endif //QT_NO_DATASTREAM
1165
1166QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.