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
21BNetEndpoint::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
34BNetEndpoint::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
47BNetEndpoint::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
88BNetEndpoint::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().
109BNetEndpoint::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
125BNetEndpoint&
126BNetEndpoint::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
152BNetEndpoint::~BNetEndpoint()
153{
154	if (fSocket >= 0)
155		Close();
156}
157
158
159// #pragma mark -
160
161
162status_t
163BNetEndpoint::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
200BArchivable*
201BNetEndpoint::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
221status_t
222BNetEndpoint::InitCheck() const
223{
224	return fSocket == -1 ? B_NO_INIT : B_OK;
225}
226
227
228int
229BNetEndpoint::Socket() const
230{
231	return fSocket;
232}
233
234
235const BNetAddress&
236BNetEndpoint::LocalAddr() const
237{
238	return fAddr;
239}
240
241
242const BNetAddress&
243BNetEndpoint::RemoteAddr() const
244{
245	return fPeer;
246}
247
248
249status_t
250BNetEndpoint::SetProtocol(int protocol)
251{
252	Close();
253	fType = protocol;	// sic (protocol is SOCK_DGRAM or SOCK_STREAM)
254	return _SetupSocket();
255}
256
257
258int
259BNetEndpoint::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
274int
275BNetEndpoint::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
300int
301BNetEndpoint::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
311void
312BNetEndpoint::SetTimeout(bigtime_t timeout)
313{
314	fTimeout = timeout < 0 ? B_INFINITE_TIMEOUT : timeout;
315}
316
317
318int
319BNetEndpoint::Error() const
320{
321	return (int)fStatus;
322}
323
324
325char*
326BNetEndpoint::ErrorStr() const
327{
328	return strerror(fStatus);
329}
330
331
332// #pragma mark -
333
334
335void
336BNetEndpoint::Close()
337{
338	if (fSocket >= 0)
339		close(fSocket);
340
341	fSocket = -1;
342	fStatus = B_NO_INIT;
343}
344
345
346status_t
347BNetEndpoint::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
375status_t
376BNetEndpoint::Bind(int port)
377{
378	BNetAddress addr(INADDR_ANY, port);
379	return Bind(addr);
380}
381
382
383status_t
384BNetEndpoint::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
410status_t
411BNetEndpoint::Connect(const char *hostname, int port)
412{
413	BNetAddress addr(hostname, port);
414	return Connect(addr);
415}
416
417
418status_t
419BNetEndpoint::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
433BNetEndpoint*
434BNetEndpoint::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
474bool
475BNetEndpoint::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	if (select(fSocket + 1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL) < 0) {
494		fStatus = errno;
495		return false;
496	}
497
498	return FD_ISSET(fSocket, &fds);
499}
500
501
502int32
503BNetEndpoint::Receive(void* buffer, size_t length, int flags)
504{
505	if (fSocket < 0 && _SetupSocket() != B_OK)
506		return fStatus;
507
508	if (fTimeout >= 0 && IsDataPending(fTimeout) == false)
509		return 0;
510
511	ssize_t bytesReceived = recv(fSocket, buffer, length, flags);
512	if (bytesReceived < 0)
513		fStatus = errno;
514
515	return bytesReceived;
516}
517
518
519int32
520BNetEndpoint::Receive(BNetBuffer& buffer, size_t length, int flags)
521{
522	BNetBuffer chunk(length);
523	ssize_t bytesReceived = Receive(chunk.Data(), length, flags);
524	if (bytesReceived > 0)
525		buffer.AppendData(chunk.Data(), bytesReceived);
526	return bytesReceived;
527}
528
529
530int32
531BNetEndpoint::ReceiveFrom(void* buffer, size_t length,
532	BNetAddress& address, int flags)
533{
534	if (fSocket < 0 && _SetupSocket() != B_OK)
535		return fStatus;
536
537	if (fTimeout >= 0 && IsDataPending(fTimeout) == false)
538		return 0;
539
540	struct sockaddr_in addr;
541	socklen_t addrSize = sizeof(addr);
542
543	ssize_t bytesReceived = recvfrom(fSocket, buffer, length, flags,
544		(struct sockaddr *)&addr, &addrSize);
545	if (bytesReceived < 0)
546		fStatus = errno;
547	else
548		address.SetTo(addr);
549
550	return bytesReceived;
551}
552
553
554int32
555BNetEndpoint::ReceiveFrom(BNetBuffer& buffer, size_t length,
556	BNetAddress& address, int flags)
557{
558	BNetBuffer chunk(length);
559	ssize_t bytesReceived = ReceiveFrom(chunk.Data(), length, address, flags);
560	if (bytesReceived > 0)
561		buffer.AppendData(chunk.Data(), bytesReceived);
562	return bytesReceived;
563}
564
565
566int32
567BNetEndpoint::Send(const void* buffer, size_t length, int flags)
568{
569	if (fSocket < 0 && _SetupSocket() != B_OK)
570		return fStatus;
571
572	ssize_t bytesSent = send(fSocket, (const char *) buffer, length, flags);
573	if (bytesSent < 0)
574		fStatus = errno;
575
576	return bytesSent;
577}
578
579
580int32
581BNetEndpoint::Send(BNetBuffer& buffer, int flags)
582{
583	return Send(buffer.Data(), buffer.Size(), flags);
584}
585
586
587int32
588BNetEndpoint::SendTo(const void* buffer, size_t length,
589	const BNetAddress& address, int flags)
590{
591	if (fSocket < 0 && _SetupSocket() != B_OK)
592		return fStatus;
593
594	struct sockaddr_in addr;
595	if (address.GetAddr(addr) != B_OK)
596		return B_ERROR;
597
598	ssize_t	bytesSent = sendto(fSocket, buffer, length, flags,
599		(struct sockaddr *) &addr, sizeof(addr));
600	if (bytesSent < 0)
601		fStatus = errno;
602
603	return bytesSent;
604}
605
606
607int32
608BNetEndpoint::SendTo(BNetBuffer& buffer,
609	const BNetAddress& address, int flags)
610{
611	return SendTo(buffer.Data(), buffer.Size(), address, flags);
612}
613
614
615// #pragma mark -
616
617
618status_t
619BNetEndpoint::_SetupSocket()
620{
621	if ((fSocket = socket(fFamily, fType, fProtocol)) < 0)
622		fStatus = errno;
623	else
624		fStatus = B_OK;
625	return fStatus;
626}
627
628
629// #pragma mark -
630
631status_t BNetEndpoint::InitCheck()
632{
633	return const_cast<const BNetEndpoint*>(this)->InitCheck();
634}
635
636
637const BNetAddress& BNetEndpoint::LocalAddr()
638{
639	return const_cast<const BNetEndpoint*>(this)->LocalAddr();
640}
641
642
643const BNetAddress& BNetEndpoint::RemoteAddr()
644{
645	return const_cast<const BNetEndpoint*>(this)->RemoteAddr();
646}
647
648
649// #pragma mark -
650
651
652// These are virtuals, implemented for binary compatibility purpose
653void BNetEndpoint::_ReservedBNetEndpointFBCCruft1() {}
654void BNetEndpoint::_ReservedBNetEndpointFBCCruft2() {}
655void BNetEndpoint::_ReservedBNetEndpointFBCCruft3() {}
656void BNetEndpoint::_ReservedBNetEndpointFBCCruft4() {}
657void BNetEndpoint::_ReservedBNetEndpointFBCCruft5() {}
658void BNetEndpoint::_ReservedBNetEndpointFBCCruft6() {}
659
660