xref: /haiku/src/kits/network/libnetapi/NetEndpoint.cpp (revision a085e81e62d7a860f809b4fb7c7bf5654c396985)
1 /*
2  * Copyright 2002-2008, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include <Message.h>
7 #include <NetEndpoint.h>
8 
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <netdb.h>
12 #include <netinet/in.h>
13 #include <new>
14 #include <string.h>
15 #include <sys/socket.h>
16 #include <sys/time.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19 
20 
21 BNetEndpoint::BNetEndpoint(int type)
22 	:
23 	fStatus(B_NO_INIT),
24 	fFamily(AF_INET),
25 	fType(type),
26 	fProtocol(0),
27 	fSocket(-1),
28 	fTimeout(B_INFINITE_TIMEOUT)
29 {
30 	_SetupSocket();
31 }
32 
33 
34 BNetEndpoint::BNetEndpoint(int family, int type, int protocol)
35 	:
36 	fStatus(B_NO_INIT),
37 	fFamily(family),
38 	fType(type),
39 	fProtocol(protocol),
40 	fSocket(-1),
41 	fTimeout(B_INFINITE_TIMEOUT)
42 {
43 	_SetupSocket();
44 }
45 
46 
47 BNetEndpoint::BNetEndpoint(BMessage* archive)
48 	:
49 	fStatus(B_NO_INIT),
50 	fFamily(AF_INET),
51 	fProtocol(0),
52 	fSocket(-1),
53 	fTimeout(B_INFINITE_TIMEOUT)
54 {
55 	if (!archive)
56 		return;
57 
58 	in_addr addr, peer;
59 	unsigned short addrPort = 0, peerPort = 0;
60 
61 	fStatus = archive->FindInt32("_BNetEndpoint_addr_addr",
62 		(int32 *)&addr.s_addr);
63 	if (fStatus == B_OK) {
64 		fStatus = archive->FindInt16("_BNetEndpoint_addr_port",
65 			(int16 *)&addrPort);
66 		if (fStatus == B_OK)
67 			fStatus = fAddr.SetTo(addr, addrPort);
68 	}
69 
70 	fStatus = archive->FindInt32("_BNetEndpoint_peer_addr",
71 		(int32 *)&peer.s_addr);
72 	if (fStatus == B_OK) {
73 		fStatus = archive->FindInt16("_BNetEndpoint_peer_port",
74 			(int16 *)&peerPort);
75 		if (fStatus == B_OK)
76 			fStatus = fPeer.SetTo(peer, peerPort);
77 	}
78 
79 	fStatus = archive->FindInt64("_BNetEndpoint_timeout", (int64 *)&fTimeout);
80 	if (fStatus == B_OK)
81 		fStatus = archive->FindInt32("_BNetEndpoint_proto", (int32 *)&fType);
82 
83 	if (fStatus == B_OK)
84 		_SetupSocket();
85 }
86 
87 
88 BNetEndpoint::BNetEndpoint(const BNetEndpoint& endpoint)
89 	:
90 	fStatus(endpoint.fStatus),
91 	fFamily(endpoint.fFamily),
92 	fType(endpoint.fType),
93 	fProtocol(endpoint.fProtocol),
94 	fSocket(-1),
95 	fTimeout(endpoint.fTimeout),
96 	fAddr(endpoint.fAddr),
97 	fPeer(endpoint.fPeer)
98 
99 {
100 	if (endpoint.fSocket >= 0) {
101 		fSocket = dup(endpoint.fSocket);
102 		if (fSocket < 0)
103 			fStatus = errno;
104 	}
105 }
106 
107 
108 BNetEndpoint&
109 BNetEndpoint::operator=(const BNetEndpoint& endpoint)
110 {
111 	if (this == &endpoint)
112 		return *this;
113 
114 	Close();
115 
116 	fStatus = endpoint.fStatus;
117 	fFamily = endpoint.fFamily;
118 	fType = endpoint.fType;
119 	fProtocol = endpoint.fProtocol;
120 	fTimeout = endpoint.fTimeout;
121 	fAddr = endpoint.fAddr;
122 	fPeer = endpoint.fPeer;
123 
124 	fSocket = -1;
125 	if (endpoint.fSocket >= 0) {
126 		fSocket = dup(endpoint.fSocket);
127 		if (fSocket < 0)
128 			fStatus = errno;
129 	}
130 
131     return *this;
132 }
133 
134 
135 BNetEndpoint::~BNetEndpoint()
136 {
137 	if (fSocket >= 0)
138 		Close();
139 }
140 
141 
142 // #pragma mark -
143 
144 
145 status_t
146 BNetEndpoint::Archive(BMessage* into, bool deep) const
147 {
148 	if (!into)
149 		return B_ERROR;
150 
151 	status_t status = BArchivable::Archive(into, deep);
152 	if (status != B_OK)
153 		return status;
154 
155 	in_addr addr, peer;
156 	unsigned short addrPort, peerPort;
157 
158 	status = fAddr.GetAddr(addr, &addrPort);
159 	if (status == B_OK) {
160 		status = into->AddInt32("_BNetEndpoint_addr_addr", addr.s_addr);
161 		if (status == B_OK)
162 			status = into->AddInt16("_BNetEndpoint_addr_port", addrPort);
163 		if (status != B_OK)
164 			return status;
165 	}
166 	status = fPeer.GetAddr(peer, &peerPort);
167 	if (status == B_OK) {
168 		status = into->AddInt32("_BNetEndpoint_peer_addr", peer.s_addr);
169 		if (status == B_OK)
170 			status = into->AddInt16("_BNetEndpoint_peer_port", peerPort);
171 		if (status != B_OK)
172 			return status;
173 	}
174 
175 	status = into->AddInt64("_BNetEndpoint_timeout", fTimeout);
176 	if (status == B_OK)
177 		status = into->AddInt32("_BNetEndpoint_proto", fType);
178 
179 	return status;
180 }
181 
182 
183 BArchivable*
184 BNetEndpoint::Instantiate(BMessage* archive)
185 {
186 	if (!archive)
187 		return NULL;
188 
189 	if (!validate_instantiation(archive, "BNetEndpoint"))
190 		return NULL;
191 
192 	BNetEndpoint* endpoint = new BNetEndpoint(archive);
193 	if (endpoint && endpoint->InitCheck() == B_OK)
194 		return endpoint;
195 
196 	delete endpoint;
197 	return NULL;
198 }
199 
200 
201 // #pragma mark -
202 
203 
204 status_t
205 BNetEndpoint::InitCheck() const
206 {
207 	return fSocket == -1 ? B_NO_INIT : B_OK;
208 }
209 
210 
211 int
212 BNetEndpoint::Socket() const
213 {
214 	return fSocket;
215 }
216 
217 
218 const BNetAddress&
219 BNetEndpoint::LocalAddr() const
220 {
221 	return fAddr;
222 }
223 
224 
225 const BNetAddress&
226 BNetEndpoint::RemoteAddr() const
227 {
228 	return fPeer;
229 }
230 
231 
232 status_t
233 BNetEndpoint::SetProtocol(int protocol)
234 {
235 	Close();
236 	fType = protocol;	// sic (protocol is SOCK_DGRAM or SOCK_STREAM)
237 	return _SetupSocket();
238 }
239 
240 
241 int
242 BNetEndpoint::SetOption(int32 option, int32 level,
243 	const void* data, unsigned int length)
244 {
245 	if (fSocket < 0 && _SetupSocket() != B_OK)
246 		return fStatus;
247 
248 	if (setsockopt(fSocket, level, option, data, length) < 0) {
249 		fStatus = errno;
250 		return B_ERROR;
251 	}
252 
253 	return B_OK;
254 }
255 
256 
257 int
258 BNetEndpoint::SetNonBlocking(bool enable)
259 {
260 	if (fSocket < 0 && _SetupSocket() != B_OK)
261 		return fStatus;
262 
263 	int flags = fcntl(fSocket, F_GETFL);
264 	if (flags < 0) {
265 		fStatus = errno;
266 		return B_ERROR;
267 	}
268 
269 	if (enable)
270 		flags |= O_NONBLOCK;
271 	else
272 		flags &= ~O_NONBLOCK;
273 
274 	if (fcntl(fSocket, F_SETFL, flags) < 0) {
275 		fStatus = errno;
276 		return B_ERROR;
277 	}
278 
279 	return B_OK;
280 }
281 
282 
283 int
284 BNetEndpoint::SetReuseAddr(bool enable)
285 {
286 	if (fSocket < 0 && _SetupSocket() != B_OK)
287 		return fStatus;
288 
289 	int onoff = (int) enable;
290 	return SetOption(SO_REUSEADDR, SOL_SOCKET, &onoff, sizeof(onoff));
291 }
292 
293 
294 void
295 BNetEndpoint::SetTimeout(bigtime_t timeout)
296 {
297 	fTimeout = timeout;
298 	// TODO: Map value < 0 to B_INFINITE_TIMEOUT or use -1 by default.
299 }
300 
301 
302 int
303 BNetEndpoint::Error() const
304 {
305 	return (int)fStatus;
306 }
307 
308 
309 char*
310 BNetEndpoint::ErrorStr() const
311 {
312 	return strerror(fStatus);
313 }
314 
315 
316 // #pragma mark -
317 
318 
319 void
320 BNetEndpoint::Close()
321 {
322 	if (fSocket >= 0)
323 		close(fSocket);
324 
325 	fSocket = -1;
326 	fStatus = B_NO_INIT;
327 }
328 
329 
330 status_t
331 BNetEndpoint::Bind(const BNetAddress& address)
332 {
333 	if (fSocket < 0 && _SetupSocket() != B_OK)
334 		return fStatus;
335 
336 	struct sockaddr_in addr;
337 	status_t status = address.GetAddr(addr);
338 	if (status != B_OK)
339 		return status;
340 
341 	if (bind(fSocket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
342 		fStatus = errno;
343 		Close();
344 		return B_ERROR;
345 	}
346 
347 	socklen_t addrSize = sizeof(addr);
348 	if (getsockname(fSocket, (struct sockaddr *)&addr, &addrSize) < 0) {
349 		fStatus = errno;
350 		Close();
351 		return B_ERROR;
352 	}
353 
354 	fAddr.SetTo(addr);
355 	return B_OK;
356 }
357 
358 
359 status_t
360 BNetEndpoint::Bind(int port)
361 {
362 	BNetAddress addr(INADDR_ANY, port);
363 	return Bind(addr);
364 }
365 
366 
367 status_t
368 BNetEndpoint::Connect(const BNetAddress& address)
369 {
370 	if (fSocket < 0 && _SetupSocket() != B_OK)
371 		return fStatus;
372 
373 	sockaddr_in addr;
374 	if (address.GetAddr(addr) != B_OK)
375 		return B_ERROR;
376 
377 	if (connect(fSocket, (sockaddr *) &addr, sizeof(addr)) < 0) {
378 		Close();
379 		fStatus = errno;
380 		return B_ERROR;
381 	}
382 
383 	socklen_t addrSize = sizeof(addr);
384 	if (getpeername(fSocket, (sockaddr *) &addr, &addrSize) < 0) {
385 		Close();
386 		fStatus = errno;
387 		return B_ERROR;
388 	}
389 	fPeer.SetTo(addr);
390 	return B_OK;
391 }
392 
393 
394 status_t
395 BNetEndpoint::Connect(const char *hostname, int port)
396 {
397 	BNetAddress addr(hostname, port);
398 	return Connect(addr);
399 }
400 
401 
402 status_t
403 BNetEndpoint::Listen(int backlog)
404 {
405 	if (fSocket < 0 && _SetupSocket() != B_OK)
406 		return fStatus;
407 
408 	if (listen(fSocket, backlog) < 0) {
409 		Close();
410 		fStatus = errno;
411 		return B_ERROR;
412 	}
413 	return B_OK;
414 }
415 
416 
417 BNetEndpoint*
418 BNetEndpoint::Accept(int32 timeout)
419 {
420 	// TODO: IsDataPending() expects 0 as special value for infinite timeout,
421 	// hence the following call is broken for timeout < 0 and timeout == 0.
422 	if (!IsDataPending(timeout < 0 ? B_INFINITE_TIMEOUT : 1000LL * timeout))
423 		return NULL;
424 
425 	struct sockaddr_in addr;
426 	socklen_t addrSize = sizeof(addr);
427 
428 	int socket = accept(fSocket, (struct sockaddr *) &addr, &addrSize);
429 	if (socket < 0) {
430 		Close();
431 		fStatus = errno;
432 		return NULL;
433 	}
434 
435 	BNetEndpoint* endpoint = new (std::nothrow) BNetEndpoint(*this);
436 	if (endpoint == NULL) {
437 		close(socket);
438 		fStatus = B_NO_MEMORY;
439 		return NULL;
440 	}
441 
442 	endpoint->fSocket = socket;
443 	endpoint->fPeer.SetTo(addr);
444 
445 	if (getsockname(socket, (struct sockaddr *)&addr, &addrSize) < 0) {
446 		delete endpoint;
447 		fStatus = errno;
448 		return NULL;
449 	}
450 
451 	endpoint->fAddr.SetTo(addr);
452 	return endpoint;
453 }
454 
455 
456 // #pragma mark -
457 
458 
459 bool
460 BNetEndpoint::IsDataPending(bigtime_t timeout)
461 {
462 	struct timeval tv;
463 	fd_set fds;
464 
465 	FD_ZERO(&fds);
466 	FD_SET(fSocket, &fds);
467 
468 	if (timeout > 0) {
469 		tv.tv_sec = timeout / 1000000;
470 			// TODO: A big value (e.g. B_INFINITE_TIMEOUT) will overflow!
471 		tv.tv_usec = (timeout % 1000000);
472 	}
473 
474 	if (select(fSocket + 1, &fds, NULL, NULL, timeout > 0 ? &tv : NULL) < 0) {
475 		fStatus = errno;
476 		return false;
477 	}
478 
479 	return FD_ISSET(fSocket, &fds);
480 }
481 
482 
483 int32
484 BNetEndpoint::Receive(void* buffer, size_t length, int flags)
485 {
486 	if (fSocket < 0 && _SetupSocket() != B_OK)
487 		return fStatus;
488 
489 	// TODO: For fTimeout == 0 this is broken as IsDataPending(0) means wait
490 	// without timeout. Furthermore the default fTimeout is B_INFINITE_TIMEOUT.
491 	if (fTimeout >= 0 && IsDataPending(fTimeout) == false)
492 		return 0;
493 
494 	ssize_t bytesReceived = recv(fSocket, buffer, length, flags);
495 	if (bytesReceived < 0)
496 		fStatus = errno;
497 
498 	return bytesReceived;
499 }
500 
501 
502 int32
503 BNetEndpoint::Receive(BNetBuffer& buffer, size_t length, int flags)
504 {
505 	BNetBuffer chunk(length);
506 	length = Receive(chunk.Data(), length, flags);
507 	buffer.AppendData(chunk.Data(), length);
508 	return length;
509 }
510 
511 
512 int32
513 BNetEndpoint::ReceiveFrom(void* buffer, size_t length,
514 	BNetAddress& address, int flags)
515 {
516 	if (fSocket < 0 && _SetupSocket() != B_OK)
517 		return fStatus;
518 
519 	// TODO: For fTimeout == 0 this is broken as IsDataPending(0) means wait
520 	// without timeout. Furthermore the default fTimeout is B_INFINITE_TIMEOUT.
521 	if (fTimeout >= 0 && IsDataPending(fTimeout) == false)
522 		return 0;
523 
524 	struct sockaddr_in addr;
525 	socklen_t addrSize = sizeof(addr);
526 
527 	length = recvfrom(fSocket, buffer, length, flags,
528 		(struct sockaddr *)&addr, &addrSize);
529 	if (length < 0)
530 		fStatus = errno;
531 	else
532 		address.SetTo(addr);
533 
534 	return length;
535 }
536 
537 
538 int32
539 BNetEndpoint::ReceiveFrom(BNetBuffer& buffer, size_t length,
540 	BNetAddress& address, int flags)
541 {
542 	BNetBuffer chunk(length);
543 	length = ReceiveFrom(chunk.Data(), length, address, flags);
544 	buffer.AppendData(chunk.Data(), length);
545 	return length;
546 }
547 
548 
549 int32
550 BNetEndpoint::Send(const void* buffer, size_t length, int flags)
551 {
552 	if (fSocket < 0 && _SetupSocket() != B_OK)
553 		return fStatus;
554 
555 	ssize_t bytesSent = send(fSocket, (const char *) buffer, length, flags);
556 	if (bytesSent < 0)
557 		fStatus = errno;
558 
559 	return bytesSent;
560 }
561 
562 
563 int32
564 BNetEndpoint::Send(BNetBuffer& buffer, int flags)
565 {
566 	return Send(buffer.Data(), buffer.Size(), flags);
567 }
568 
569 
570 int32
571 BNetEndpoint::SendTo(const void* buffer, size_t length,
572 	const BNetAddress& address, int flags)
573 {
574 	if (fSocket < 0 && _SetupSocket() != B_OK)
575 		return fStatus;
576 
577 	struct sockaddr_in addr;
578 	if (address.GetAddr(addr) != B_OK)
579 		return B_ERROR;
580 
581 	ssize_t	bytesSent = sendto(fSocket, buffer, length, flags,
582 		(struct sockaddr *) &addr, sizeof(addr));
583 	if (bytesSent < 0)
584 		fStatus = errno;
585 
586 	return bytesSent;
587 }
588 
589 
590 int32
591 BNetEndpoint::SendTo(BNetBuffer& buffer,
592 	const BNetAddress& address, int flags)
593 {
594 	return SendTo(buffer.Data(), buffer.Size(), address, flags);
595 }
596 
597 
598 // #pragma mark -
599 
600 
601 status_t
602 BNetEndpoint::_SetupSocket()
603 {
604 	if ((fSocket = socket(fFamily, fType, fProtocol)) < 0)
605 		fStatus = errno;
606 	else
607 		fStatus = B_OK;
608 	return fStatus;
609 }
610 
611 
612 // #pragma mark -
613 
614 status_t BNetEndpoint::InitCheck()
615 {
616 	return const_cast<const BNetEndpoint*>(this)->InitCheck();
617 }
618 
619 
620 const BNetAddress& BNetEndpoint::LocalAddr()
621 {
622 	return const_cast<const BNetEndpoint*>(this)->LocalAddr();
623 }
624 
625 
626 const BNetAddress& BNetEndpoint::RemoteAddr()
627 {
628 	return const_cast<const BNetEndpoint*>(this)->RemoteAddr();
629 }
630 
631 
632 // #pragma mark -
633 
634 
635 // These are virtuals, implemented for binary compatibility purpose
636 void BNetEndpoint::_ReservedBNetEndpointFBCCruft1() {}
637 void BNetEndpoint::_ReservedBNetEndpointFBCCruft2() {}
638 void BNetEndpoint::_ReservedBNetEndpointFBCCruft3() {}
639 void BNetEndpoint::_ReservedBNetEndpointFBCCruft4() {}
640 void BNetEndpoint::_ReservedBNetEndpointFBCCruft5() {}
641 void BNetEndpoint::_ReservedBNetEndpointFBCCruft6() {}
642 
643