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