xref: /haiku/src/add-ons/kernel/file_systems/netfs/shared/PortConnection.cpp (revision 220d04022750f40f8bac8f01fa551211e28d04f2)
1 // PortConnection.cpp
2 
3 #include <stdio.h>
4 
5 #include "AutoDeleter.h"
6 #include "PortConnection.h"
7 
8 namespace PortConnectionDefs {
9 
10 const int32 kProtocolVersion = 1;
11 
12 const char* kPortConnectionPortName = "NetFS port connection port";
13 
14 // number of client up/down stream channels
15 const int32 kMinUpStreamChannels		= 1;
16 const int32 kMaxUpStreamChannels		= 10;
17 const int32 kDefaultUpStreamChannels	= 5;
18 const int32 kMinDownStreamChannels		= 1;
19 const int32 kMaxDownStreamChannels		= 5;
20 const int32 kDefaultDownStreamChannels	= 1;
21 
22 } // namespace PortConnectionDefs
23 
24 using namespace PortConnectionDefs;
25 
26 // #pragma mark -
27 // #pragma mark ----- PortConnection -----
28 
29 // constructor
30 PortConnection::PortConnection()
31 	: AbstractConnection(),
32 	  fUpStreamChannels(0),
33 	  fDownStreamChannels(0)
34 {
35 }
36 
37 // destructor
38 PortConnection::~PortConnection()
39 {
40 }
41 
42 // Init (server side)
43 status_t
44 PortConnection::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)
62 status_t
63 PortConnection::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
141 status_t
142 PortConnection::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
188 status_t
189 PortConnection::_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