xref: /haiku/src/kits/network/libnetapi/NetEndpoint.cpp (revision 83b1a68c52ba3e0e8796282759f694b7fdddf06d)
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;
315 	// TODO: Map value < 0 to B_INFINITE_TIMEOUT or use -1 by default.
316 }
317 
318 
319 int
320 BNetEndpoint::Error() const
321 {
322 	return (int)fStatus;
323 }
324 
325 
326 char*
327 BNetEndpoint::ErrorStr() const
328 {
329 	return strerror(fStatus);
330 }
331 
332 
333 // #pragma mark -
334 
335 
336 void
337 BNetEndpoint::Close()
338 {
339 	if (fSocket >= 0)
340 		close(fSocket);
341 
342 	fSocket = -1;
343 	fStatus = B_NO_INIT;
344 }
345 
346 
347 status_t
348 BNetEndpoint::Bind(const BNetAddress& address)
349 {
350 	if (fSocket < 0 && _SetupSocket() != B_OK)
351 		return fStatus;
352 
353 	struct sockaddr_in addr;
354 	status_t status = address.GetAddr(addr);
355 	if (status != B_OK)
356 		return status;
357 
358 	if (bind(fSocket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
359 		fStatus = errno;
360 		Close();
361 		return B_ERROR;
362 	}
363 
364 	socklen_t addrSize = sizeof(addr);
365 	if (getsockname(fSocket, (struct sockaddr *)&addr, &addrSize) < 0) {
366 		fStatus = errno;
367 		Close();
368 		return B_ERROR;
369 	}
370 
371 	fAddr.SetTo(addr);
372 	return B_OK;
373 }
374 
375 
376 status_t
377 BNetEndpoint::Bind(int port)
378 {
379 	BNetAddress addr(INADDR_ANY, port);
380 	return Bind(addr);
381 }
382 
383 
384 status_t
385 BNetEndpoint::Connect(const BNetAddress& address)
386 {
387 	if (fSocket < 0 && _SetupSocket() != B_OK)
388 		return fStatus;
389 
390 	sockaddr_in addr;
391 	if (address.GetAddr(addr) != B_OK)
392 		return B_ERROR;
393 
394 	if (connect(fSocket, (sockaddr *) &addr, sizeof(addr)) < 0) {
395 		Close();
396 		fStatus = errno;
397 		return B_ERROR;
398 	}
399 
400 	socklen_t addrSize = sizeof(addr);
401 	if (getpeername(fSocket, (sockaddr *) &addr, &addrSize) < 0) {
402 		Close();
403 		fStatus = errno;
404 		return B_ERROR;
405 	}
406 	fPeer.SetTo(addr);
407 	return B_OK;
408 }
409 
410 
411 status_t
412 BNetEndpoint::Connect(const char *hostname, int port)
413 {
414 	BNetAddress addr(hostname, port);
415 	return Connect(addr);
416 }
417 
418 
419 status_t
420 BNetEndpoint::Listen(int backlog)
421 {
422 	if (fSocket < 0 && _SetupSocket() != B_OK)
423 		return fStatus;
424 
425 	if (listen(fSocket, backlog) < 0) {
426 		Close();
427 		fStatus = errno;
428 		return B_ERROR;
429 	}
430 	return B_OK;
431 }
432 
433 
434 BNetEndpoint*
435 BNetEndpoint::Accept(int32 timeout)
436 {
437 	// TODO: IsDataPending() expects 0 as special value for infinite timeout,
438 	// hence the following call is broken for timeout < 0 and timeout == 0.
439 	if (!IsDataPending(timeout < 0 ? B_INFINITE_TIMEOUT : 1000LL * timeout))
440 		return NULL;
441 
442 	struct sockaddr_in peerAddress;
443 	socklen_t peerAddressSize = sizeof(peerAddress);
444 
445 	int socket
446 		= accept(fSocket, (struct sockaddr *)&peerAddress, &peerAddressSize);
447 	if (socket < 0) {
448 		Close();
449 		fStatus = errno;
450 		return NULL;
451 	}
452 
453 	struct sockaddr_in localAddress;
454 	socklen_t localAddressSize = sizeof(localAddress);
455 	if (getsockname(socket, (struct sockaddr *)&localAddress,
456 			&localAddressSize) < 0) {
457 		close(socket);
458 		fStatus = errno;
459 		return NULL;
460 	}
461 
462 	BNetEndpoint* endpoint = new (std::nothrow) BNetEndpoint(*this, socket,
463 		localAddress, peerAddress);
464 	if (endpoint == NULL) {
465 		close(socket);
466 		fStatus = B_NO_MEMORY;
467 		return NULL;
468 	}
469 
470 	return endpoint;
471 }
472 
473 
474 // #pragma mark -
475 
476 
477 bool
478 BNetEndpoint::IsDataPending(bigtime_t timeout)
479 {
480 	struct timeval tv;
481 	fd_set fds;
482 
483 	FD_ZERO(&fds);
484 	FD_SET(fSocket, &fds);
485 
486 	if (timeout > 0) {
487 		tv.tv_sec = timeout / 1000000;
488 			// TODO: A big value (e.g. B_INFINITE_TIMEOUT) will overflow!
489 		tv.tv_usec = (timeout % 1000000);
490 	}
491 
492 	if (select(fSocket + 1, &fds, NULL, NULL, timeout > 0 ? &tv : NULL) < 0) {
493 		fStatus = errno;
494 		return false;
495 	}
496 
497 	return FD_ISSET(fSocket, &fds);
498 }
499 
500 
501 int32
502 BNetEndpoint::Receive(void* buffer, size_t length, int flags)
503 {
504 	if (fSocket < 0 && _SetupSocket() != B_OK)
505 		return fStatus;
506 
507 	// TODO: For fTimeout == 0 this is broken as IsDataPending(0) means wait
508 	// without timeout. Furthermore the default fTimeout is B_INFINITE_TIMEOUT.
509 	if (fTimeout >= 0 && IsDataPending(fTimeout) == false)
510 		return 0;
511 
512 	ssize_t bytesReceived = recv(fSocket, buffer, length, flags);
513 	if (bytesReceived < 0)
514 		fStatus = errno;
515 
516 	return bytesReceived;
517 }
518 
519 
520 int32
521 BNetEndpoint::Receive(BNetBuffer& buffer, size_t length, int flags)
522 {
523 	BNetBuffer chunk(length);
524 	ssize_t bytesReceived = Receive(chunk.Data(), length, flags);
525 	if (bytesReceived > 0)
526 		buffer.AppendData(chunk.Data(), bytesReceived);
527 	return bytesReceived;
528 }
529 
530 
531 int32
532 BNetEndpoint::ReceiveFrom(void* buffer, size_t length,
533 	BNetAddress& address, int flags)
534 {
535 	if (fSocket < 0 && _SetupSocket() != B_OK)
536 		return fStatus;
537 
538 	// TODO: For fTimeout == 0 this is broken as IsDataPending(0) means wait
539 	// without timeout. Furthermore the default fTimeout is B_INFINITE_TIMEOUT.
540 	if (fTimeout >= 0 && IsDataPending(fTimeout) == false)
541 		return 0;
542 
543 	struct sockaddr_in addr;
544 	socklen_t addrSize = sizeof(addr);
545 
546 	ssize_t bytesReceived = recvfrom(fSocket, buffer, length, flags,
547 		(struct sockaddr *)&addr, &addrSize);
548 	if (bytesReceived < 0)
549 		fStatus = errno;
550 	else
551 		address.SetTo(addr);
552 
553 	return bytesReceived;
554 }
555 
556 
557 int32
558 BNetEndpoint::ReceiveFrom(BNetBuffer& buffer, size_t length,
559 	BNetAddress& address, int flags)
560 {
561 	BNetBuffer chunk(length);
562 	ssize_t bytesReceived = ReceiveFrom(chunk.Data(), length, address, flags);
563 	if (bytesReceived > 0)
564 		buffer.AppendData(chunk.Data(), bytesReceived);
565 	return bytesReceived;
566 }
567 
568 
569 int32
570 BNetEndpoint::Send(const void* buffer, size_t length, int flags)
571 {
572 	if (fSocket < 0 && _SetupSocket() != B_OK)
573 		return fStatus;
574 
575 	ssize_t bytesSent = send(fSocket, (const char *) buffer, length, flags);
576 	if (bytesSent < 0)
577 		fStatus = errno;
578 
579 	return bytesSent;
580 }
581 
582 
583 int32
584 BNetEndpoint::Send(BNetBuffer& buffer, int flags)
585 {
586 	return Send(buffer.Data(), buffer.Size(), flags);
587 }
588 
589 
590 int32
591 BNetEndpoint::SendTo(const void* buffer, size_t length,
592 	const BNetAddress& address, int flags)
593 {
594 	if (fSocket < 0 && _SetupSocket() != B_OK)
595 		return fStatus;
596 
597 	struct sockaddr_in addr;
598 	if (address.GetAddr(addr) != B_OK)
599 		return B_ERROR;
600 
601 	ssize_t	bytesSent = sendto(fSocket, buffer, length, flags,
602 		(struct sockaddr *) &addr, sizeof(addr));
603 	if (bytesSent < 0)
604 		fStatus = errno;
605 
606 	return bytesSent;
607 }
608 
609 
610 int32
611 BNetEndpoint::SendTo(BNetBuffer& buffer,
612 	const BNetAddress& address, int flags)
613 {
614 	return SendTo(buffer.Data(), buffer.Size(), address, flags);
615 }
616 
617 
618 // #pragma mark -
619 
620 
621 status_t
622 BNetEndpoint::_SetupSocket()
623 {
624 	if ((fSocket = socket(fFamily, fType, fProtocol)) < 0)
625 		fStatus = errno;
626 	else
627 		fStatus = B_OK;
628 	return fStatus;
629 }
630 
631 
632 // #pragma mark -
633 
634 status_t BNetEndpoint::InitCheck()
635 {
636 	return const_cast<const BNetEndpoint*>(this)->InitCheck();
637 }
638 
639 
640 const BNetAddress& BNetEndpoint::LocalAddr()
641 {
642 	return const_cast<const BNetEndpoint*>(this)->LocalAddr();
643 }
644 
645 
646 const BNetAddress& BNetEndpoint::RemoteAddr()
647 {
648 	return const_cast<const BNetEndpoint*>(this)->RemoteAddr();
649 }
650 
651 
652 // #pragma mark -
653 
654 
655 // These are virtuals, implemented for binary compatibility purpose
656 void BNetEndpoint::_ReservedBNetEndpointFBCCruft1() {}
657 void BNetEndpoint::_ReservedBNetEndpointFBCCruft2() {}
658 void BNetEndpoint::_ReservedBNetEndpointFBCCruft3() {}
659 void BNetEndpoint::_ReservedBNetEndpointFBCCruft4() {}
660 void BNetEndpoint::_ReservedBNetEndpointFBCCruft5() {}
661 void BNetEndpoint::_ReservedBNetEndpointFBCCruft6() {}
662 
663