xref: /haiku/src/add-ons/kernel/file_systems/netfs/shared/InsecureChannel.cpp (revision 99d027cd0238c1d86da86d7c3f4200509ccc61a6)
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 
19 static const int32 kMaxInterruptedTxCount = 20;
20 
21 // constructor
22 InsecureChannel::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
42 InsecureChannel::~InsecureChannel()
43 {
44 	Close();
45 }
46 
47 // Close
48 void
49 InsecureChannel::Close()
50 {
51 	fClosed = true;
52 	safe_closesocket(fSocket);
53 }
54 
55 // Send
56 status_t
57 InsecureChannel::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 {
71 if (!fClosed) {
72 PRINT(("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
97 status_t
98 InsecureChannel::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 {
112 if (!fClosed) {
113 PRINT(("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
136 status_t
137 InsecureChannel::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