* Added MYBonjourBrowser and MYBonjourService.
* Added MYPortMapper.
* Added -[TCPEndpoint setPeerToPeerIdentity:].
* Created a static-library target.
5 // Created by Jens Alfke on 1/4/08.
6 // Copyright 2008 Jens Alfke. All rights reserved.
15 #import <sys/socket.h>
17 #import <netinet/in.h>
22 @implementation IPAddress
25 + (UInt32) IPv4FromDottedQuadString: (NSString*)str
29 NSScanner *scanner = [NSScanner scannerWithString: str];
30 for( int i=0; i<4; i++ ) {
31 if( i>0 && ! [scanner scanString: @"." intoString: nil] )
34 if( ! [scanner scanInteger: &octet] || octet<0 || octet>255 )
36 ipv4 = (ipv4<<8) | octet;
38 if( ! [scanner isAtEnd] )
44 - (id) initWithHostname: (NSString*)hostname port: (UInt16)port
49 _ipv4 = [[self class] IPv4FromDottedQuadString: hostname];
52 return [[HostAddress alloc] initWithHostname: hostname port: port];
60 - (id) initWithIPv4: (UInt32)ipv4 port: (UInt16)port
70 - (id) initWithIPv4: (UInt32)ipv4
72 return [self initWithIPv4: ipv4 port: 0];
75 - (id) initWithSockAddr: (const struct sockaddr*)sockaddr
77 if( sockaddr->sa_family == AF_INET ) {
78 const struct sockaddr_in *addr_in = (const struct sockaddr_in*)sockaddr;
79 return [self initWithIPv4: addr_in->sin_addr.s_addr port: ntohs(addr_in->sin_port)];
86 + (IPAddress*) addressOfSocket: (CFSocketNativeHandle)socket
88 uint8_t name[SOCK_MAXADDRLEN];
89 socklen_t namelen = sizeof(name);
90 struct sockaddr *addr = (struct sockaddr*)name;
91 if (0 == getpeername(socket, addr, &namelen))
92 return [[[self alloc] initWithSockAddr: addr] autorelease];
97 - (id) copyWithZone: (NSZone*)zone
102 - (void)encodeWithCoder:(NSCoder *)coder
105 [coder encodeInt32: _ipv4 forKey: @"ipv4"];
107 [coder encodeInt: _port forKey: @"port"];
110 - (id)initWithCoder:(NSCoder *)decoder
114 _ipv4 = [decoder decodeInt32ForKey: @"ipv4"];
115 _port = [decoder decodeIntForKey: @"port"];
121 @synthesize ipv4=_ipv4, port=_port;
123 - (BOOL) isEqual: (IPAddress*)addr
125 return [addr isKindOfClass: [IPAddress class]] && [self isSameHost: addr] && addr->_port==_port;
128 - (BOOL) isSameHost: (IPAddress*)addr
130 return addr && _ipv4==addr->_ipv4;
135 return _ipv4 ^ _port;
138 - (NSString*) ipv4name
140 UInt32 ipv4 = self.ipv4;
142 const UInt8* b = (const UInt8*)&ipv4;
143 return [NSString stringWithFormat: @"%u.%u.%u.%u",
144 (unsigned)b[0],(unsigned)b[1],(unsigned)b[2],(unsigned)b[3]];
149 - (NSString*) hostname
151 return [self ipv4name];
154 - (NSString*) description
156 NSString *name = self.hostname ?: @"0.0.0.0";
158 name = [name stringByAppendingFormat: @":%hu",_port];
163 + (IPAddress*) localAddressWithPort: (UInt16)port
165 // getifaddrs returns a linked list of interface entries;
166 // find the first active non-loopback interface with IPv4:
168 struct ifaddrs *interfaces;
169 if( getifaddrs(&interfaces) == 0 ) {
170 struct ifaddrs *interface;
171 for( interface=interfaces; interface; interface=interface->ifa_next ) {
172 if( (interface->ifa_flags & IFF_UP) && ! (interface->ifa_flags & IFF_LOOPBACK) ) {
173 const struct sockaddr_in *addr = (const struct sockaddr_in*) interface->ifa_addr;
174 if( addr && addr->sin_family==AF_INET ) {
175 address = addr->sin_addr.s_addr;
180 freeifaddrs(interfaces);
182 return [[[self alloc] initWithIPv4: address port: port] autorelease];
185 + (IPAddress*) localAddress
187 return [self localAddressWithPort: 0];
191 // Private IP address ranges. See RFC 3330.
192 static const struct {UInt32 mask, value;} const kPrivateRanges[] = {
193 {0xFF000000, 0x00000000}, // 0.x.x.x (hosts on "this" network)
194 {0xFF000000, 0x0A000000}, // 10.x.x.x (private address range)
195 {0xFF000000, 0x7F000000}, // 127.x.x.x (loopback)
196 {0xFFFF0000, 0xA9FE0000}, // 169.254.x.x (link-local self-configured addresses)
197 {0xFFF00000, 0xAC100000}, // 172.(16-31).x.x (private address range)
198 {0xFFFF0000, 0xC0A80000}, // 192.168.x.x (private address range)
205 UInt32 address = ntohl(self.ipv4);
207 for( i=0; kPrivateRanges[i].mask; i++ )
208 if( (address & kPrivateRanges[i].mask) == kPrivateRanges[i].value )
220 @implementation HostAddress
223 - (id) initWithHostname: (NSString*)hostname port: (UInt16)port
225 self = [super initWithIPv4: 0 port: port];
227 if( [hostname length]==0 ) {
231 _hostname = [hostname copy];
237 - (void)encodeWithCoder:(NSCoder *)coder
239 [super encodeWithCoder: coder];
240 [coder encodeObject: _hostname forKey: @"host"];
243 - (id)initWithCoder:(NSCoder *)decoder
245 self = [super initWithCoder: decoder];
247 _hostname = [[decoder decodeObjectForKey: @"host"] copy];
261 return [_hostname hash] ^ _port;
265 - (NSString*) hostname {return _hostname;}
270 struct hostent *ent = gethostbyname(_hostname.UTF8String);
272 Log(@"HostAddress: DNS lookup failed for <%@>: %s", _hostname, hstrerror(h_errno));
275 return * (const in_addr_t*) ent->h_addr_list[0];
279 - (BOOL) isSameHost: (IPAddress*)addr
281 return [addr isKindOfClass: [HostAddress class]] && [_hostname caseInsensitiveCompare: addr.hostname]==0;
290 @implementation RecentAddress
293 - (id) initWithIPAddress: (IPAddress*)addr
295 return [super initWithIPv4: addr.ipv4 port: addr.port];
299 @synthesize lastSuccess=_lastSuccess, successes=_successes;
303 if( _successes < 0xFFFF )
305 _lastSuccess = CFAbsoluteTimeGetCurrent();
311 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
312 BOOL significant = ( now-_lastSuccess >= 18*60*60 );
318 - (void)encodeWithCoder:(NSCoder *)coder
320 [super encodeWithCoder: coder];
321 [coder encodeDouble: _lastSuccess forKey: @"last"];
322 [coder encodeInt: _successes forKey: @"succ"];
325 - (id)initWithCoder:(NSCoder *)decoder
327 self = [super initWithCoder: decoder];
329 _lastSuccess = [decoder decodeDoubleForKey: @"last"];
330 _successes = [decoder decodeIntForKey: @"succ"];
344 TestCase(IPAddress) {
345 RequireTestCase(CollectionUtils);
346 IPAddress *addr = [[IPAddress alloc] initWithIPv4: htonl(0x0A0001FE) port: 8080];
347 CAssertEq(addr.ipv4,(UInt32)htonl(0x0A0001FE));
348 CAssertEq(addr.port,8080);
349 CAssertEqual(addr.hostname,@"10.0.1.254");
350 CAssertEqual(addr.description,@"10.0.1.254:8080");
351 CAssert(addr.isPrivate);
353 addr = [[IPAddress alloc] initWithHostname: @"66.66.0.255" port: 123];
354 CAssertEq(addr.class,[IPAddress class]);
355 CAssertEq(addr.ipv4,(UInt32)htonl(0x424200FF));
356 CAssertEq(addr.port,123);
357 CAssertEqual(addr.hostname,@"66.66.0.255");
358 CAssertEqual(addr.description,@"66.66.0.255:123");
359 CAssert(!addr.isPrivate);
361 addr = [[IPAddress alloc] initWithHostname: @"www.apple.com" port: 80];
362 CAssertEq(addr.class,[HostAddress class]);
363 Log(@"www.apple.com = %@ [0x%08X]", addr.ipv4name, ntohl(addr.ipv4));
364 CAssertEq(addr.ipv4,(UInt32)htonl(0x11FBC820));
365 CAssertEq(addr.port,80);
366 CAssertEqual(addr.hostname,@"www.apple.com");
367 CAssertEqual(addr.description,@"www.apple.com:80");
368 CAssert(!addr.isPrivate);
373 Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
375 Redistribution and use in source and binary forms, with or without modification, are permitted
376 provided that the following conditions are met:
378 * Redistributions of source code must retain the above copyright notice, this list of conditions
379 and the following disclaimer.
380 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
381 and the following disclaimer in the documentation and/or other materials provided with the
384 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
385 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
386 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
387 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
388 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
389 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
390 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
391 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.