1// InsecureChannel.cpp
2
3#include <errno.h>
4
5#ifdef HAIKU_TARGET_PLATFORM_BEOS
6#	include <socket.h>
7#else
8#	include <unistd.h>
9#	include <netinet/in.h>
10#	include <sys/socket.h>
11#endif
12
13#include "Compatibility.h"
14#include "DebugSupport.h"
15#include "InsecureChannel.h"
16#include "NetAddress.h"
17#include "Utils.h"
18
19static const int32 kMaxInterruptedTxCount = 20;
20
21// constructor
22InsecureChannel::InsecureChannel(int socket)
23	: Channel(),
24	  fSocket(socket),
25	  fClosed(false)
26{
27	// set socket to blocking (with BONE a connection socket seems to inherit
28	// the non-blocking property of the listener socket)
29	if (fSocket >= 0) {
30		int dontBlock = 0;
31		setsockopt(fSocket, SOL_SOCKET, SO_NONBLOCK, &dontBlock, sizeof(int));
32
33#ifndef HAIKU_TARGET_PLATFORM_BEOS
34		int txLowWater = 1;
35		setsockopt(fSocket, SOL_SOCKET, SO_SNDLOWAT, &txLowWater, sizeof(int));
36		setsockopt(fSocket, SOL_SOCKET, SO_RCVLOWAT, &txLowWater, sizeof(int));
37#endif
38	}
39}
40
41// destructor
42InsecureChannel::~InsecureChannel()
43{
44	Close();
45}
46
47// Close
48void
49InsecureChannel::Close()
50{
51	fClosed = true;
52	safe_closesocket(fSocket);
53}
54
55// Send
56status_t
57InsecureChannel::Send(const void* _buffer, int32 size)
58{
59	if (size == 0)
60		return B_OK;
61	if (!_buffer || size < 0)
62		return B_BAD_VALUE;
63	const uint8* buffer = static_cast<const uint8*>(_buffer);
64	int32 remainingRetries = kMaxInterruptedTxCount;
65	while (size > 0) {
66		int32 bytesSent = send(fSocket, buffer, size, 0);
67		if (bytesSent < 0) {
68			status_t error = errno;
69			if (fClosed || errno != B_INTERRUPTED || --remainingRetries < 0)
70{
71if (!fClosed) {
72PRINT(("InsecureChannel::Send(): B_INTERRUPTED\n"));
73}
74				return error;
75}
76//PRINT(("InsecureChannel::Send: B_INTERRUPTED ignored, remaining retries: %ld\n",
77//remainingRetries));
78			bytesSent = 0;
79		} else if (bytesSent == 0) {
80			// This seems to indicate that the remote peer closed the
81			// connection.
82			PRINT(("Connection::Send(): sent 0 bytes. Assuming "
83				"that the remote peer closed the connection\n"));
84			return B_ERROR;
85		} else {
86			size -= bytesSent;
87			buffer += bytesSent;
88			remainingRetries = kMaxInterruptedTxCount;
89//PRINT(("InsecureChannel::Send(): sent %ld bytes, still to sent: %lu\n",
90//bytesSent, size));
91		}
92	}
93	return B_OK;
94}
95
96// Receive
97status_t
98InsecureChannel::Receive(void* _buffer, int32 size)
99{
100	if (size == 0)
101		return B_OK;
102	if (!_buffer || size < 0)
103		return B_BAD_VALUE;
104	uint8* buffer = static_cast<uint8*>(_buffer);
105	int32 remainingRetries = kMaxInterruptedTxCount;
106	while (size > 0) {
107		int32 bytesRead = recv(fSocket, buffer, size, 0);
108		if (bytesRead < 0) {
109			status_t error = errno;
110			if (fClosed || error != B_INTERRUPTED || --remainingRetries < 0)
111{
112if (!fClosed) {
113PRINT(("InsecureChannel::Receive(): B_INTERRUPTED\n"));
114}
115				return error;
116}
117//PRINT(("InsecureChannel::Receive(): B_INTERRUPTED ignored\n"));
118		} else if (bytesRead == 0) {
119			// This seems to indicate that the remote peer closed the
120			// connection.
121			PRINT(("Connection::Receive(): received 0 bytes. Assuming "
122				"that the remote peer closed the connection\n"));
123			return B_ERROR;
124		} else {
125			size -= bytesRead;
126			buffer += bytesRead;
127			remainingRetries = kMaxInterruptedTxCount;
128//PRINT(("InsecureChannel::Receive(): received %ld bytes, still to read: %lu\n",
129//bytesRead, size));
130		}
131	}
132	return B_OK;
133}
134
135// GetPeerAddress
136status_t
137InsecureChannel::GetPeerAddress(NetAddress *address) const
138{
139	if (!address)
140		return B_BAD_VALUE;
141
142	sockaddr_in addr;
143	socklen_t size = sizeof(sockaddr_in);
144	if (getpeername(fSocket, (sockaddr*)&addr, &size) < 0)
145		return errno;
146	if (addr.sin_family != AF_INET)
147		return B_BAD_VALUE;
148
149	address->SetAddress(addr);
150	return B_OK;
151}
152
153