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
PortConnection()30 PortConnection::PortConnection()
31 : AbstractConnection(),
32 fUpStreamChannels(0),
33 fDownStreamChannels(0)
34 {
35 }
36
37 // destructor
~PortConnection()38 PortConnection::~PortConnection()
39 {
40 }
41
42 // Init (server side)
43 status_t
Init(Channel * channel,int32 upStreamChannels,int32 downStreamChannels)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
Init(const char * parameters)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
FinishInitialization()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
_CreateChannel(PortChannel ** _channel,PortChannel::Info * info,bool inverse)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