xref: /haiku/src/kits/network/libnetapi/NetEndpoint.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
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 // Private constructor only used from BNetEndpoint::Accept().
109 BNetEndpoint::BNetEndpoint(const BNetEndpoint& endpoint, int socket,
110 	const struct sockaddr_in& localAddress,
111 	const struct sockaddr_in& peerAddress)
112 	:
113 	fStatus(endpoint.fStatus),
114 	fFamily(endpoint.fFamily),
115 	fType(endpoint.fType),
116 	fProtocol(endpoint.fProtocol),
117 	fSocket(socket),
118 	fTimeout(endpoint.fTimeout),
119 	fAddr(localAddress),
120 	fPeer(peerAddress)
121 {
122 }
123 
124 
125 BNetEndpoint&
126 BNetEndpoint::operator=(const BNetEndpoint& endpoint)
127 {
128 	if (this == &endpoint)
129 		return *this;
130 
131 	Close();
132 
133 	fStatus = endpoint.fStatus;
134 	fFamily = endpoint.fFamily;
135 	fType = endpoint.fType;
136 	fProtocol = endpoint.fProtocol;
137 	fTimeout = endpoint.fTimeout;
138 	fAddr = endpoint.fAddr;
139 	fPeer = endpoint.fPeer;
140 
141 	fSocket = -1;
142 	if (endpoint.fSocket >= 0) {
143 		fSocket = dup(endpoint.fSocket);
144 		if (fSocket < 0)
145 			fStatus = errno;
146 	}
147 
148     return *this;
149 }
150 
151 
152 BNetEndpoint::~BNetEndpoint()
153 {
154 	if (fSocket >= 0)
155 		Close();
156 }
157 
158 
159 // #pragma mark -
160 
161 
162 status_t
163 BNetEndpoint::Archive(BMessage* into, bool deep) const
164 {
165 	if (!into)
166 		return B_ERROR;
167 
168 	status_t status = BArchivable::Archive(into, deep);
169 	if (status != B_OK)
170 		return status;
171 
172 	in_addr addr, peer;
173 	unsigned short addrPort, peerPort;
174 
175 	status = fAddr.GetAddr(addr, &addrPort);
176 	if (status == B_OK) {
177 		status = into->AddInt32("_BNetEndpoint_addr_addr", addr.s_addr);
178 		if (status == B_OK)
179 			status = into->AddInt16("_BNetEndpoint_addr_port", addrPort);
180 		if (status != B_OK)
181 			return status;
182 	}
183 	status = fPeer.GetAddr(peer, &peerPort);
184 	if (status == B_OK) {
185 		status = into->AddInt32("_BNetEndpoint_peer_addr", peer.s_addr);
186 		if (status == B_OK)
187 			status = into->AddInt16("_BNetEndpoint_peer_port", peerPort);
188 		if (status != B_OK)
189 			return status;
190 	}
191 
192 	status = into->AddInt64("_BNetEndpoint_timeout", fTimeout);
193 	if (status == B_OK)
194 		status = into->AddInt32("_BNetEndpoint_proto", fType);
195 
196 	return status;
197 }
198 
199 
200 BArchivable*
201 BNetEndpoint::Instantiate(BMessage* archive)
202 {
203 	if (!archive)
204 		return NULL;
205 
206 	if (!validate_instantiation(archive, "BNetEndpoint"))
207 		return NULL;
208 
209 	BNetEndpoint* endpoint = new BNetEndpoint(archive);
210 	if (endpoint && endpoint->InitCheck() == B_OK)
211 		return endpoint;
212 
213 	delete endpoint;
214 	return NULL;
215 }
216 
217 
218 // #pragma mark -
219 
220 
221 status_t
222 BNetEndpoint::InitCheck() const
223 {
224 	return fSocket == -1 ? B_NO_INIT : B_OK;
225 }
226 
227 
228 int
229 BNetEndpoint::Socket() const
230 {
231 	return fSocket;
232 }
233 
234 
235 const BNetAddress&
236 BNetEndpoint::LocalAddr() const
237 {
238 	return fAddr;
239 }
240 
241 
242 const BNetAddress&
243 BNetEndpoint::RemoteAddr() const
244 {
245 	return fPeer;
246 }
247 
248 
249 status_t
250 BNetEndpoint::SetProtocol(int protocol)
251 {
252 	Close();
253 	fType = protocol;	// sic (protocol is SOCK_DGRAM or SOCK_STREAM)
254 	return _SetupSocket();
255 }
256 
257 
258 int
259 BNetEndpoint::SetOption(int32 option, int32 level,
260 	const void* data, unsigned int length)
261 {
262 	if (fSocket < 0 && _SetupSocket() != B_OK)
263 		return fStatus;
264 
265 	if (setsockopt(fSocket, level, option, data, length) < 0) {
266 		fStatus = errno;
267 		return B_ERROR;
268 	}
269 
270 	return B_OK;
271 }
272 
273 
274 int
275 BNetEndpoint::SetNonBlocking(bool enable)
276 {
277 	if (fSocket < 0 && _SetupSocket() != B_OK)
278 		return fStatus;
279 
280 	int flags = fcntl(fSocket, F_GETFL);
281 	if (flags < 0) {
282 		fStatus = errno;
283 		return B_ERROR;
284 	}
285 
286 	if (enable)
287 		flags |= O_NONBLOCK;
288 	else
289 		flags &= ~O_NONBLOCK;
290 
291 	if (fcntl(fSocket, F_SETFL, flags) < 0) {
292 		fStatus = errno;
293 		return B_ERROR;
294 	}
295 
296 	return B_OK;
297 }
298 
299 
300 int
301 BNetEndpoint::SetReuseAddr(bool enable)
302 {
303 	if (fSocket < 0 && _SetupSocket() != B_OK)
304 		return fStatus;
305 
306 	int onoff = (int) enable;
307 	return SetOption(SO_REUSEADDR, SOL_SOCKET, &onoff, sizeof(onoff));
308 }
309 
310 
311 void
312 BNetEndpoint::SetTimeout(bigtime_t timeout)
313 {
314 	fTimeout = timeout < 0 ? B_INFINITE_TIMEOUT : timeout;
315 }
316 
317 
318 int
319 BNetEndpoint::Error() const
320 {
321 	return (int)fStatus;
322 }
323 
324 
325 char*
326 BNetEndpoint::ErrorStr() const
327 {
328 	return strerror(fStatus);
329 }
330 
331 
332 // #pragma mark -
333 
334 
335 void
336 BNetEndpoint::Close()
337 {
338 	if (fSocket >= 0)
339 		close(fSocket);
340 
341 	fSocket = -1;
342 	fStatus = B_NO_INIT;
343 }
344 
345 
346 status_t
347 BNetEndpoint::Bind(const BNetAddress& address)
348 {
349 	if (fSocket < 0 && _SetupSocket() != B_OK)
350 		return fStatus;
351 
352 	struct sockaddr_in addr;
353 	status_t status = address.GetAddr(addr);
354 	if (status != B_OK)
355 		return status;
356 
357 	if (bind(fSocket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
358 		fStatus = errno;
359 		Close();
360 		return B_ERROR;
361 	}
362 
363 	socklen_t addrSize = sizeof(addr);
364 	if (getsockname(fSocket, (struct sockaddr *)&addr, &addrSize) < 0) {
365 		fStatus = errno;
366 		Close();
367 		return B_ERROR;
368 	}
369 
370 	fAddr.SetTo(addr);
371 	return B_OK;
372 }
373 
374 
375 status_t
376 BNetEndpoint::Bind(int port)
377 {
378 	BNetAddress addr(INADDR_ANY, port);
379 	return Bind(addr);
380 }
381 
382 
383 status_t
384 BNetEndpoint::Connect(const BNetAddress& address)
385 {
386 	if (fSocket < 0 && _SetupSocket() != B_OK)
387 		return fStatus;
388 
389 	sockaddr_in addr;
390 	if (address.GetAddr(addr) != B_OK)
391 		return B_ERROR;
392 
393 	if (connect(fSocket, (sockaddr *) &addr, sizeof(addr)) < 0) {
394 		Close();
395 		fStatus = errno;
396 		return B_ERROR;
397 	}
398 
399 	socklen_t addrSize = sizeof(addr);
400 	if (getpeername(fSocket, (sockaddr *) &addr, &addrSize) < 0) {
401 		Close();
402 		fStatus = errno;
403 		return B_ERROR;
404 	}
405 	fPeer.SetTo(addr);
406 	return B_OK;
407 }
408 
409 
410 status_t
411 BNetEndpoint::Connect(const char *hostname, int port)
412 {
413 	BNetAddress addr(hostname, port);
414 	return Connect(addr);
415 }
416 
417 
418 status_t
419 BNetEndpoint::Listen(int backlog)
420 {
421 	if (fSocket < 0 && _SetupSocket() != B_OK)
422 		return fStatus;
423 
424 	if (listen(fSocket, backlog) < 0) {
425 		Close();
426 		fStatus = errno;
427 		return B_ERROR;
428 	}
429 	return B_OK;
430 }
431 
432 
433 BNetEndpoint*
434 BNetEndpoint::Accept(int32 timeout)
435 {
436 	if (!IsDataPending(timeout < 0 ? B_INFINITE_TIMEOUT : 1000LL * timeout))
437 		return NULL;
438 
439 	struct sockaddr_in peerAddress;
440 	socklen_t peerAddressSize = sizeof(peerAddress);
441 
442 	int socket
443 		= accept(fSocket, (struct sockaddr *)&peerAddress, &peerAddressSize);
444 	if (socket < 0) {
445 		Close();
446 		fStatus = errno;
447 		return NULL;
448 	}
449 
450 	struct sockaddr_in localAddress;
451 	socklen_t localAddressSize = sizeof(localAddress);
452 	if (getsockname(socket, (struct sockaddr *)&localAddress,
453 			&localAddressSize) < 0) {
454 		close(socket);
455 		fStatus = errno;
456 		return NULL;
457 	}
458 
459 	BNetEndpoint* endpoint = new (std::nothrow) BNetEndpoint(*this, socket,
460 		localAddress, peerAddress);
461 	if (endpoint == NULL) {
462 		close(socket);
463 		fStatus = B_NO_MEMORY;
464 		return NULL;
465 	}
466 
467 	return endpoint;
468 }
469 
470 
471 // #pragma mark -
472 
473 
474 bool
475 BNetEndpoint::IsDataPending(bigtime_t timeout)
476 {
477 	struct timeval tv;
478 	fd_set fds;
479 
480 	FD_ZERO(&fds);
481 	FD_SET(fSocket, &fds);
482 
483 	// Make sure the timeout does not overflow. If it does, have an infinite
484 	// timeout instead. Note that this conveniently includes B_INFINITE_TIMEOUT.
485 	if (timeout > INT32_MAX * 1000000ll)
486 		timeout = -1;
487 
488 	if (timeout >= 0) {
489 		tv.tv_sec = timeout / 1000000;
490 		tv.tv_usec = (timeout % 1000000);
491 	}
492 
493 	int status;
494 	do {
495 		status = select(fSocket + 1, &fds, NULL, NULL,
496 			timeout >= 0 ? &tv : NULL);
497 	} while (status == -1 && errno == EINTR);
498 
499 	if (status < 0) {
500 		fStatus = errno;
501 		return false;
502 	}
503 
504 	return FD_ISSET(fSocket, &fds);
505 }
506 
507 
508 int32
509 BNetEndpoint::Receive(void* buffer, size_t length, int flags)
510 {
511 	if (fSocket < 0 && _SetupSocket() != B_OK)
512 		return fStatus;
513 
514 	if (fTimeout >= 0 && IsDataPending(fTimeout) == false)
515 		return 0;
516 
517 	ssize_t bytesReceived = recv(fSocket, buffer, length, flags);
518 	if (bytesReceived < 0)
519 		fStatus = errno;
520 
521 	return bytesReceived;
522 }
523 
524 
525 int32
526 BNetEndpoint::Receive(BNetBuffer& buffer, size_t length, int flags)
527 {
528 	BNetBuffer chunk(length);
529 	ssize_t bytesReceived = Receive(chunk.Data(), length, flags);
530 	if (bytesReceived > 0)
531 		buffer.AppendData(chunk.Data(), bytesReceived);
532 	return bytesReceived;
533 }
534 
535 
536 int32
537 BNetEndpoint::ReceiveFrom(void* buffer, size_t length,
538 	BNetAddress& address, int flags)
539 {
540 	if (fSocket < 0 && _SetupSocket() != B_OK)
541 		return fStatus;
542 
543 	if (fTimeout >= 0 && IsDataPending(fTimeout) == false)
544 		return 0;
545 
546 	struct sockaddr_in addr;
547 	socklen_t addrSize = sizeof(addr);
548 
549 	ssize_t bytesReceived = recvfrom(fSocket, buffer, length, flags,
550 		(struct sockaddr *)&addr, &addrSize);
551 	if (bytesReceived < 0)
552 		fStatus = errno;
553 	else
554 		address.SetTo(addr);
555 
556 	return bytesReceived;
557 }
558 
559 
560 int32
561 BNetEndpoint::ReceiveFrom(BNetBuffer& buffer, size_t length,
562 	BNetAddress& address, int flags)
563 {
564 	BNetBuffer chunk(length);
565 	ssize_t bytesReceived = ReceiveFrom(chunk.Data(), length, address, flags);
566 	if (bytesReceived > 0)
567 		buffer.AppendData(chunk.Data(), bytesReceived);
568 	return bytesReceived;
569 }
570 
571 
572 int32
573 BNetEndpoint::Send(const void* buffer, size_t length, int flags)
574 {
575 	if (fSocket < 0 && _SetupSocket() != B_OK)
576 		return fStatus;
577 
578 	ssize_t bytesSent = send(fSocket, (const char *) buffer, length, flags);
579 	if (bytesSent < 0)
580 		fStatus = errno;
581 
582 	return bytesSent;
583 }
584 
585 
586 int32
587 BNetEndpoint::Send(BNetBuffer& buffer, int flags)
588 {
589 	return Send(buffer.Data(), buffer.Size(), flags);
590 }
591 
592 
593 int32
594 BNetEndpoint::SendTo(const void* buffer, size_t length,
595 	const BNetAddress& address, int flags)
596 {
597 	if (fSocket < 0 && _SetupSocket() != B_OK)
598 		return fStatus;
599 
600 	struct sockaddr_in addr;
601 	if (address.GetAddr(addr) != B_OK)
602 		return B_ERROR;
603 
604 	ssize_t	bytesSent = sendto(fSocket, buffer, length, flags,
605 		(struct sockaddr *) &addr, sizeof(addr));
606 	if (bytesSent < 0)
607 		fStatus = errno;
608 
609 	return bytesSent;
610 }
611 
612 
613 int32
614 BNetEndpoint::SendTo(BNetBuffer& buffer,
615 	const BNetAddress& address, int flags)
616 {
617 	return SendTo(buffer.Data(), buffer.Size(), address, flags);
618 }
619 
620 
621 // #pragma mark -
622 
623 
624 status_t
625 BNetEndpoint::_SetupSocket()
626 {
627 	if ((fSocket = socket(fFamily, fType, fProtocol)) < 0)
628 		fStatus = errno;
629 	else
630 		fStatus = B_OK;
631 	return fStatus;
632 }
633 
634 
635 // #pragma mark -
636 
637 status_t BNetEndpoint::InitCheck()
638 {
639 	return const_cast<const BNetEndpoint*>(this)->InitCheck();
640 }
641 
642 
643 const BNetAddress& BNetEndpoint::LocalAddr()
644 {
645 	return const_cast<const BNetEndpoint*>(this)->LocalAddr();
646 }
647 
648 
649 const BNetAddress& BNetEndpoint::RemoteAddr()
650 {
651 	return const_cast<const BNetEndpoint*>(this)->RemoteAddr();
652 }
653 
654 
655 // #pragma mark -
656 
657 
658 // These are virtuals, implemented for binary compatibility purpose
659 void BNetEndpoint::_ReservedBNetEndpointFBCCruft1() {}
660 void BNetEndpoint::_ReservedBNetEndpointFBCCruft2() {}
661 void BNetEndpoint::_ReservedBNetEndpointFBCCruft3() {}
662 void BNetEndpoint::_ReservedBNetEndpointFBCCruft4() {}
663 void BNetEndpoint::_ReservedBNetEndpointFBCCruft5() {}
664 void BNetEndpoint::_ReservedBNetEndpointFBCCruft6() {}
665 
666