1 /**************************************************************************/
2 /*                                                                        */
3 /* Copyright (c) 2001, 2010 NoMachine, http://www.nomachine.com/.         */
4 /*                                                                        */
5 /* NXCOMP, NX protocol compression and NX extensions to this software     */
6 /* are copyright of NoMachine. Redistribution and use of the present      */
7 /* software is allowed according to terms specified in the file LICENSE   */
8 /* which comes in the source distribution.                                */
9 /*                                                                        */
10 /* Check http://www.nomachine.com/licensing.html for applicability.       */
11 /*                                                                        */
12 /* NX and NoMachine are trademarks of Medialogic S.p.A.                   */
13 /*                                                                        */
14 /* All rights reserved.                                                   */
15 /*                                                                        */
16 /**************************************************************************/
17 
18 #ifndef ClientChannel_H
19 #define ClientChannel_H
20 
21 #include "List.h"
22 #include "Channel.h"
23 
24 #include "SequenceQueue.h"
25 
26 #include "ClientReadBuffer.h"
27 
28 //
29 // Set the verbosity level.
30 //
31 
32 #define PANIC
33 #define WARNING
34 #undef  TEST
35 #undef  DEBUG
36 
37 //
38 // If defined, the client channel will
39 // have the chance of suppressing more
40 // opcodes for test purposes.
41 //
42 
43 #undef  LAME
44 
45 //
46 // Define this to log a line when a
47 // channel is created or destroyed.
48 //
49 
50 #undef  REFERENCES
51 
52 //
53 // This class implements the X client
54 // side compression of the protocol.
55 //
56 
57 class ClientChannel : public Channel
58 {
59   public:
60 
61   ClientChannel(Transport *transport, StaticCompressor *compressor);
62 
63   virtual ~ClientChannel();
64 
65   virtual int handleRead(EncodeBuffer &encodeBuffer, const unsigned char *message,
66                              unsigned int length);
67 
68   virtual int handleWrite(const unsigned char *message, unsigned int length);
69 
70   virtual int handleSplit(EncodeBuffer &encodeBuffer, MessageStore *store,
71                               T_store_action action, int position, const unsigned char opcode,
72                                   const unsigned char *buffer, const unsigned int size);
73 
handleSplit(DecodeBuffer & decodeBuffer,MessageStore * store,T_store_action action,int position,unsigned char & opcode,unsigned char * & buffer,unsigned int & size)74   virtual int handleSplit(DecodeBuffer &decodeBuffer, MessageStore *store,
75                               T_store_action action, int position, unsigned char &opcode,
76                                   unsigned char *&buffer, unsigned int &size)
77   {
78     return 0;
79   }
80 
81   virtual int handleSplit(EncodeBuffer &encodeBuffer);
82 
handleSplit(DecodeBuffer & decodeBuffer)83   virtual int handleSplit(DecodeBuffer &decodeBuffer)
84   {
85     return 0;
86   }
87 
88   virtual int handleSplitEvent(EncodeBuffer &encodeBuffer, Split *split);
89 
90   virtual int handleSplitEvent(DecodeBuffer &decodeBuffer);
91 
handleMotion(EncodeBuffer & encodeBuffer)92   virtual int handleMotion(EncodeBuffer &encodeBuffer)
93   {
94     return 0;
95   }
96 
handleCompletion(EncodeBuffer & encodeBuffer)97   virtual int handleCompletion(EncodeBuffer &encodeBuffer)
98   {
99     return 0;
100   }
101 
102   virtual int handleConfiguration();
103 
104   virtual int handleFinish();
105 
handleAsyncEvents()106   virtual int handleAsyncEvents()
107   {
108     return 0;
109   }
110 
needSplit()111   virtual int needSplit() const
112   {
113     #if defined(TEST) || defined(SPLIT)
114     *logofs << "needSplit: SPLIT! Returning pending split "
115             << "flag " << splitState_.pending << " with "
116             << clientStore_ -> getSplitTotalSize()
117             << " splits in the split stores.\n"
118             << logofs_flush;
119     #endif
120 
121     return splitState_.pending;
122   }
123 
needMotion()124   virtual int needMotion() const
125   {
126     return 0;
127   }
128 
getType()129   virtual T_channel_type getType() const
130   {
131     return channel_x11;
132   }
133 
134   int setBigEndian(int flag);
135 
136   //
137   // Initialize the static members.
138   //
139 
140   static int setReferences();
141 
142   private:
143 
144   int handleFastReadRequest(EncodeBuffer &encodeBuffer, const unsigned char &opcode,
145                                 const unsigned char *&buffer, const unsigned int &size);
146 
147   int handleFastWriteReply(DecodeBuffer &decodeBuffer, unsigned char &opcode,
148                                unsigned char *&buffer, unsigned int &size);
149 
150   int handleFastWriteEvent(DecodeBuffer &decodeBuffer, unsigned char &opcode,
151                                unsigned char *&buffer, unsigned int &size);
152 
153   //
154   // Intercept the request before the opcode
155   // is encoded.
156   //
157 
handleTaintRequest(unsigned char & opcode,const unsigned char * & buffer,unsigned int & size)158   int handleTaintRequest(unsigned char &opcode, const unsigned char *&buffer,
159                              unsigned int &size)
160   {
161     if (control -> isProtoStep7() == 0)
162     {
163       if (opcode == X_NXFreeSplit || opcode == X_NXAbortSplit ||
164               opcode == X_NXFinishSplit)
165       {
166         return handleTaintSplitRequest(opcode, buffer, size);
167       }
168       else if (opcode == X_NXSetCacheParameters)
169       {
170         return handleTaintCacheRequest(opcode, buffer, size);
171       }
172       else if (opcode == X_NXGetFontParameters)
173       {
174         return handleTaintFontRequest(opcode, buffer, size);
175       }
176     }
177 
178     if (control -> TaintReplies > 0 &&
179             opcode == X_GetInputFocus)
180     {
181       return handleTaintSyncRequest(opcode, buffer, size);
182     }
183 
184     #ifdef LAME
185 
186     return handleTaintLameRequest(opcode, buffer, size);
187 
188     #endif
189 
190     return 0;
191   }
192 
193   int handleTaintCacheRequest(unsigned char &opcode, const unsigned char *&buffer,
194                                   unsigned int &size);
195 
196   int handleTaintFontRequest(unsigned char &opcode, const unsigned char *&buffer,
197                                  unsigned int &size);
198 
199   int handleTaintSplitRequest(unsigned char &opcode, const unsigned char *&buffer,
200                                   unsigned int &size);
201 
202   int handleTaintLameRequest(unsigned char &opcode, const unsigned char *&buffer,
203                                  unsigned int &size);
204 
205   int handleTaintSyncRequest(unsigned char &opcode, const unsigned char *&buffer,
206                                  unsigned int &size);
207 
208   int handleTaintSyncError(unsigned char opcode);
209 
210   //
211   // How to handle sequence counter
212   // in notification event.
213   //
214 
215   enum T_sequence_mode
216   {
217     sequence_immediate,
218     sequence_deferred
219   };
220 
221   //
222   // Send split notifications to the
223   // agent.
224   //
225 
226   int handleRestart(T_sequence_mode mode, int resource);
227 
228   int handleNotify(T_notification_type type, T_sequence_mode mode,
229                        int resource, int request, int position);
230 
231   //
232   // Other utility functions used in
233   // handling of the image streaming.
234   //
235 
mustSplitMessage(int resource)236   int mustSplitMessage(int resource)
237   {
238     return (clientStore_ -> getSplitStore(resource) ->
239                 getSize() != 0);
240   }
241 
canSplitMessage(T_split_mode mode,unsigned int size)242   int canSplitMessage(T_split_mode mode, unsigned int size)
243   {
244     return ((int) size >= control -> SplitDataThreshold &&
245                 (clientStore_ -> getSplitTotalStorageSize() < control ->
246                      SplitTotalStorageSize && clientStore_ ->
247                          getSplitTotalSize() < control -> SplitTotalSize));
248   }
249 
canSendSplit(Split * split)250   int canSendSplit(Split *split)
251   {
252     return (split -> getMode() != split_sync ||
253                 split -> getState() == split_missed ||
254                     split -> getState() == split_loaded);
255   }
256 
257   int handleSplitSend(EncodeBuffer &encodeBuffer, int resource,
258                           int &total, int &bytes);
259 
260   Split *handleSplitFind(T_checksum checksum, int resource);
261 
262   int handleSplitChecksum(EncodeBuffer &encodeBuffer, T_checksum checksum);
263 
handleSplitEnable()264   void handleSplitEnable()
265   {
266     if (control -> isProtoStep7() == 0)
267     {
268       #if defined(TEST) || defined(SPLIT)
269       *logofs << "handleSplitEnable: WARNING! Disabling split "
270               << "with an old proxy version.\n"
271               << logofs_flush;
272       #endif
273 
274       enableSplit_ = 0;
275     }
276   }
277 
handleSplitPending(int resource)278   void handleSplitPending(int resource)
279   {
280     if (splitState_.pending == 0)
281     {
282       if (clientStore_ -> getSplitStore(resource) != NULL &&
283               clientStore_ -> getSplitStore(resource) ->
284                   getFirstSplit() != NULL)
285       {
286         splitState_.pending = canSendSplit(clientStore_ ->
287             getSplitStore(resource) -> getFirstSplit());
288 
289         #if defined(TEST) || defined(SPLIT)
290         *logofs << "handleSplitPending: SPLIT! Set the pending "
291                 << "split flag to " << splitState_.pending
292                 << " with " << clientStore_ -> getSplitTotalSize()
293                 << " splits in the split stores.\n"
294                 << logofs_flush;
295         #endif
296       }
297     }
298   }
299 
300   //
301   // Scan all the split stores to find
302   // if there is any split to send.
303   //
304 
305   void handleSplitPending();
306 
307   //
308   // Handle the MIT-SHM initialization
309   // messages exchanged with the remote
310   // proxy.
311   //
312 
313   int handleShmemRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode,
314                              const unsigned char *buffer, const unsigned int size);
315 
316   int handleShmemReply(DecodeBuffer &decodeBuffer, unsigned char &opcode,
317                            unsigned char *&buffer, unsigned int &size);
318 
319   //
320   // Query the port used to tunnel
321   // the font server connections.
322   //
323 
324   int handleFontRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode,
325                             const unsigned char *buffer, const unsigned int size);
326 
327   int handleFontReply(DecodeBuffer &decodeBuffer, unsigned char &opcode,
328                           unsigned char *&buffer, unsigned int &size);
329 
330   //
331   // Let the agent set the cache
332   // policy for image requests.
333   //
334 
335   int handleCacheRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode,
336                              const unsigned char *buffer, const unsigned int size);
337 
338   //
339   // Encode the start and end split
340   // requests.
341   //
342 
343   int handleStartSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode,
344                                   const unsigned char *buffer, const unsigned int size);
345 
346   int handleEndSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode,
347                                 const unsigned char *buffer, const unsigned int size);
348 
349   //
350   // Empty a split store and send the
351   // restart event.
352   //
353 
354   int handleAbortSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode,
355                                   const unsigned char *buffer, const unsigned int size);
356 
357   //
358   // Force the proxy to finalize all
359   // the pending split operations and
360   // restart a resource.
361   //
362 
363   int handleFinishSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode,
364                                    const unsigned char *buffer, const unsigned int size);
365 
366   //
367   // Tell the remote peer to send the
368   // split requests to the X server.
369   //
370 
371   int handleCommitSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode,
372                                    const unsigned char *buffer, const unsigned int size);
373 
374   //
375   // Other utilities.
376   //
377 
378   void handleDecodeCharInfo(DecodeBuffer &, unsigned char *);
379 
380   //
381   // Own read buffer. It is able to identify
382   // full messages read from the X descriptor.
383   //
384 
385   ClientReadBuffer readBuffer_;
386 
387   //
388   // Sequence number of last request coming
389   // from the X client or the X server.
390   //
391 
392   unsigned int clientSequence_;
393   unsigned int serverSequence_;
394 
395   //
396   // Last sequence number known by client. It can
397   // be the real sequence generated by server or
398   // the one of the last auto-generated event.
399   //
400 
401   unsigned int lastSequence_;
402 
403   //
404   // Used to identify replies based on sequence
405   // number of original request.
406   //
407 
408   SequenceQueue sequenceQueue_;
409 
410   //
411   // This is used to test the synchronous flush
412   // in the proxy.
413   //
414 
415   int lastRequest_;
416 
417   //
418   // Current resource id selected as target and
419   // other information related to the image split.
420   // The pending and abort flags are set when we
421   // want the proxy to give us a chance to send
422   // more split data. We also save the position
423   // of the last commit operation performed by
424   // channel so we can differentially encode the
425   // position of next message to commit.
426   //
427 
428   typedef struct
429   {
430     int resource;
431     int pending;
432     int commit;
433     T_split_mode mode;
434 
435   } T_split_state;
436 
437   T_split_state splitState_;
438 
439   //
440   // List of agent resources.
441   //
442 
443   List splitResources_;
444 
445   //
446   // How many sync requests we
447   // have tainted so far.
448   //
449 
450   int taintCounter_;
451 
452   private:
453 
454   //
455   // Keep track of object
456   // creation and deletion.
457   //
458 
459   #ifdef REFERENCES
460 
461   static int references_;
462 
463   #endif
464 };
465 
466 #endif /* ClientChannel_H */
467