1// NetAddress.cpp 2 3#include <new> 4#include <netdb.h> 5#include <stdio.h> 6#include <unistd.h> 7 8#if defined(HAIKU_TARGET_PLATFORM_DANO) || defined(HAIKU_TARGET_PLATFORM_DANO) 9# include <net/route.h> 10# include <sys/sockio.h> 11# include <stdlib.h> 12#endif 13 14#include <AutoLocker.h> 15#include <ByteOrder.h> 16#include <HashString.h> 17#include <Referenceable.h> 18 19#include "Compatibility.h" 20#include "Locker.h" 21#include "NetAddress.h" 22 23// constructor 24NetAddress::NetAddress() 25{ 26 fAddress.sin_family = AF_INET; 27 fAddress.sin_addr.s_addr = 0; 28 fAddress.sin_port = 0; 29} 30 31// constructor 32NetAddress::NetAddress(const sockaddr_in& address) 33{ 34 fAddress = address; 35} 36 37// copy constructor 38NetAddress::NetAddress(const NetAddress& address) 39{ 40 fAddress = address.fAddress; 41} 42 43// SetIP 44void 45NetAddress::SetIP(int32 address) 46{ 47 fAddress.sin_addr.s_addr = B_HOST_TO_BENDIAN_INT32(address); 48} 49 50// GetIP 51int32 52NetAddress::GetIP() const 53{ 54 return B_BENDIAN_TO_HOST_INT32(fAddress.sin_addr.s_addr); 55} 56 57// SetPort 58void 59NetAddress::SetPort(uint16 port) 60{ 61 fAddress.sin_port = B_HOST_TO_BENDIAN_INT32(port); 62} 63 64// GetPort 65uint16 66NetAddress::GetPort() const 67{ 68 return B_BENDIAN_TO_HOST_INT16(fAddress.sin_port); 69} 70 71// SetAddress 72void 73NetAddress::SetAddress(const sockaddr_in& address) 74{ 75 fAddress = address; 76} 77 78// GetAddress 79const sockaddr_in& 80NetAddress::GetAddress() const 81{ 82 return fAddress; 83} 84 85// IsLocal 86bool 87NetAddress::IsLocal() const 88{ 89 // special address? 90 if (fAddress.sin_addr.s_addr == INADDR_ANY 91 || fAddress.sin_addr.s_addr == INADDR_BROADCAST) { 92 return false; 93 } 94 // create a socket and try to bind it to a port of this address 95 int fd = socket(AF_INET, SOCK_DGRAM, 0); 96 if (fd < 0) 97 return false; 98#if defined(HAIKU_TARGET_PLATFORM_DANO) 99 // BONE does allow you to bind to any address! 100 // Therefore, we iterate over all routes, and see if there are any local 101 // ones for this address. 102 103 bool result = false; 104 uint32 count; 105 if (ioctl(fd, SIOCGRTSIZE, &count) == 0) { 106 route_req_t* routes = (route_req_t*)malloc(count * sizeof(route_req_t)); 107 if (routes != NULL) { 108 route_table_req table; 109 table.rrtp = routes; 110 table.len = count * sizeof(route_req_t); 111 table.cnt = count; 112 if (ioctl(fd, SIOCGRTTABLE, &table) == 0) { 113 for (uint32 i = 0; i < table.cnt; i++) { 114 if ((routes[i].flags & RTF_LOCAL) == 0) 115 continue; 116 if (((sockaddr_in*)&routes[i].dst)->sin_addr.s_addr 117 == fAddress.sin_addr.s_addr) { 118 result = true; 119 break; 120 } 121 } 122 } 123 free(routes); 124 } 125 } 126#else 127 // bind it to a port 128 sockaddr_in addr = fAddress; 129 addr.sin_port = 0; 130 bool result = (bind(fd, (sockaddr*)&addr, sizeof(addr)) == 0); 131#endif 132 closesocket(fd); 133 134 return result; 135} 136 137 138// GetString 139status_t 140NetAddress::GetString(HashString* string, bool includePort) const 141{ 142 if (!string) 143 return B_BAD_VALUE; 144 char buffer[32]; 145 uint32 ip = GetIP(); 146 if (includePort) { 147 sprintf(buffer, "%lu.%lu.%lu.%lu:%hu", 148 ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff, 149 GetPort()); 150 } else { 151 sprintf(buffer, "%lu.%lu.%lu.%lu", 152 ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); 153 } 154 return (string->SetTo(buffer) ? B_OK : B_NO_MEMORY); 155} 156 157// GetHashCode 158uint32 159NetAddress::GetHashCode() const 160{ 161 return (fAddress.sin_addr.s_addr * 31 + fAddress.sin_port); 162} 163 164// = 165NetAddress& 166NetAddress::operator=(const NetAddress& address) 167{ 168 fAddress = address.fAddress; 169 return *this; 170} 171 172// == 173bool 174NetAddress::operator==(const NetAddress& address) const 175{ 176 return (fAddress.sin_addr.s_addr == address.fAddress.sin_addr.s_addr 177 && fAddress.sin_port == address.fAddress.sin_port); 178} 179 180// != 181bool 182NetAddress::operator!=(const NetAddress& address) const 183{ 184 return !(*this == address); 185} 186 187 188// #pragma mark - 189 190// Resolver 191class NetAddressResolver::Resolver : public BReferenceable { 192public: 193 Resolver() 194 : BReferenceable(), 195 fLock() 196 { 197 } 198 199 status_t InitCheck() const 200 { 201 return (fLock.Sem() >= 0 ? B_OK : B_NO_INIT); 202 } 203 204 status_t GetHostAddress(const char* hostName, NetAddress* address) 205 { 206 AutoLocker<Locker> _(fLock); 207 struct hostent* host = gethostbyname(hostName); 208 if (!host) 209 return h_errno; 210 if (host->h_addrtype != AF_INET || !host->h_addr_list[0]) 211 return B_BAD_VALUE; 212 sockaddr_in addr; 213 addr.sin_family = AF_INET; 214 addr.sin_port = 0; 215 addr.sin_addr = *(in_addr*)host->h_addr_list[0]; 216 *address = addr; 217 return B_OK; 218 } 219 220protected: 221 virtual void LastReferenceReleased() 222 { 223 // don't delete 224 } 225 226private: 227 Locker fLock; 228}; 229 230// constructor 231NetAddressResolver::NetAddressResolver() 232{ 233 _Lock(); 234 // initialize static instance, if not done yet 235 if (sResolver) { 236 sResolver->AcquireReference(); 237 fResolver = sResolver; 238 } else { 239 sResolver = new(std::nothrow) Resolver; 240 if (sResolver) { 241 if (sResolver->InitCheck() != B_OK) { 242 delete sResolver; 243 sResolver = NULL; 244 } 245 } 246 fResolver = sResolver; 247 } 248 _Unlock(); 249} 250 251// destructor 252NetAddressResolver::~NetAddressResolver() 253{ 254 if (fResolver) { 255 _Lock(); 256 if (sResolver->ReleaseReference() == 1) { 257 delete sResolver; 258 sResolver = NULL; 259 } 260 _Unlock(); 261 } 262} 263 264// InitCheck 265status_t 266NetAddressResolver::InitCheck() const 267{ 268 return (fResolver ? B_OK : B_NO_INIT); 269} 270 271// GetAddress 272status_t 273NetAddressResolver::GetHostAddress(const char* hostName, NetAddress* address) 274{ 275 if (!fResolver) 276 return B_NO_INIT; 277 if (!hostName || !address) 278 return B_BAD_VALUE; 279 return fResolver->GetHostAddress(hostName, address); 280} 281 282// _Lock 283void 284NetAddressResolver::_Lock() 285{ 286 while (atomic_add(&sLockCounter, 1) > 0) { 287 atomic_add(&sLockCounter, -1); 288 snooze(10000); 289 } 290} 291 292// _Unlock 293void 294NetAddressResolver::_Unlock() 295{ 296 atomic_add(&sLockCounter, -1); 297} 298 299 300// sResolver 301NetAddressResolver::Resolver* volatile NetAddressResolver::sResolver = NULL; 302 303// sLockCounter 304vint32 NetAddressResolver::sLockCounter = 0; 305