1// PortConnection.cpp
2
3#include <stdio.h>
4
5#include "AutoDeleter.h"
6#include "PortConnection.h"
7
8namespace PortConnectionDefs {
9
10const int32 kProtocolVersion = 1;
11
12const char* kPortConnectionPortName = "NetFS port connection port";
13
14// number of client up/down stream channels
15const int32 kMinUpStreamChannels		= 1;
16const int32 kMaxUpStreamChannels		= 10;
17const int32 kDefaultUpStreamChannels	= 5;
18const int32 kMinDownStreamChannels		= 1;
19const int32 kMaxDownStreamChannels		= 5;
20const int32 kDefaultDownStreamChannels	= 1;
21
22} // namespace PortConnectionDefs
23
24using namespace PortConnectionDefs;
25
26// #pragma mark -
27// #pragma mark ----- PortConnection -----
28
29// constructor
30PortConnection::PortConnection()
31	: AbstractConnection(),
32	  fUpStreamChannels(0),
33	  fDownStreamChannels(0)
34{
35}
36
37// destructor
38PortConnection::~PortConnection()
39{
40}
41
42// Init (server side)
43status_t
44PortConnection::Init(Channel* channel, int32 upStreamChannels,
45	int32 downStreamChannels)
46{
47	ObjectDeleter<Channel> deleter(channel);
48	status_t error = AbstractConnection::Init();
49	if (error != B_OK)
50		return error;
51	// add the channel
52	error = AddDownStreamChannel(channel);
53	if (error != B_OK)
54		return error;
55	deleter.Detach();
56	fUpStreamChannels = upStreamChannels;
57	fDownStreamChannels = downStreamChannels;
58	return B_OK;
59}
60
61// Init (client side)
62status_t
63PortConnection::Init(const char* parameters)
64{
65	status_t error = AbstractConnection::Init();
66	if (error != B_OK)
67		return error;
68	// parse the parameters
69	// parameter format is "[ <up> [ <down> ] ]"
70	int upStreamChannels = kDefaultUpStreamChannels;
71	int downStreamChannels = kDefaultDownStreamChannels;
72	if (parameters)
73		sscanf(parameters, "%d %d", &upStreamChannels, &downStreamChannels);
74	// get the server port
75	port_id serverPort = find_port(kPortConnectionPortName);
76	if (serverPort < 0)
77		return serverPort;
78	// create a client channel
79	PortChannel* channel;
80	error = _CreateChannel(&channel);
81	if (error != B_OK)
82		return error;
83	// add it as up stream channel
84	error = AddUpStreamChannel(channel);
85	if (error != B_OK) {
86		delete channel;
87		return error;
88	}
89	// send the server a connect request
90	ConnectRequest request;
91	request.protocolVersion = kProtocolVersion;
92	request.upStreamChannels = upStreamChannels;
93	request.downStreamChannels = downStreamChannels;
94	channel->GetInfo(&request.channelInfo);
95	error = write_port(serverPort, 0, &request, sizeof(ConnectRequest));
96	if (error != B_OK)
97		return error;
98	// get the server reply
99	ConnectReply reply;
100	error = channel->Receive(&reply, sizeof(ConnectReply));
101	if (error != B_OK)
102		return error;
103	error = reply.error;
104	if (error != B_OK)
105		return error;
106	upStreamChannels = reply.upStreamChannels;
107	downStreamChannels = reply.downStreamChannels;
108	int32 allChannels = upStreamChannels + downStreamChannels;
109	// create the channels
110	PortChannel::Info* infos = new(std::nothrow)
111		PortChannel::Info[allChannels - 1];
112	if (!infos)
113		return B_NO_MEMORY;
114	ArrayDeleter<PortChannel::Info> _(infos);
115	for (int32 i = 1; i < allChannels; i++) {
116		// create a channel
117		PortChannel* otherChannel;
118		error = _CreateChannel(&otherChannel);
119		if (error != B_OK)
120			return error;
121		// add the channel
122		if (i < upStreamChannels)
123			error = AddUpStreamChannel(otherChannel);
124		else
125			error = AddDownStreamChannel(otherChannel);
126		if (error != B_OK) {
127			delete otherChannel;
128			return error;
129		}
130		// add the info
131		otherChannel->GetInfo(infos + i - 1);
132	}
133	// send the infos to the server
134	error = channel->Send(infos, sizeof(PortChannel::Info) * (allChannels - 1));
135	if (error != B_OK)
136		return error;
137	return B_OK;
138}
139
140// FinishInitialization
141status_t
142PortConnection::FinishInitialization()
143{
144	// get the down stream channel
145	Channel* channel = DownStreamChannelAt(0);
146	if (!channel)
147		return B_BAD_VALUE;
148	// send the connect reply
149	ConnectReply reply;
150	reply.error = B_OK;
151	reply.upStreamChannels = fUpStreamChannels;
152	reply.downStreamChannels = fDownStreamChannels;
153	status_t error = channel->Send(&reply, sizeof(ConnectReply));
154	if (error != B_OK)
155		return error;
156	// receive the channel infos
157	int32 allChannels = fUpStreamChannels + fDownStreamChannels;
158	PortChannel::Info* infos = new(std::nothrow)
159		PortChannel::Info[allChannels - 1];
160	if (!infos)
161		return B_NO_MEMORY;
162	ArrayDeleter<PortChannel::Info> _(infos);
163	error = channel->Receive(infos,
164		sizeof(PortChannel::Info) * (allChannels - 1));
165	if (error != B_OK)
166		return error;
167	// create the channels
168	for (int32 i = 1; i < allChannels; i++) {
169		// create a channel
170		PortChannel* otherChannel;
171		error = _CreateChannel(&otherChannel, infos + i - 1, true);
172		if (error != B_OK)
173			return error;
174		// add the channel
175		if (i < fUpStreamChannels)	// inverse, since we're on server side
176			error = AddDownStreamChannel(otherChannel);
177		else
178			error = AddUpStreamChannel(otherChannel);
179		if (error != B_OK) {
180			delete otherChannel;
181			return error;
182		}
183	}
184	return B_OK;
185}
186
187// _CreateChannel
188status_t
189PortConnection::_CreateChannel(PortChannel** _channel, PortChannel::Info* info,
190	bool inverse)
191{
192	PortChannel* channel = (info ? new(std::nothrow) PortChannel(info, inverse)
193								 : new(std::nothrow) PortChannel);
194	if (!channel)
195		return B_NO_MEMORY;
196	status_t error = channel->InitCheck();
197	if (error != B_OK) {
198		delete channel;
199		return error;
200	}
201	*_channel = channel;
202	return B_OK;
203}
204
205