15a1d355fSStephan Aßmus // InsecureConnection.cpp
25a1d355fSStephan Aßmus
35a1d355fSStephan Aßmus // TODO: Asynchronous connecting on client side?
45a1d355fSStephan Aßmus
55a1d355fSStephan Aßmus #include <new>
65a1d355fSStephan Aßmus
75a1d355fSStephan Aßmus #include <errno.h>
85a1d355fSStephan Aßmus #include <netdb.h>
95a1d355fSStephan Aßmus #include <stdio.h>
105a1d355fSStephan Aßmus #include <string.h>
115a1d355fSStephan Aßmus #include <unistd.h>
125a1d355fSStephan Aßmus
135a1d355fSStephan Aßmus #include <ByteOrder.h>
145a1d355fSStephan Aßmus
155a1d355fSStephan Aßmus #include "Compatibility.h"
165a1d355fSStephan Aßmus #include "DebugSupport.h"
175a1d355fSStephan Aßmus #include "InsecureChannel.h"
185a1d355fSStephan Aßmus #include "InsecureConnection.h"
195a1d355fSStephan Aßmus #include "NetAddress.h"
205a1d355fSStephan Aßmus #include "NetFSDefs.h"
215a1d355fSStephan Aßmus
225a1d355fSStephan Aßmus namespace InsecureConnectionDefs {
235a1d355fSStephan Aßmus
245a1d355fSStephan Aßmus const int32 kProtocolVersion = 1;
255a1d355fSStephan Aßmus
265a1d355fSStephan Aßmus const bigtime_t kAcceptingTimeout = 10000000; // 10 s
275a1d355fSStephan Aßmus
285a1d355fSStephan Aßmus // number of client up/down stream channels
295a1d355fSStephan Aßmus const int32 kMinUpStreamChannels = 1;
305a1d355fSStephan Aßmus const int32 kMaxUpStreamChannels = 10;
315a1d355fSStephan Aßmus const int32 kDefaultUpStreamChannels = 5;
325a1d355fSStephan Aßmus const int32 kMinDownStreamChannels = 1;
335a1d355fSStephan Aßmus const int32 kMaxDownStreamChannels = 5;
345a1d355fSStephan Aßmus const int32 kDefaultDownStreamChannels = 1;
355a1d355fSStephan Aßmus
365a1d355fSStephan Aßmus } // namespace InsecureConnectionDefs
375a1d355fSStephan Aßmus
385a1d355fSStephan Aßmus using namespace InsecureConnectionDefs;
395a1d355fSStephan Aßmus
405a1d355fSStephan Aßmus // SocketCloser
415a1d355fSStephan Aßmus struct SocketCloser {
SocketCloserSocketCloser425a1d355fSStephan Aßmus SocketCloser(int fd) : fFD(fd) {}
~SocketCloserSocketCloser435a1d355fSStephan Aßmus ~SocketCloser()
445a1d355fSStephan Aßmus {
455a1d355fSStephan Aßmus if (fFD >= 0)
465a1d355fSStephan Aßmus closesocket(fFD);
475a1d355fSStephan Aßmus }
485a1d355fSStephan Aßmus
DetachSocketCloser495a1d355fSStephan Aßmus int Detach()
505a1d355fSStephan Aßmus {
515a1d355fSStephan Aßmus int fd = fFD;
525a1d355fSStephan Aßmus fFD = -1;
535a1d355fSStephan Aßmus return fd;
545a1d355fSStephan Aßmus }
555a1d355fSStephan Aßmus
565a1d355fSStephan Aßmus private:
575a1d355fSStephan Aßmus int fFD;
585a1d355fSStephan Aßmus };
595a1d355fSStephan Aßmus
605a1d355fSStephan Aßmus
615a1d355fSStephan Aßmus // #pragma mark -
625a1d355fSStephan Aßmus // #pragma mark ----- InsecureConnection -----
635a1d355fSStephan Aßmus
645a1d355fSStephan Aßmus // constructor
InsecureConnection()655a1d355fSStephan Aßmus InsecureConnection::InsecureConnection()
665a1d355fSStephan Aßmus {
675a1d355fSStephan Aßmus }
685a1d355fSStephan Aßmus
695a1d355fSStephan Aßmus // destructor
~InsecureConnection()705a1d355fSStephan Aßmus InsecureConnection::~InsecureConnection()
715a1d355fSStephan Aßmus {
725a1d355fSStephan Aßmus }
735a1d355fSStephan Aßmus
745a1d355fSStephan Aßmus // Init (server side)
755a1d355fSStephan Aßmus status_t
Init(int fd)765a1d355fSStephan Aßmus InsecureConnection::Init(int fd)
775a1d355fSStephan Aßmus {
785a1d355fSStephan Aßmus status_t error = AbstractConnection::Init();
795a1d355fSStephan Aßmus if (error != B_OK) {
805a1d355fSStephan Aßmus closesocket(fd);
815a1d355fSStephan Aßmus return error;
825a1d355fSStephan Aßmus }
835a1d355fSStephan Aßmus // create the initial channel
845a1d355fSStephan Aßmus Channel* channel = new(std::nothrow) InsecureChannel(fd);
855a1d355fSStephan Aßmus if (!channel) {
865a1d355fSStephan Aßmus closesocket(fd);
875a1d355fSStephan Aßmus return B_NO_MEMORY;
885a1d355fSStephan Aßmus }
895a1d355fSStephan Aßmus // add it
905a1d355fSStephan Aßmus error = AddDownStreamChannel(channel);
915a1d355fSStephan Aßmus if (error != B_OK) {
925a1d355fSStephan Aßmus delete channel;
935a1d355fSStephan Aßmus return error;
945a1d355fSStephan Aßmus }
955a1d355fSStephan Aßmus return B_OK;
965a1d355fSStephan Aßmus }
975a1d355fSStephan Aßmus
985a1d355fSStephan Aßmus // Init (client side)
995a1d355fSStephan Aßmus status_t
Init(const char * parameters)1005a1d355fSStephan Aßmus InsecureConnection::Init(const char* parameters)
1015a1d355fSStephan Aßmus {
1025a1d355fSStephan Aßmus PRINT(("InsecureConnection::Init\n"));
1035a1d355fSStephan Aßmus if (!parameters)
1045a1d355fSStephan Aßmus return B_BAD_VALUE;
1055a1d355fSStephan Aßmus status_t error = AbstractConnection::Init();
1065a1d355fSStephan Aßmus if (error != B_OK)
1075a1d355fSStephan Aßmus return error;
1085a1d355fSStephan Aßmus // parse the parameters to get a server name and a port we shall connect to
1095a1d355fSStephan Aßmus // parameter format is "<server>[:port] [ <up> [ <down> ] ]"
1105a1d355fSStephan Aßmus char server[256];
1115a1d355fSStephan Aßmus uint16 port = kDefaultInsecureConnectionPort;
1125a1d355fSStephan Aßmus int upStreamChannels = kDefaultUpStreamChannels;
1135a1d355fSStephan Aßmus int downStreamChannels = kDefaultDownStreamChannels;
1145a1d355fSStephan Aßmus if (strchr(parameters, ':')) {
1155a1d355fSStephan Aßmus int result = sscanf(parameters, "%255[^:]:%hu %d %d", server, &port,
1165a1d355fSStephan Aßmus &upStreamChannels, &downStreamChannels);
1175a1d355fSStephan Aßmus if (result < 2)
1185a1d355fSStephan Aßmus return B_BAD_VALUE;
1195a1d355fSStephan Aßmus } else {
1205a1d355fSStephan Aßmus int result = sscanf(parameters, "%255[^:] %d %d", server,
1215a1d355fSStephan Aßmus &upStreamChannels, &downStreamChannels);
1225a1d355fSStephan Aßmus if (result < 1)
1235a1d355fSStephan Aßmus return B_BAD_VALUE;
1245a1d355fSStephan Aßmus }
1255a1d355fSStephan Aßmus // resolve server address
1265a1d355fSStephan Aßmus NetAddress netAddress;
1275a1d355fSStephan Aßmus error = NetAddressResolver().GetHostAddress(server, &netAddress);
1285a1d355fSStephan Aßmus if (error != B_OK)
1295a1d355fSStephan Aßmus return error;
1305a1d355fSStephan Aßmus in_addr serverAddr = netAddress.GetAddress().sin_addr;
1315a1d355fSStephan Aßmus // open the initial channel
1325a1d355fSStephan Aßmus Channel* channel;
1335a1d355fSStephan Aßmus error = _OpenClientChannel(serverAddr, port, &channel);
1345a1d355fSStephan Aßmus if (error != B_OK)
1355a1d355fSStephan Aßmus return error;
1365a1d355fSStephan Aßmus error = AddUpStreamChannel(channel);
1375a1d355fSStephan Aßmus if (error != B_OK) {
1385a1d355fSStephan Aßmus delete channel;
1395a1d355fSStephan Aßmus return error;
1405a1d355fSStephan Aßmus }
1415a1d355fSStephan Aßmus // send the server a connect request
1425a1d355fSStephan Aßmus ConnectRequest request;
1435a1d355fSStephan Aßmus request.protocolVersion = B_HOST_TO_BENDIAN_INT32(kProtocolVersion);
1445a1d355fSStephan Aßmus request.serverAddress = serverAddr.s_addr;
1455a1d355fSStephan Aßmus request.upStreamChannels = B_HOST_TO_BENDIAN_INT32(upStreamChannels);
1465a1d355fSStephan Aßmus request.downStreamChannels = B_HOST_TO_BENDIAN_INT32(downStreamChannels);
1475a1d355fSStephan Aßmus error = channel->Send(&request, sizeof(ConnectRequest));
1485a1d355fSStephan Aßmus if (error != B_OK)
1495a1d355fSStephan Aßmus return error;
1505a1d355fSStephan Aßmus // get the server reply
1515a1d355fSStephan Aßmus ConnectReply reply;
1525a1d355fSStephan Aßmus error = channel->Receive(&reply, sizeof(ConnectReply));
1535a1d355fSStephan Aßmus if (error != B_OK)
1545a1d355fSStephan Aßmus return error;
1555a1d355fSStephan Aßmus error = B_BENDIAN_TO_HOST_INT32(reply.error);
1565a1d355fSStephan Aßmus if (error != B_OK)
1575a1d355fSStephan Aßmus return error;
1585a1d355fSStephan Aßmus upStreamChannels = B_BENDIAN_TO_HOST_INT32(reply.upStreamChannels);
1595a1d355fSStephan Aßmus downStreamChannels = B_BENDIAN_TO_HOST_INT32(reply.downStreamChannels);
1605a1d355fSStephan Aßmus port = B_BENDIAN_TO_HOST_INT16(reply.port);
1615a1d355fSStephan Aßmus // open the remaining channels
1625a1d355fSStephan Aßmus int32 allChannels = upStreamChannels + downStreamChannels;
1635a1d355fSStephan Aßmus for (int32 i = 1; i < allChannels; i++) {
164*ebb21bd1SMurai Takashi PRINT(" creating channel %" B_PRId32 "\n", i);
1655a1d355fSStephan Aßmus // open the channel
1665a1d355fSStephan Aßmus error = _OpenClientChannel(serverAddr, port, &channel);
1675a1d355fSStephan Aßmus if (error != B_OK)
1685a1d355fSStephan Aßmus RETURN_ERROR(error);
1695a1d355fSStephan Aßmus // add it
1705a1d355fSStephan Aßmus if (i < upStreamChannels)
1715a1d355fSStephan Aßmus error = AddUpStreamChannel(channel);
1725a1d355fSStephan Aßmus else
1735a1d355fSStephan Aßmus error = AddDownStreamChannel(channel);
1745a1d355fSStephan Aßmus if (error != B_OK) {
1755a1d355fSStephan Aßmus delete channel;
1765a1d355fSStephan Aßmus return error;
1775a1d355fSStephan Aßmus }
1785a1d355fSStephan Aßmus }
1795a1d355fSStephan Aßmus return B_OK;
1805a1d355fSStephan Aßmus }
1815a1d355fSStephan Aßmus
1825a1d355fSStephan Aßmus // FinishInitialization
1835a1d355fSStephan Aßmus status_t
FinishInitialization()1845a1d355fSStephan Aßmus InsecureConnection::FinishInitialization()
1855a1d355fSStephan Aßmus {
1865a1d355fSStephan Aßmus PRINT(("InsecureConnection::FinishInitialization()\n"));
1875a1d355fSStephan Aßmus // get the down stream channel
1885a1d355fSStephan Aßmus InsecureChannel* channel
1895a1d355fSStephan Aßmus = dynamic_cast<InsecureChannel*>(DownStreamChannelAt(0));
1905a1d355fSStephan Aßmus if (!channel)
1915a1d355fSStephan Aßmus return B_BAD_VALUE;
1925a1d355fSStephan Aßmus // receive the connect request
1935a1d355fSStephan Aßmus ConnectRequest request;
1945a1d355fSStephan Aßmus status_t error = channel->Receive(&request, sizeof(ConnectRequest));
1955a1d355fSStephan Aßmus if (error != B_OK)
1965a1d355fSStephan Aßmus return error;
1975a1d355fSStephan Aßmus // check the protocol version
1985a1d355fSStephan Aßmus int32 protocolVersion = B_BENDIAN_TO_HOST_INT32(request.protocolVersion);
1995a1d355fSStephan Aßmus if (protocolVersion != kProtocolVersion) {
2005a1d355fSStephan Aßmus _SendErrorReply(channel, B_ERROR);
2015a1d355fSStephan Aßmus return B_ERROR;
2025a1d355fSStephan Aßmus }
2035a1d355fSStephan Aßmus // get our address (we need it for binding)
2045a1d355fSStephan Aßmus in_addr serverAddr;
2055a1d355fSStephan Aßmus serverAddr.s_addr = request.serverAddress;
2065a1d355fSStephan Aßmus // check number of up and down stream channels
2075a1d355fSStephan Aßmus int32 upStreamChannels = B_BENDIAN_TO_HOST_INT32(request.upStreamChannels);
2085a1d355fSStephan Aßmus int32 downStreamChannels = B_BENDIAN_TO_HOST_INT32(
2095a1d355fSStephan Aßmus request.downStreamChannels);
2105a1d355fSStephan Aßmus if (upStreamChannels < kMinUpStreamChannels)
2115a1d355fSStephan Aßmus upStreamChannels = kMinUpStreamChannels;
2125a1d355fSStephan Aßmus else if (upStreamChannels > kMaxUpStreamChannels)
2135a1d355fSStephan Aßmus upStreamChannels = kMaxUpStreamChannels;
2145a1d355fSStephan Aßmus if (downStreamChannels < kMinDownStreamChannels)
2155a1d355fSStephan Aßmus downStreamChannels = kMinDownStreamChannels;
2165a1d355fSStephan Aßmus else if (downStreamChannels > kMaxDownStreamChannels)
2175a1d355fSStephan Aßmus downStreamChannels = kMaxDownStreamChannels;
2185a1d355fSStephan Aßmus // due to a bug on BONE we have a maximum of 2 working connections
2195a1d355fSStephan Aßmus // accepted on one listener socket.
2205a1d355fSStephan Aßmus NetAddress peerAddress;
2215a1d355fSStephan Aßmus if (channel->GetPeerAddress(&peerAddress) == B_OK
2225a1d355fSStephan Aßmus && peerAddress.IsLocal()) {
2235a1d355fSStephan Aßmus upStreamChannels = 1;
2245a1d355fSStephan Aßmus if (downStreamChannels > 2)
2255a1d355fSStephan Aßmus downStreamChannels = 2;
2265a1d355fSStephan Aßmus }
2275a1d355fSStephan Aßmus int32 allChannels = upStreamChannels + downStreamChannels;
2285a1d355fSStephan Aßmus // create a listener socket
2295a1d355fSStephan Aßmus int fd = socket(AF_INET, SOCK_STREAM, 0);
2305a1d355fSStephan Aßmus if (fd < 0) {
2315a1d355fSStephan Aßmus error = errno;
2325a1d355fSStephan Aßmus _SendErrorReply(channel, error);
2335a1d355fSStephan Aßmus return error;
2345a1d355fSStephan Aßmus }
2355a1d355fSStephan Aßmus SocketCloser _(fd);
2365a1d355fSStephan Aßmus // bind it to some port
2375a1d355fSStephan Aßmus sockaddr_in addr;
2385a1d355fSStephan Aßmus addr.sin_family = AF_INET;
2395a1d355fSStephan Aßmus addr.sin_port = 0;
2405a1d355fSStephan Aßmus addr.sin_addr = serverAddr;
2415a1d355fSStephan Aßmus if (bind(fd, (sockaddr*)&addr, sizeof(addr)) < 0) {
2425a1d355fSStephan Aßmus error = errno;
2435a1d355fSStephan Aßmus _SendErrorReply(channel, error);
2445a1d355fSStephan Aßmus return error;
2455a1d355fSStephan Aßmus }
2465a1d355fSStephan Aßmus // get the port
2475a1d355fSStephan Aßmus socklen_t addrSize = sizeof(addr);
2485a1d355fSStephan Aßmus if (getsockname(fd, (sockaddr*)&addr, &addrSize) < 0) {
2495a1d355fSStephan Aßmus error = errno;
2505a1d355fSStephan Aßmus _SendErrorReply(channel, error);
2515a1d355fSStephan Aßmus return error;
2525a1d355fSStephan Aßmus }
2535a1d355fSStephan Aßmus // set socket to non-blocking
2545a1d355fSStephan Aßmus int dontBlock = 1;
2555a1d355fSStephan Aßmus if (setsockopt(fd, SOL_SOCKET, SO_NONBLOCK, &dontBlock, sizeof(int)) < 0) {
2565a1d355fSStephan Aßmus error = errno;
2575a1d355fSStephan Aßmus _SendErrorReply(channel, error);
2585a1d355fSStephan Aßmus return error;
2595a1d355fSStephan Aßmus }
2605a1d355fSStephan Aßmus // start listening
2615a1d355fSStephan Aßmus if (listen(fd, allChannels - 1) < 0) {
2625a1d355fSStephan Aßmus error = errno;
2635a1d355fSStephan Aßmus _SendErrorReply(channel, error);
2645a1d355fSStephan Aßmus return error;
2655a1d355fSStephan Aßmus }
2665a1d355fSStephan Aßmus // send the reply
2675a1d355fSStephan Aßmus ConnectReply reply;
2685a1d355fSStephan Aßmus reply.error = B_HOST_TO_BENDIAN_INT32(B_OK);
2695a1d355fSStephan Aßmus reply.upStreamChannels = B_HOST_TO_BENDIAN_INT32(upStreamChannels);
2705a1d355fSStephan Aßmus reply.downStreamChannels = B_HOST_TO_BENDIAN_INT32(downStreamChannels);
2715a1d355fSStephan Aßmus reply.port = addr.sin_port;
2725a1d355fSStephan Aßmus error = channel->Send(&reply, sizeof(ConnectReply));
2735a1d355fSStephan Aßmus if (error != B_OK)
2745a1d355fSStephan Aßmus return error;
2755a1d355fSStephan Aßmus // start accepting
2765a1d355fSStephan Aßmus bigtime_t startAccepting = system_time();
2775a1d355fSStephan Aßmus for (int32 i = 1; i < allChannels; ) {
2785a1d355fSStephan Aßmus // accept a connection
2795a1d355fSStephan Aßmus int channelFD = accept(fd, NULL, 0);
2805a1d355fSStephan Aßmus if (channelFD < 0) {
2815a1d355fSStephan Aßmus error = errno;
2825a1d355fSStephan Aßmus if (error == B_INTERRUPTED) {
2835a1d355fSStephan Aßmus error = B_OK;
2845a1d355fSStephan Aßmus continue;
2855a1d355fSStephan Aßmus }
2865a1d355fSStephan Aßmus if (error == B_WOULD_BLOCK) {
2875a1d355fSStephan Aßmus bigtime_t now = system_time();
2885a1d355fSStephan Aßmus if (now - startAccepting > kAcceptingTimeout)
2895a1d355fSStephan Aßmus RETURN_ERROR(B_TIMED_OUT);
2905a1d355fSStephan Aßmus snooze(10000);
2915a1d355fSStephan Aßmus continue;
2925a1d355fSStephan Aßmus }
2935a1d355fSStephan Aßmus RETURN_ERROR(error);
2945a1d355fSStephan Aßmus }
295*ebb21bd1SMurai Takashi PRINT(" accepting channel %" B_PRId32 "\n", i);
2965a1d355fSStephan Aßmus // create a channel
2975a1d355fSStephan Aßmus channel = new(std::nothrow) InsecureChannel(channelFD);
2985a1d355fSStephan Aßmus if (!channel) {
2995a1d355fSStephan Aßmus closesocket(channelFD);
3005a1d355fSStephan Aßmus return B_NO_MEMORY;
3015a1d355fSStephan Aßmus }
3025a1d355fSStephan Aßmus // add it
3035a1d355fSStephan Aßmus if (i < upStreamChannels) // inverse, since we are on server side
3045a1d355fSStephan Aßmus error = AddDownStreamChannel(channel);
3055a1d355fSStephan Aßmus else
3065a1d355fSStephan Aßmus error = AddUpStreamChannel(channel);
3075a1d355fSStephan Aßmus if (error != B_OK) {
3085a1d355fSStephan Aßmus delete channel;
3095a1d355fSStephan Aßmus return error;
3105a1d355fSStephan Aßmus }
3115a1d355fSStephan Aßmus i++;
3125a1d355fSStephan Aßmus startAccepting = system_time();
3135a1d355fSStephan Aßmus }
3145a1d355fSStephan Aßmus return B_OK;
3155a1d355fSStephan Aßmus }
3165a1d355fSStephan Aßmus
3175a1d355fSStephan Aßmus // _OpenClientChannel
3185a1d355fSStephan Aßmus status_t
_OpenClientChannel(in_addr serverAddr,uint16 port,Channel ** _channel)3195a1d355fSStephan Aßmus InsecureConnection::_OpenClientChannel(in_addr serverAddr, uint16 port,
3205a1d355fSStephan Aßmus Channel** _channel)
3215a1d355fSStephan Aßmus {
3225a1d355fSStephan Aßmus // create a socket
3235a1d355fSStephan Aßmus int fd = socket(AF_INET, SOCK_STREAM, 0);
3245a1d355fSStephan Aßmus if (fd < 0)
3255a1d355fSStephan Aßmus return errno;
3265a1d355fSStephan Aßmus // connect
3275a1d355fSStephan Aßmus sockaddr_in addr;
3285a1d355fSStephan Aßmus addr.sin_family = AF_INET;
3295a1d355fSStephan Aßmus addr.sin_port = htons(port);
3305a1d355fSStephan Aßmus addr.sin_addr = serverAddr;
3315a1d355fSStephan Aßmus if (connect(fd, (sockaddr*)&addr, sizeof(addr)) < 0) {
3325a1d355fSStephan Aßmus status_t error = errno;
3335a1d355fSStephan Aßmus closesocket(fd);
3345a1d355fSStephan Aßmus RETURN_ERROR(error);
3355a1d355fSStephan Aßmus }
3365a1d355fSStephan Aßmus // create the channel
3375a1d355fSStephan Aßmus Channel* channel = new(std::nothrow) InsecureChannel(fd);
3385a1d355fSStephan Aßmus if (!channel) {
3395a1d355fSStephan Aßmus closesocket(fd);
3405a1d355fSStephan Aßmus return B_NO_MEMORY;
3415a1d355fSStephan Aßmus }
3425a1d355fSStephan Aßmus *_channel = channel;
3435a1d355fSStephan Aßmus return B_OK;
3445a1d355fSStephan Aßmus }
3455a1d355fSStephan Aßmus
3465a1d355fSStephan Aßmus // _SendErrorReply
3475a1d355fSStephan Aßmus status_t
_SendErrorReply(Channel * channel,status_t error)3485a1d355fSStephan Aßmus InsecureConnection::_SendErrorReply(Channel* channel, status_t error)
3495a1d355fSStephan Aßmus {
3505a1d355fSStephan Aßmus ConnectReply reply;
3515a1d355fSStephan Aßmus reply.error = B_HOST_TO_BENDIAN_INT32(error);
3525a1d355fSStephan Aßmus return channel->Send(&reply, sizeof(ConnectReply));
3535a1d355fSStephan Aßmus }
3545a1d355fSStephan Aßmus
355