1 #include "dxpcconf.h"
2 #include <fcntl.h>
3 #include <sys/time.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <unistd.h>
7 #include "Multiplexer.H"
8 #include "Channel.H"
9 #include "util.H"
10
11 extern int silent;
12
Multiplexer(int proxyFD)13 Multiplexer::Multiplexer(int proxyFD):
14 proxyFD_(proxyFD),
15 proxyReadBuffer_(proxyFD),
16 proxyInputChannel_(-1),
17 proxyOutputChannel_(-1)
18 {
19 for (unsigned int i = 0; i < MAX_CONNECTIONS; i++)
20 channels_[i] = 0;
21 }
22
23
~Multiplexer()24 Multiplexer::~Multiplexer()
25 {
26 for (unsigned int i = 0; i < MAX_CONNECTIONS; i++)
27 delete channels_[i];
28 }
29
30
31 // Add the file descriptors for this multiplexer's X connections
32 // to the supplied select set
setSelectFDs(fd_set * fdSet,unsigned int & max)33 void Multiplexer::setSelectFDs(fd_set * fdSet, unsigned int &max)
34 {
35 int numFDsToSelect = max;
36
37 for (unsigned int i = 0; i < MAX_CONNECTIONS; i++)
38 if (channels_[i] != 0)
39 {
40 int nextFD = channelIDToFD(i);
41
42 // CERR << "Multiplexer::setSelectFDs setting " << nextFD << ENDL;
43 FD_SET(nextFD, fdSet);
44 if (nextFD >= numFDsToSelect)
45 numFDsToSelect = nextFD + 1;
46 }
47 max = numFDsToSelect;
48 }
49
50
handleSelect(int fd)51 int Multiplexer::handleSelect(int fd)
52 {
53 unsigned char controlMessages[9];
54 unsigned int controlMessagesLength = 0;
55
56 encodeBuffer_.reset();
57
58 if (fd == proxyFD_)
59 {
60 // Data arrived from peer proxy
61
62 if (!proxyReadBuffer_.doRead())
63 {
64 if (!silent)
65 {
66 CERR << "lost connection to peer proxy" << ENDL;
67 }
68 return 0;
69 }
70 const unsigned char *message;
71 unsigned int messageLength;
72
73 while ((message = proxyReadBuffer_.getMessage(messageLength)) != 0)
74 {
75 if ((messageLength == 3) && (message[0] == 0))
76 {
77 if (message[1] == (unsigned char) CTRL_NEW_CONNECTION)
78 {
79 int channelNum = (int) message[2];
80
81 if (!createNewConnectionFromProxy(channelNum))
82 {
83 controlMessages[controlMessagesLength++] = 0;
84 controlMessages[controlMessagesLength++] =
85 (unsigned char) CTRL_DROP_CONNECTION;
86 controlMessages[controlMessagesLength++] =
87 (unsigned char) channelNum;
88 }
89 }
90 else if (message[1] == (unsigned char) CTRL_DROP_CONNECTION)
91 {
92 int channelNum = (int) message[2];
93
94 if (((unsigned int) channelNum < MAX_CONNECTIONS) &&
95 (channels_[channelNum] != 0))
96 {
97 SOCKCLOSE(channelIDToFD(channelNum));
98 delete channels_[channelNum];
99
100 channels_[channelNum] = 0;
101 cleanupChannelFDMapping(channelNum);
102 }
103 }
104 else if (message[1] == (unsigned char) CTRL_SWITCH_CONNECTION)
105 {
106 proxyInputChannel_ = (int) message[2];
107 }
108 else
109 {
110 CERR << "invalid message from peer proxy!" << ENDL;
111 return 0;
112 }
113 }
114 else
115 {
116 int channelNum = proxyInputChannel_;
117
118 if ((channelNum >= 0) &&
119 ((unsigned int) channelNum < MAX_CONNECTIONS) &&
120 (channels_[channelNum] != 0))
121 {
122 if (!channels_[channelNum]->
123 doWrite(message, messageLength))
124 {
125 SOCKCLOSE(channelIDToFD(channelNum));
126 delete channels_[channelNum];
127
128 channels_[channelNum] = 0;
129 cleanupChannelFDMapping(channelNum);
130 controlMessages[controlMessagesLength++] = 0;
131 controlMessages[controlMessagesLength++] =
132 (unsigned char) CTRL_DROP_CONNECTION;
133 controlMessages[controlMessagesLength++] =
134 (unsigned char) channelNum;
135 }
136 }
137 }
138 }
139 }
140 else
141 {
142 // Data arrived from some X connection
143
144 int channelNum = fdToChannelID(fd);
145
146 if ((channelNum < 0) || (channels_[channelNum] == 0))
147 {
148 SOCKCLOSE(fd);
149 return 1;
150 }
151
152 // CERR << "data received on X channel " << channelNum << ENDL;
153
154 // Let the channel object read all the new data from its
155 // file descriptor, isolate messages, compress those messages,
156 // and append the compressed form to the encodeBuffer_
157 if (!channels_[channelNum]->doRead(encodeBuffer_))
158 {
159 SOCKCLOSE(fd);
160 delete channels_[channelNum];
161
162 channels_[channelNum] = 0;
163 cleanupChannelFDMapping(channelNum);
164
165 // Send channel shutdown message to the peer proxy
166 controlMessages[controlMessagesLength++] = 0;
167 controlMessages[controlMessagesLength++] =
168 (unsigned char) CTRL_DROP_CONNECTION;
169 controlMessages[controlMessagesLength++] =
170 (unsigned char) channelNum;
171 }
172 // Generate a control message to the peer proxy to tell it that
173 // we're now sending data for a different channel
174 else if (channelNum != proxyOutputChannel_)
175 {
176 proxyOutputChannel_ = channelNum;
177 controlMessages[controlMessagesLength++] = 0;
178 controlMessages[controlMessagesLength++] =
179 (unsigned char) CTRL_SWITCH_CONNECTION;
180 controlMessages[controlMessagesLength++] =
181 (unsigned char) channelNum;
182 }
183 }
184
185
186 // write any outstanding control messages, followed by any outstanding
187 // compressed X messages, to proxyFD...
188 // This code assumes that "encodeBuffer_.getData()" actually references
189 // a location offset several bytes from the start of the buffer, so that
190 // the length header and any necessary control messages can be inserted
191 // in front of the data already in the buffer. (See EncodeBuffer.C.)
192 // This is an ugly hack, but it's the easiest way to encapsulate the
193 // header and message data together in a single write(2) call.
194 // (Experimentation has shown that doing separate writes for the
195 // header and the data causes the responsiveness of applications
196 // run over dxpc to deteriorate enormously.)
197 unsigned int dataLength = encodeBuffer_.getDataLength();
198
199 if (dataLength + controlMessagesLength != 0)
200 {
201 unsigned char temp[5];
202 unsigned int lengthLength = 0;
203 unsigned int length = dataLength;
204
205 while (length)
206 {
207 temp[lengthLength++] = (unsigned char) (length & 0x7f);
208 length >>= 7;
209 }
210
211 unsigned char *data = encodeBuffer_.getData();
212 unsigned char *outputMessage = data -
213 (controlMessagesLength + lengthLength);
214 unsigned int outputLength = dataLength + controlMessagesLength +
215 lengthLength;
216 unsigned char *nextDest = outputMessage;
217
218 for (unsigned int i = 0; i < controlMessagesLength; i++)
219 *nextDest++ = controlMessages[i];
220 for (int j = lengthLength - 1; j > 0; j--)
221 *nextDest++ = (temp[j] | 0x80);
222 if (lengthLength)
223 *nextDest++ = temp[0];
224
225 if ((dataLength != 0) &&
226 (proxyOutputChannel_ >= 0) &&
227 ((unsigned int) proxyOutputChannel_ < MAX_CONNECTIONS) &&
228 (channels_[proxyOutputChannel_] != NULL))
229 channels_[proxyOutputChannel_]->recordFramingBits((controlMessagesLength + lengthLength) << 3);
230
231 if (WriteAll(proxyFD_, outputMessage, outputLength) <= 0)
232 return 0;
233 }
234 return 1;
235 }
236