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