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