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
NetAddress()25 NetAddress::NetAddress()
26 {
27 fAddress.sin_family = AF_INET;
28 fAddress.sin_addr.s_addr = 0;
29 fAddress.sin_port = 0;
30 }
31
32 // constructor
NetAddress(const sockaddr_in & address)33 NetAddress::NetAddress(const sockaddr_in& address)
34 {
35 fAddress = address;
36 }
37
38 // copy constructor
NetAddress(const NetAddress & address)39 NetAddress::NetAddress(const NetAddress& address)
40 {
41 fAddress = address.fAddress;
42 }
43
44 // SetIP
45 void
SetIP(int32 address)46 NetAddress::SetIP(int32 address)
47 {
48 fAddress.sin_addr.s_addr = B_HOST_TO_BENDIAN_INT32(address);
49 }
50
51 // GetIP
52 int32
GetIP() const53 NetAddress::GetIP() const
54 {
55 return B_BENDIAN_TO_HOST_INT32(fAddress.sin_addr.s_addr);
56 }
57
58 // SetPort
59 void
SetPort(uint16 port)60 NetAddress::SetPort(uint16 port)
61 {
62 fAddress.sin_port = B_HOST_TO_BENDIAN_INT32(port);
63 }
64
65 // GetPort
66 uint16
GetPort() const67 NetAddress::GetPort() const
68 {
69 return B_BENDIAN_TO_HOST_INT16(fAddress.sin_port);
70 }
71
72 // SetAddress
73 void
SetAddress(const sockaddr_in & address)74 NetAddress::SetAddress(const sockaddr_in& address)
75 {
76 fAddress = address;
77 }
78
79 // GetAddress
80 const sockaddr_in&
GetAddress() const81 NetAddress::GetAddress() const
82 {
83 return fAddress;
84 }
85
86 // IsLocal
87 bool
IsLocal() const88 NetAddress::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
140 status_t
GetString(HashString * string,bool includePort) const141 NetAddress::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
159 uint32
GetHashCode() const160 NetAddress::GetHashCode() const
161 {
162 return (fAddress.sin_addr.s_addr * 31 + fAddress.sin_port);
163 }
164
165 // =
166 NetAddress&
operator =(const NetAddress & address)167 NetAddress::operator=(const NetAddress& address)
168 {
169 fAddress = address.fAddress;
170 return *this;
171 }
172
173 // ==
174 bool
operator ==(const NetAddress & address) const175 NetAddress::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 // !=
182 bool
operator !=(const NetAddress & address) const183 NetAddress::operator!=(const NetAddress& address) const
184 {
185 return !(*this == address);
186 }
187
188
189 // #pragma mark -
190
191 // Resolver
192 class NetAddressResolver::Resolver : public BReferenceable {
193 public:
Resolver()194 Resolver()
195 : BReferenceable(),
196 fLock()
197 {
198 }
199
InitCheck() const200 status_t InitCheck() const
201 {
202 return fLock.InitCheck();
203 }
204
GetHostAddress(const char * hostName,NetAddress * address)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
221 protected:
LastReferenceReleased()222 virtual void LastReferenceReleased()
223 {
224 // don't delete
225 }
226
227 private:
228 Locker fLock;
229 };
230
231 // constructor
NetAddressResolver()232 NetAddressResolver::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
~NetAddressResolver()253 NetAddressResolver::~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
266 status_t
InitCheck() const267 NetAddressResolver::InitCheck() const
268 {
269 return (fResolver ? B_OK : B_NO_INIT);
270 }
271
272 // GetAddress
273 status_t
GetHostAddress(const char * hostName,NetAddress * address)274 NetAddressResolver::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
284 void
_Lock()285 NetAddressResolver::_Lock()
286 {
287 while (atomic_add(&sLockCounter, 1) > 0) {
288 atomic_add(&sLockCounter, -1);
289 snooze(10000);
290 }
291 }
292
293 // _Unlock
294 void
_Unlock()295 NetAddressResolver::_Unlock()
296 {
297 atomic_add(&sLockCounter, -1);
298 }
299
300
301 // sResolver
302 NetAddressResolver::Resolver* volatile NetAddressResolver::sResolver = NULL;
303
304 // sLockCounter
305 int32 NetAddressResolver::sLockCounter = 0;
306