#include <stdio.h>
#include "AutoDeleter.h"
#include "PortConnection.h"
namespace PortConnectionDefs {
const int32 kProtocolVersion = 1;
const char* kPortConnectionPortName = "NetFS port connection port";
const int32 kMinUpStreamChannels = 1;
const int32 kMaxUpStreamChannels = 10;
const int32 kDefaultUpStreamChannels = 5;
const int32 kMinDownStreamChannels = 1;
const int32 kMaxDownStreamChannels = 5;
const int32 kDefaultDownStreamChannels = 1;
}
using namespace PortConnectionDefs;
PortConnection::PortConnection()
: AbstractConnection(),
fUpStreamChannels(0),
fDownStreamChannels(0)
{
}
PortConnection::~PortConnection()
{
}
status_t
PortConnection::Init(Channel* channel, int32 upStreamChannels,
int32 downStreamChannels)
{
ObjectDeleter<Channel> deleter(channel);
status_t error = AbstractConnection::Init();
if (error != B_OK)
return error;
error = AddDownStreamChannel(channel);
if (error != B_OK)
return error;
deleter.Detach();
fUpStreamChannels = upStreamChannels;
fDownStreamChannels = downStreamChannels;
return B_OK;
}
status_t
PortConnection::Init(const char* parameters)
{
status_t error = AbstractConnection::Init();
if (error != B_OK)
return error;
int upStreamChannels = kDefaultUpStreamChannels;
int downStreamChannels = kDefaultDownStreamChannels;
if (parameters)
sscanf(parameters, "%d %d", &upStreamChannels, &downStreamChannels);
port_id serverPort = find_port(kPortConnectionPortName);
if (serverPort < 0)
return serverPort;
PortChannel* channel;
error = _CreateChannel(&channel);
if (error != B_OK)
return error;
error = AddUpStreamChannel(channel);
if (error != B_OK) {
delete channel;
return error;
}
ConnectRequest request;
request.protocolVersion = kProtocolVersion;
request.upStreamChannels = upStreamChannels;
request.downStreamChannels = downStreamChannels;
channel->GetInfo(&request.channelInfo);
error = write_port(serverPort, 0, &request, sizeof(ConnectRequest));
if (error != B_OK)
return error;
ConnectReply reply;
error = channel->Receive(&reply, sizeof(ConnectReply));
if (error != B_OK)
return error;
error = reply.error;
if (error != B_OK)
return error;
upStreamChannels = reply.upStreamChannels;
downStreamChannels = reply.downStreamChannels;
int32 allChannels = upStreamChannels + downStreamChannels;
PortChannel::Info* infos = new(std::nothrow)
PortChannel::Info[allChannels - 1];
if (!infos)
return B_NO_MEMORY;
ArrayDeleter<PortChannel::Info> _(infos);
for (int32 i = 1; i < allChannels; i++) {
PortChannel* otherChannel;
error = _CreateChannel(&otherChannel);
if (error != B_OK)
return error;
if (i < upStreamChannels)
error = AddUpStreamChannel(otherChannel);
else
error = AddDownStreamChannel(otherChannel);
if (error != B_OK) {
delete otherChannel;
return error;
}
otherChannel->GetInfo(infos + i - 1);
}
error = channel->Send(infos, sizeof(PortChannel::Info) * (allChannels - 1));
if (error != B_OK)
return error;
return B_OK;
}
status_t
PortConnection::FinishInitialization()
{
Channel* channel = DownStreamChannelAt(0);
if (!channel)
return B_BAD_VALUE;
ConnectReply reply;
reply.error = B_OK;
reply.upStreamChannels = fUpStreamChannels;
reply.downStreamChannels = fDownStreamChannels;
status_t error = channel->Send(&reply, sizeof(ConnectReply));
if (error != B_OK)
return error;
int32 allChannels = fUpStreamChannels + fDownStreamChannels;
PortChannel::Info* infos = new(std::nothrow)
PortChannel::Info[allChannels - 1];
if (!infos)
return B_NO_MEMORY;
ArrayDeleter<PortChannel::Info> _(infos);
error = channel->Receive(infos,
sizeof(PortChannel::Info) * (allChannels - 1));
if (error != B_OK)
return error;
for (int32 i = 1; i < allChannels; i++) {
PortChannel* otherChannel;
error = _CreateChannel(&otherChannel, infos + i - 1, true);
if (error != B_OK)
return error;
if (i < fUpStreamChannels)
error = AddDownStreamChannel(otherChannel);
else
error = AddUpStreamChannel(otherChannel);
if (error != B_OK) {
delete otherChannel;
return error;
}
}
return B_OK;
}
status_t
PortConnection::_CreateChannel(PortChannel** _channel, PortChannel::Info* info,
bool inverse)
{
PortChannel* channel = (info ? new(std::nothrow) PortChannel(info, inverse)
: new(std::nothrow) PortChannel);
if (!channel)
return B_NO_MEMORY;
status_t error = channel->InitCheck();
if (error != B_OK) {
delete channel;
return error;
}
*_channel = channel;
return B_OK;
}